Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
5.7 KiB
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
- As the owner,
/admin/users→ «دعوت مدیر جدید» → copy the link. - Open it in a private window → «ساخت حساب مدیر» → set a password → land on
/onboarding. - Step through the five steps; leave at step 2 and reload to confirm the draft resumes. Choose «Git پلتفرم (پیشنهادی)», skip production, create.
- The success screen shows the demo URL; «برو به مدیر AI» →
/manager. The DB has exactly one project with a full profile, and the Null hooks recorded onebootstrap_teamand oneon_app_created. /admin/model-grants: grant a model to the new org, set its daily cap, revoke./memory: teach a rule, pin it, confirm a lesson, keep the page open while another tab changes memory — the list refreshes onmemory.changed./settings→ «یکپارچهسازی (MCP)»: mint a token, copy it once, revoke it./admin/mcp: flip the global and per-org switches.
CHANGE REQUESTs still open
ModelGrantPortshould exposeget_org_policy(organization_id)(and.mcp_enabled) so Agent 2 reads the policy through the port it already holds.expire_memories()needs a worker hook (billing worker or a new tick inworkers/__main__.py).pipeline_statusshould be pointed at Agent 3's delivery/deploy tables.@agy/contractslacksmemory.changedand the MCP event types; the web compares raw strings.- Post-login redirect: an existing manager with
needs_onboardingstill lands on/dashboard(login/page.tsxandAppShell.tsxare locked);useNeedsOnboarding()is ready to use. build_memory_service/build_model_grant_servicelive incontainer_orgonly; re-export fromcontainer.pyfor 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_statusis a stub until Agent 3's tables are wired.- The MCP rate limiter is process-local.
mcp_gateway_enabledis a process-local setting mutation; a restart re-reads it from the environment.