Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
122 lines
5.7 KiB
Markdown
122 lines
5.7 KiB
Markdown
# Agent 1 — final report (org platform)
|
|
|
|
Branch: `dev`. Phases 1, 2 (previously merged) plus 3, 4 and 5 (implemented now,
|
|
reconstructed from the sibling `agent1/org-platform` branch and reconciled onto
|
|
`dev`'s shapes).
|
|
|
|
## Summary
|
|
|
|
The org-platform workstream is complete on `dev`: a platform owner invites a
|
|
manager, the manager builds one organization with one application through a
|
|
five-step wizard, the owner decides which models that organization may use, the
|
|
organization builds a memory of its own rules / preferences / lessons / code map,
|
|
and an external AI agent can act inside it through a scoped MCP token the
|
|
organization's own admin minted. Everything is tenant-scoped, audited,
|
|
Persian/RTL on the UI side, and no secret reaches a response, a draft, an audit
|
|
row, a log or an LLM prompt.
|
|
|
|
```
|
|
apps/api: pytest -q → 587 passed, 1 skipped
|
|
apps/api: ruff check . → All checks passed!
|
|
apps/api: mypy app → Success: no issues found in 147 source files
|
|
apps/api: alembic upgrade head / downgrade -1 / upgrade head / check → clean, single head
|
|
apps/web: tsc --noEmit → clean · next lint → No ESLint warnings or errors
|
|
apps/web: vitest run → 99 passed (13 files)
|
|
```
|
|
|
|
Migrations added on `dev` (the branch's single `a1b2c3d4e5f1` was split into one
|
|
owned migration per phase, chained off `dev`'s own head):
|
|
|
|
| revision | phase | tables |
|
|
|---|---|---|
|
|
| `e6f7a8b9c0d1` | 3 | `default_model_grants`, `org_policies` |
|
|
| `f7a8b9c0d1e2` | 4 | `org_memories` |
|
|
| `a8b9c0d1e2f3` | 5 | `mcp_tokens` |
|
|
|
|
(Phases 1 and 2 were already on `dev`: `a1b2c3d4e5f1` platform invites,
|
|
`d5e6f7a8b9c0` org setup drafts.)
|
|
|
|
## Endpoints added (all under `/api`, roles as enforced by the router)
|
|
|
|
### Phase 1 — invites, roles, sharing
|
|
`POST/GET /admin/platform-invites`, `POST /admin/platform-invites/{id}/revoke`,
|
|
`GET /invites/{token}`, `POST /invites/accept`, `GET /auth/me`
|
|
(`needs_onboarding`), `POST /organizations/{id}/transfer-ownership`,
|
|
`POST /organizations/{id}/leave`, `GET/DELETE /organizations/{id}/invites[/{id}]`,
|
|
and the `/admin/users` lifecycle.
|
|
|
|
### Phase 2 — wizard and app profile
|
|
`GET /setup/catalog`, `GET/PUT /setup/draft`, `POST /setup/check-git`,
|
|
`POST /setup/check-deploy`, `POST /setup/complete`,
|
|
`GET/PATCH /organizations/{org}/app/profile`,
|
|
`PUT /organizations/{org}/app/deploy-target`,
|
|
`PUT /organizations/{org}/app/git`.
|
|
|
|
### Phase 3 — owner grants and policy
|
|
`GET /admin/model-grants/{org}`, `PUT/DELETE /admin/model-grants/{org}/models/{model}`,
|
|
`GET /admin/model-grants/{org}/active`,
|
|
`GET/PUT/DELETE /admin/default-model-grants[/{model}]`,
|
|
`GET/PUT /admin/org-policies/{org}`.
|
|
|
|
### Phase 4 — memory
|
|
`GET /organizations/{org}/memory`, `POST /organizations/{org}/memory`,
|
|
`PATCH /organizations/{org}/memory/{id}`,
|
|
`POST /organizations/{org}/memory/{id}/pin`, `.../confirm`,
|
|
`DELETE /organizations/{org}/memory/{id}`.
|
|
|
|
### Phase 5 — MCP
|
|
`GET /organizations/{org}/mcp-tokens`, `POST .../mcp-tokens`,
|
|
`DELETE .../mcp-tokens/{id}`, `GET .../mcp-tokens/settings`,
|
|
`GET/PUT /admin/mcp`, `PUT /admin/mcp/organizations/{id}`, and the MCP server at
|
|
`/mcp` (`python -m app.interfaces.mcp.server`, `pnpm mcp:dev`).
|
|
|
|
MCP tools: `app_get_profile`, `tasks_list`, `tasks_get`, `tasks_create`,
|
|
`memory_search`, `memory_write`, `knowledge_search`, `pipeline_status`
|
|
(`{"available": false}` until Agent 3's tables are wired).
|
|
|
|
## Tables added (all in `db/models_org.py`)
|
|
|
|
`platform_invites` (1) · `org_setup_drafts` (2) · `default_model_grants` (3) ·
|
|
`org_policies` (3) · `org_memories` (4) · `mcp_tokens` (5). `org_model_grants`,
|
|
which the grants engine reads, is foundation-owned.
|
|
|
|
## Manual QA — the wizard
|
|
|
|
1. As the owner, `/admin/users` → «دعوت مدیر جدید» → copy the link.
|
|
2. Open it in a private window → «ساخت حساب مدیر» → set a password → land on
|
|
`/onboarding`.
|
|
3. Step through the five steps; leave at step 2 and reload to confirm the draft
|
|
resumes. Choose «Git پلتفرم (پیشنهادی)», skip production, create.
|
|
4. The success screen shows the demo URL; «برو به مدیر AI» → `/manager`. The DB
|
|
has exactly one project with a full profile, and the Null hooks recorded one
|
|
`bootstrap_team` and one `on_app_created`.
|
|
5. `/admin/model-grants`: grant a model to the new org, set its daily cap, revoke.
|
|
6. `/memory`: teach a rule, pin it, confirm a lesson, keep the page open while
|
|
another tab changes memory — the list refreshes on `memory.changed`.
|
|
7. `/settings` → «یکپارچهسازی (MCP)»: mint a token, copy it once, revoke it.
|
|
`/admin/mcp`: flip the global and per-org switches.
|
|
|
|
## CHANGE REQUESTs still open
|
|
|
|
1. **`ModelGrantPort` should expose `get_org_policy(organization_id)`** (and
|
|
`.mcp_enabled`) so Agent 2 reads the policy through the port it already holds.
|
|
2. **`expire_memories()`** needs a worker hook (billing worker or a new tick in
|
|
`workers/__main__.py`).
|
|
3. **`pipeline_status`** should be pointed at Agent 3's delivery/deploy tables.
|
|
4. **`@agy/contracts`** lacks `memory.changed` and the MCP event types; the web
|
|
compares raw strings.
|
|
5. **Post-login redirect**: an existing manager with `needs_onboarding` still
|
|
lands on `/dashboard` (`login/page.tsx` and `AppShell.tsx` are locked);
|
|
`useNeedsOnboarding()` is ready to use.
|
|
6. **`build_memory_service` / `build_model_grant_service`** live in `container_org`
|
|
only; re-export from `container.py` for one import surface.
|
|
|
|
## Known limitations
|
|
|
|
- A reflection is not grant-checked (uses `pick_for_mode(CHEAP)` like the engine).
|
|
- `expire_memories()` has no caller yet.
|
|
- `pipeline_status` is a stub until Agent 3's tables are wired.
|
|
- The MCP rate limiter is process-local.
|
|
- `mcp_gateway_enabled` is a process-local setting mutation; a restart re-reads
|
|
it from the environment.
|