Commit Graph

7 Commits

Author SHA1 Message Date
soroush.asadi bcdbc7e941 Versioned PRODUCT.md library + marketplace — backend (Slice 4)
Mirrors the agent-profile stack for products: ProductProfile entity (org-scoped,
versioned by org+key+version; null org = free builtin), a PRODUCT.md parser + writer,
and endpoints — upload, list, marketplace, get, publish/unpublish, fork, install, and
apply-to-product (sets Product.Identity to the profile's PRODUCT.md). Reuses the shared
ProfileOrigin/Status/Visibility enums; product profiles are gated owner-level
(CreateProductsAndTeams). Adds the product_profiles table.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 20:40:57 +03:30
soroush.asadi 56d41a231f Product identity: a shared PRODUCT.md injected into every agent run on the product
Adds Product.Identity (a PRODUCT.md brief) and threads it through the run context:
AgentRunContextProvider resolves the run's team -> product and carries ProductId +
ProductIdentity on AgentRunContext; PromptAssembler injects a "# Product" section
(framed as shared, data-not-instructions) ahead of the agent's persona. Adds
GET/PUT /products/{id}/identity (read = view-board, set = owner) and the EF column.

This makes the product, not just the team, the unit of shared context — every agent
on a product sees the same identity. Product-scoped working memory follows next.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 18:09:42 +03:30
soroush.asadi 0bcf16e77f Agent profiles (AGENTS.md): per-org library, free builtins, versioning, marketplace, persona
Reusable agent definitions authored as AGENTS.md (YAML frontmatter + a Markdown body that becomes
the agent's operating guide). Mirrors the skill library, including its review hardening.

- AgentProfile entity (OrgBoard): org-scoped + versioned by (OrganizationId, ProfileKey, Version),
  NULLS NOT DISTINCT unique index; Origin Builtin|Authored|Installed; ProfileVisibility +
  ProfileStatus with the Public⟹Published invariant enforced in Apply()/SetVisibility(). AGENTS.md
  parser (YamlDotNet). AgentProfileWriter is the single upsert path (insert-only mode for install).
- Free builtins: AgentProfileSeeder seeds Aria (PO), Quill (QA), Edison (backend) on startup via a
  new IStartupSeeder + SeederRunner (runs after migrations). Idempotent, null-org, visible to all.
- Endpoints (/api/orgboard/agent-profiles): upload, list (resolvable-winner order), get versions,
  publish/unpublish, fork, marketplace (per-(key,version) AlreadyInLibrary), install (insert-only →
  clean 409, no clobber). ConfigureAgents to author/manage; ViewBoard to browse; audited.
- Persona: Agent gains Persona; ConfigureAgent stores it; AgentRunContext carries it; PromptAssembler
  injects it as "# Operating guide" (data, not instructions) so an applied profile shapes the run.
- Client: Agent profiles page (library + marketplace tabs, upload editor, publish/unlist/fork/install),
  routed + in the nav.

Verified: ArchitectureTests 8/8, IntegrationTests 55/55 (new AgentProfilesTests: builtins seeded,
upload + validation, publish, cross-org marketplace list→install→private copy, duplicate 409, per-
version flag, Member 403; persona renders as the operating guide), client build green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 09:18:37 +03:30
soroush.asadi c5e0e5cfe3 MCP compatibility for AI agents: server registry, JSON-RPC client, gateway, run-time tool catalog
Agents can now use Model Context Protocol servers. End to end:
- SharedKernel seam IMcpGateway (ListToolsAsync / CallToolAsync) + McpToolDescriptor / McpToolResult,
  so the Assembler discovers and can invoke MCP tools without referencing Integrations' tables.
- Integrations: McpServerConfig (org-scoped, owner-only; auth headers AES-GCM encrypted, never
  returned — only their names) + AddMcpServers migration. McpClient: a dependency-free Streamable-HTTP
  JSON-RPC 2.0 client (initialize → notifications/initialized → tools/list / tools/call), carrying the
  Mcp-Session-Id and parsing both application/json and text/event-stream replies. McpGateway resolves
  an org's servers, decrypts headers server-side, and is best-effort: an unreachable server is logged
  and skipped, never failing the run. CRUD + connectivity-test endpoints (create/test/delete owner-only
  via ManageApiKeys; list via ConfigureAgents to bind).
- OrgBoard: Agent gains McpServerIds (uuid[]; migration backfills existing agents to empty) flowing
  through ConfigureAgent + AgentRunContext.
- Assembler: AgentRunExecutor lists the agent's MCP tools (best-effort) and PromptAssembler renders a
  "# Tools (MCP)" catalog — labelled as data, never instructions — and records it in the run trace.
- Client: SeatsPage gains an MCP servers card (add/test/delete, encrypted auth header) and a per-agent
  MCP server multi-select; api client gains del().

Note: discovery + the governed call gateway are in place now; the autonomous model-driven tool-call
loop (model emits tool_calls → gated execution → feedback) needs a tool-calling model client and is
the next increment — the stub model can't drive it.

Verified: ArchitectureTests 8/8, IntegrationTests 53/53 (McpClientTests: JSON-RPC handshake/session,
json + SSE; McpServerRegistryTests: owner-only, encrypted-header-never-returned, graceful test,
Member 403; PromptAssemblerMcpTests: catalog + trace, omitted when empty), client build green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 19:25:43 +03:30
soroush.asadi 1e65654114 Org structure: divisions → products/services → teams + custom model base URL
The object spine becomes definable (data model was designed-for from day one):
- Division and Product entities (Product carries kind: Product|Service, optional DivisionId);
  Team gains nullable ProductId — pre-structure teams keep working. AddDivisionsAndProducts
  migration; org-scoped validation; owner-only writes (audited); list endpoints.
- /structure page: define divisions, products/services (with division), teams (under a
  product). Org chart now renders the full spine — org → divisions → products → teams →
  seats — with parentless layers linking up to the org.
- BYOK custom URL: the SeatsPage model-connection form gains a Base URL field (provider
  list: stub/openai/ollama/vllm/custom). Backend already supported it end to end —
  ApiConfig.Endpoint flows into the OpenAI-compatible adapter ({base}/v1/chat/completions),
  so any OpenAI-compatible gateway or self-hosted model works; the config list shows it.

Verified: ArchitectureTests 8/8, IntegrationTests 45/45 (new OrgStructureTests: spine
creation, kind tags, org-scoped validation 400s, Member 403), client build green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 18:13:52 +03:30
soroush.asadi e202246a1c M3: Agent bound to a seat — configure an AI seat
OrgBoard: Agent entity (name, monogram, autonomy dial, ApiConfigId + optional fallback,
skill keys, docs) + AddAgents migration; one agent per seat. References Skills by key and
the BYOK config by id — never reaches into those modules.

Endpoints: POST/GET /api/orgboard/seats (create/list seats), POST/GET
/api/orgboard/seats/{id}/agent (configure/read the agent) — ConfigureAgents at [team, org].
Configuring an agent flips the seat to the AI state and points it at the agent; audited.

Verified: build green; ArchitectureTests 8/8; IntegrationTests 27/27 incl. the M3 acceptance
flow — owner adds a BYOK config, then configures "Aria" (gated autonomy, skills, that config)
on a seat, flipping it to AI, with the key never exposed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 23:49:28 +03:30
soroush.asadi e1911f58b1 M1: OrgBoard — organizations, teams, seats, the board & cartable
OrgBoard module (references SharedKernel only; RBAC via ICurrentUser/IPermissionService):
- Organization, Team, Seat (human/open/ai), WorkItem (board task: type, status, assignee,
  parent) entities; internal OrgBoardDbContext (schema "orgboard") + InitialOrgBoard
  migration; design-time factory. (WorkItem avoids the System.Threading.Tasks.Task clash.)
- Endpoints under /api/orgboard, every mutation permission-checked at the scope chain
  [team, org]: POST /organizations, POST/GET /teams, POST /tasks, GET /board (columns
  backlog->in progress->in review->done), PATCH /tasks/{id}/move, /assign, GET /cartable.

Test isolation: integration tests now use IClassFixture so each class gets its own
pgvector container (the bootstrap-once rule made a shared container collide).

Verified: build green; ArchitectureTests 8/8 (OrgBoard references only SharedKernel);
IntegrationTests 12/12 incl. a new board flow — owner sets up org+team, creates/moves/
assigns a task, sees it on the board and in the cartable; an invited Member can view the
board but is 403'd from creating a team.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 11:58:20 +03:30