Files

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

  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.