A new "Get started" page (top of the sidebar) that detects setup progress from real data
and guides the full flow: model the org -> product identity -> connect a model (BYOK) ->
staff an AI seat -> fill the backlog -> review the first agent output. Each step shows
done/todo with a deep link, plus an overall progress bar.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Updates §11 to reflect the shipped app-wide glassmorphism theme (frosted glass over a
gradient field, dark-glass sidebar, gradient primary actions), the animated agent-identity
face, and the Action→Result→Run log review inbox — superseding the original flat language.
The load-bearing seat-state triad is unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
App-wide glassmorphism (frosted cards/popovers/sheets/inputs/pills + gradient field, gradient primary actions, dark-glass sidebar) with contrast fixes; and a restructured review inbox showing each held item as Action -> Result -> Run log, with the run log surfacing latency, skills, tools called, memory hits, product-identity inclusion, raw output, and the assembled prompt (enriched assembler run endpoint).
Restructures each held item into Action -> Result -> Run log:
- Action: a clear statement of what approving does (write artifact + N child tasks),
with a destructive warning where relevant.
- Result: the editable proposed artifact + child tasks (with the edit diff).
- Run log: lazily fetches the AgentRun and shows latency, the agent/autonomy, skills
applied, available + actually-called tools (with ok/failed), memory hits, product-
identity inclusion, and collapsible raw model output + assembled prompt.
Enriches the assembler run endpoint (Trace, ResultJson, LatencyMs, timestamps) so the
approver can see exactly how the agent reached its result before deciding.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neutral badges become frosted (translucent + blur), the primary badge picks up the
gradient, and the sidebar nav active/hover states are now a frosted white highlight
(ring + blur) instead of the opaque accent — cohesive on the dark-glass sidebar.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Addresses washed-out contrast and extends glass to the sidebar:
- Deeper, more vivid gradient field so frosted cards lift off the background.
- Cards more opaque (0.74) with crisper borders + inner highlight; darker muted text.
- Frosted form fields kept more opaque than cards so input text stays high-contrast
(mode-aware light/dark).
- Sidebar is now true dark frosted glass (translucent + backdrop-blur) instead of a
solid gradient, kept dark enough to keep the white nav text readable.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Central restyle keyed on shadcn data-slots so all 13 pages inherit it without edits:
a soft gradient field on the body, frosted-glass surfaces (translucent --card/--popover
+ backdrop-blur + hairline borders) on cards, popovers, selects, sheets, and form fields,
gradient primary buttons with glass secondary/outline, and a gradient + blurred sidebar.
The content area is transparent so the gradient shows behind the glass. Inline-styled
gradient cards (Team view) are unaffected.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Animated agent identity (Companion face) + per-team activity endpoint/hook; in-app Markdown Edit/Preview authoring + read-only .md viewer across skills/profiles/persona/review; shared version-library helpers; MCP tool-use execution loop for autonomous agents; BYOK full-URL endpoint fix; product-centric agents — shared PRODUCT.md identity injected into every run, in-app identity editor, layered product+team working memory, and a versioned PRODUCT.md library + marketplace with apply-to-product; a gradient Team view of a product's AI agents with live status.
A new "Team" page (route /team, sidebar entry) showing a product and its AI agents as
gradient cards: a hero card with the product's shared identity summary + team/agent
counts, then one gradient card per AI agent (role-themed gradient, monogram, role/team,
autonomy, skills) with live run status via useAgentActivity. Gradients are a deliberate,
scoped exception to the app's flat house style, used only on this showcase view.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A new "Product profiles" page (library + marketplace) mirroring the agent-profile
library: upload/author a PRODUCT.md (Markdown editor), view, edit, new version, fork
builtins, publish/unpublish, install from marketplace, and Apply-to-product (sets the
chosen product's shared identity). Reuses groupVersions + MarkdownEditor; adds the
route and a sidebar entry.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
Generalizes working memory to a scope: ITeamMemory becomes IWorkingMemory with a
MemoryScope (Team | Product); MemoryEntry's TeamId becomes ScopeType+ScopeId (data-
preserving rename migration). On approval, Governance writes the decision/correction
at PRODUCT scope when the team belongs to a product (resolved via IBoardStats), so it
is shared by every agent across the product's teams — else at team scope. The assembler
recalls product memory (shared) plus team memory (local), merged by relevance, under a
"# Shared memory" section.
This is the other half of product-centric agents: a decision approved on one team now
informs every agent on the product, not just that team.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Each product on the Structure page gets an "Identity" action that opens the Markdown
editor (Edit/Preview, frontmatter-aware) wired to GET/PUT /products/{id}/identity, with
a starter PRODUCT.md template. Adds api.put. Saving makes the brief shared by every
agent across the product's teams (injected by the assembler from Slice 1).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
The OpenAI-compatible adapter unconditionally appended /v1/chat/completions to the
configured endpoint, so a BYOK config whose endpoint is the full gateway URL (e.g.
https://host/v1/chat/completions) produced a doubled path and failed. ResolveChatUrl
now uses the URL as-is when it already targets /chat/completions, appends
/chat/completions to a base ending in /v1, and otherwise appends /v1/chat/completions.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extracts the per-key version grouping + same-version dedupe (org-owned shadows
builtin) into lib/versionedLibrary.groupVersions and the semver patch bump into
lib/semver.bumpPatch, both of which were duplicated byte-for-byte across the
Skills and Agent-profiles pages. One source of truth so the two libraries can't
drift.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds MarkdownEditor (react-markdown + remark-gfm, no raw HTML — authored/retrieved
content is data, not markup) with Edit | Preview tabs, wired into the AGENTS.md and
SKILL.md editors, the agent persona, and the review artifact.
Adds a read-only "View" on every skill and agent-profile card — including builtins,
which previously had no way to be inspected at all — rendering the full SKILL.md /
AGENTS.md (frontmatter + body + actions/golden tests). Collapses a same-version
builtin that an org has forked so its own copy shadows it, keeping the version
picker unambiguous and the item clearly editable/versionable.
Also lands the agent-face wiring on the seat configurator (a live xl preview with a
state cycler) and the review inbox header.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Each AI agent now has an expressive Companion face (AgentFace) whose animation
maps to its real AgentRun state — idle, thinking (queued), working (running),
review (held), done, failed — so a glance at the board or org chart reads as live
status, the same way the seat-state triad reads human/open/AI. Pure CSS keyframes
(no animation dependency), em-scaled across four sizes, per-agent hue derived
deterministically in the indigo band, reduced-motion respected.
Adds a per-team agent-activity read endpoint (latest run status per agent) and a
self-contained polling hook (useAgentActivity) that merges run activity with
governance holds. Wired into the board assignee chips and the org chart (a custom
React Flow seat node with hidden handles so edges still connect).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Autonomous agents with MCP tools now run a bounded tool-use loop: the model may
call tools (executed via the gateway, results fed back) until it returns a final
answer. Gated/DraftOnly agents get the tool catalog as data but never auto-call —
a human-in-the-loop agent never autonomously reaches an external tool.
Extends IModelClient with tool definitions and a tool-use conversation, adds the
OpenAI-compatible tool serialization/parsing plus a deterministic "tooluse" stub
client, and records every tool call in the run trace.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The AI-seats configurator gains a "Start from a profile (AGENTS.md)" picker. Selecting one loads
the org's resolved profile (builtins + authored + installed, one per key) and prefills the agent's
name, monogram, recommended autonomy, and skills (intersected with the org's skill library), and sets
the operating-guide persona — all still editable before saving. A persona textarea is shown and sent
to ConfigureAgent (already persisted + injected into the run as "# Operating guide"). Closes the loop:
upload/install an AGENTS.md → stand up a seat from it in one step.
Frontend only; the persona/ConfigureAgent path is covered by existing tests. Client build green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Brings two stacked features to main:
- MCP compatibility: org MCP server registry (encrypted), JSON-RPC client, gateway, agent
binding, run-time tool catalog injection.
- Agent profiles (AGENTS.md): per-org library, free builtins, versioning, fork, marketplace
publish/install, and persona injection into runs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
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>
Adversarial review found a display-vs-run mismatch: the seat picker collapses the library to the
first row per key, but ListSkills ordered by version only — so for a key the org authored alongside
a higher-versioned builtin, the picker showed/flagged the builtin while the run injected the org's
own skill. ListSkills now orders the same way the run-time catalog resolves (Published-first,
org-owned-over-builtin, then latest version with the same Ordinal comparison), computed in-memory so
the version tiebreak can't diverge from SkillCatalog. The run itself was already correct; this aligns
what the operator sees with what executes. No client change needed.
SkillRunScopingTests now also asserts the library's first row for a key the org authored is the
org-owned Published row, not the builtin.
Verified: skills test subset 4/4 (full suite green pre-merge).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ISkillCatalog.GetByKeysAsync now takes the org id and resolves each key within that org's namespace
only — the org's own published skill, else a shared builtin (null org), never another org's. Org-owned
is preferred over the builtin; only Published (golden-tested) skills are injected; the resolved
skill@version is recorded in the prompt heading and run trace. AgentRunExecutor threads
context.OrganizationId. SeatsPage now loads the org library (builtins + authored + installed), dedupes
to one entry per key, and flags drafts (won't run until published).
Verified: ArchitectureTests 8/8, IntegrationTests 48/48 (new SkillRunScopingTests: a run assembles the
org's own skill over the builtin of the same key, and another org's same-key skill never leaks in),
client build green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Orgs can now share skills across the tenant boundary — the next step after the per-org library.
Endpoints (all ManageSkills-gated + audited):
- POST /{key}/publish — list one of your published versions on the marketplace (Visibility→Public;
only a Published/golden-tested skill may be listed). POST /{key}/unpublish reverses it.
- POST /install — copy a publicly-listed skill (by row id) into your org as a private Installed
copy; rejects installing your own skill and duplicate (org+key+version) installs.
- GET /marketplace?organizationId= — other orgs' Authored+Public+Published skills (yours excluded),
each flagged whether that exact (key, version) is already in your library.
- SkillSummary now carries Id (install targets a specific source row). Authored skills default to
private — listing is an explicit publish step, never a side effect of authoring.
UI (Skills page): a Marketplace tab with Install / "In your library"; Publish / Unlist on your own
published skills; a "Listed" badge.
Fixes from the adversarial review (4 confirmed findings, all addressed):
- HIGH — Public⟹Published is now a domain invariant (Skill.Index forces PrivateToOrg whenever the
re-derived status isn't Published), so re-authoring a listed version without golden tests can no
longer leave it Public+Draft or decouple the marketplace gate from the eval gate.
- MEDIUM — install now uses an insert-only indexer path so the (org,key,version) unique index is the
source of truth: a race with a concurrent install/author becomes a clean 409, never an in-place
clobber of an existing row's content/ownership.
- MEDIUM/LOW — AlreadyInLibrary is computed per (key, version) to match the install conflict rule, so
a newer, not-yet-owned version of a key you already hold still shows as installable.
Verified: ArchitectureTests 8/8, IntegrationTests 47/47 (SkillMarketplaceTests: publish gate, own-org
exclusion, cross-org list→install→private copy, duplicate 409, per-version flag, Public⟹Published
invariant, Member 403), client build green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Skills move from a global Git-only registry to a per-company library that orgs author and
version in-app — Git stays as the shared *starter* library.
Domain & persistence:
- Skill gains OrganizationId (null = shared builtin, visible to every org), Origin
(Builtin | Authored | Installed), AuthoredByMemberId. Identity is now
(OrganizationId, SkillKey, Version); the unique index uses NULLS NOT DISTINCT so builtins
stay unique by key+version while each org gets its own namespace (and can fork a builtin).
AddSkillOwnership migration backfills existing rows as Builtin.
- Owned GoldenExample rows are cloned in Skill.Index so a fork can't re-parent the source's
tracked entities.
Authoring (tenant, dynamic):
- POST /api/skills/authored — structured fields → same indexer pipeline (embedding +
publish gate apply identically), tagged org + author. POST /api/skills/{key}/fork copies a
builtin/global skill into your org as an editable Authored draft. List/Get are org-scoped
(your org + shared builtins). New Capability.ManageSkills (Owner + TeamOwner), audited.
- GET /api/skills/marketplace: read-only seam listing public skills across orgs (install is
the next step).
Security (from adversarial review — two confirmed criticals):
- Managing shared builtins is an operator action, not a tenant one. /index (posts arbitrary
content as a global builtin) and /sync (re-indexes the shared library) now require a
platform admin key (X-Skills-Admin-Key, fixed-time compare, fail-closed when unset) via
SkillAdminOptions — previously any authenticated user of any org could inject/poison global
skills. New test asserts an authenticated Owner without the key gets 403 on both.
UI: new /skills library page — browse shared + org skills grouped by key with their versions,
create / new-version / fork, golden-test editor + body, Draft/Published badge and the
publish-gate hint (needs roles + ≥1 golden test).
Verified: ArchitectureTests 8/8, IntegrationTests 46/46 (new SkillLibraryTests: org
isolation, version coexistence, fork, publish gate, Member 403, admin-gate 403), client build
green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
IdentityModule registered AddAuthentication/AddJwtBearer/AddAuthorization in both hosts,
but the authorization policy cache requires endpoint routing (EndpointDataSource), which a
Generic Host worker doesn't have — Development's ValidateOnBuild crashed the worker at boot
(found by running it; tests always used WebApplicationFactory). The auth stack now registers
only when IWebHostEnvironment is present; ICurrentUser stays available everywhere (reports
unauthenticated off-request). Verified: worker boots + drains (processor started, heartbeats
healthy); IdentityFlowTests + ReviewFlowTests green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
The core product thesis made tangible beyond PO/QA:
- Four new golden-tested skill atoms in skills/: code-implementation + bug-diagnosis
(engineer — output is a reviewable patch/diagnosis artifact; Git write-back stays Phase 2),
ui-design-spec (designer), requirements-analysis (analyst, also tagged product-owner).
The catalogue now spans five roles with eight atoms.
- Seat configurator: SuggestedSkills — maps the seat's free-text role name to skill role
tags and offers the matching set one click ("Use set"). Any role name → staffed with AI.
- AnyRoleSeatTests: an "Backend Engineer" seat (Edison, gated) runs the same pipeline —
skills assemble, implement-code/Draft parsed, proposal held in the review inbox like any
governed action. SkillSyncTests updated for the larger catalogue.
Verified: IntegrationTests 44/44, client build green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
UI (daily-drivable now):
- Board: dnd-kit drag-and-drop between columns; click a card → task detail drawer (Sheet)
with status, member assignee picker, send-to-AI-seat dispatch, description/artifact,
parent/children navigation; seat-triad assignee chips (AI indigo monogram / human slate).
- Cartable page (the personal pending slice), Members & invitations page (invite + copy
join token; V1 sends no email), Review inbox now shows a word-level diff of your edits
vs the proposal (lib/diff.ts, LCS), Org chart page (React Flow: org → teams → seats in
the human/open/AI triad). Nav reordered; nothing left "soon".
Accountability & benchmarking:
- Identity: GET /members (directory + org role) and GET /invitations (with join token,
inviter-only) — the directory also resolves names client-side everywhere.
- OrgBoard: work_item_transitions recorded on every status change (AddWorkItemTransitions
migration); GET /performance — per assignee (human and AI on the same scale): pending by
column, done, worked hours (time in InProgress), avg cycle time (start of work → done),
plus the unassigned-pending count. Owner-level capability.
- Performance page: benchmark table merging board metrics with AI trust metrics (approval
rate + edit distance from analytics); flags work with no one accountable.
Verified: build green; ArchitectureTests 8/8; IntegrationTests 43/43 (new: directory,
invitations list + Member 403s, transition-derived worked-hours/cycle-time, unassigned
count); client npm build green (TS strict).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The two-role loop runs end to end and the bet is measurable: team working memory (pgvector)
written on approval and read at assembly; a story hitting done hands off to the QA agent
whose plan waits in review; analytics show approval rate and human edit distance per agent.
Verified: ArchitectureTests 8/8, IntegrationTests 42/42, client build green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Working memory (Memory module's first real code):
- MemoryEntry (schema "memory", vector(384), InitialMemory migration); TeamMemory implements
the SharedKernel ITeamMemory seam (embed-and-store on write, cosine recall on read);
GET /api/memory/search. HashingTextEmbedder promoted to SharedKernel (pure, deterministic;
swapped for ONNX/BYOK embedders later behind ITextEmbedder).
- Written on approval: Governance's approve stores an Approval/Correction entry per decision.
- Read at assembly: the executor recalls the team's top-3 relevant entries; the prompt gains
a "# Team memory" section (treated as data, not instructions).
The single V1 event trigger:
- IAgentDispatcher (SharedKernel) implemented by Assembler's AgentRunDispatcher (shared by
the API and triggers). OrgBoard's QaHandoffTrigger: a task hitting done creates a QA task
(provenance parent, assigned to the QA agent) and dispatches a run for the team's QA AI
seat. Guardrails: Test/Review tasks never re-trigger (no self-cascade) and a task hands
off at most once. Audited as handoff.triggered.
Analytics — the V1 verdict view:
- IBoardStats (SharedKernel) implemented by OrgBoard; GET /api/governance/analytics returns
approval rate, avg edit distance, per-agent metrics + edit-distance trend, tasks done.
- UI: /analytics — stat cards, per-agent table, recharts edit-distance trend per agent.
Verified: build green; ArchitectureTests 8/8; IntegrationTests 42/42 incl. the M6 acceptance
end to end — a dev marks a story done → Quill wakes via the handoff (QA task with provenance,
assigned to the agent) → drafts a test plan that waits in review → approve records the second
agent's edit distance → analytics show approval rate 100%, avg edit distance > 0, and trends
for BOTH Aria and Quill; memory written on Aria's corrected approval is recalled into her next
prompt; the guardrails hold. Client build green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Governance closes the loop: the autonomy x risk gate (destructive always holds), the
ReviewItem + review inbox (approve / edit-and-approve / send back) with the reasoning
trace, execution of approved actions onto the board (artifact + child tasks), and the
north-star metric — human edit distance — captured and audited for real. Verified:
ArchitectureTests 8/8, IntegrationTests 41/41, client build green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The trust centerpiece: /reviews lists held agent actions for the scopes the caller may
approve. Each card shows the agent badge, action kind + risk (destructive flagged red),
an EDITABLE proposed artifact and child-task list (edits feed the edit-distance metric),
an expandable reasoning trace (pretty-printed), and Approve / Send back. Toasts surface
the recorded edit distance. New shadcn-style Textarea; nav gains "Review inbox".
Verified: npm run build green (TS strict, 1893 modules).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SharedKernel:
- ActionRisk (risk lives on the action) + GatePolicy (the pure autonomy x risk matrix:
Read never holds, Draft/Publish hold unless Autonomous, Destructive ALWAYS holds).
- IActionGate (AgentActionProposal -> execute|hold) and IBoardWriter.AttachArtifactAsync.
Governance:
- ReviewItem (held action: artifact, child titles, trace, decision, edit distance) in a new
review_items table (AddReviewItems migration).
- ActionGate: hold -> ReviewItem + "action.held" audit; autonomous -> execute + audit.
- HeldActionExecutor: writes the artifact onto the task and creates the child tasks via
IBoardWriter (implemented by OrgBoard — no cross-module table access).
- Review inbox API: GET /api/governance/reviews (scope-filtered to where the caller may
approve), POST /reviews/{id}/approve (optional edited content/children -> normalized
edit distance recorded — the north-star metric), POST /reviews/{id}/sendback. Deciding
twice is 409; Members are 403.
Assembler:
- OutputParser (numbered-list child titles, conservative) and the executor now hands every
completed run's proposal to the gate.
OrgBoard: WorkItem.AttachArtifact + BoardWriter.AttachArtifactAsync.
Verified: build green; ArchitectureTests 8/8; IntegrationTests 41/41 incl. the full M5
acceptance — Aria (gated) proposes a spec, it waits in the inbox with its trace, a Member is
403'd, the owner edits-and-approves, the spec + four child stories land on the board, edit
distance > 0 is recorded and audited; Quill (autonomous) executes straight to the board;
destructive holds even for an autonomous seat and can be sent back. Plus the GatePolicy matrix.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A task → an AgentRun → a parsed output. Postgres job queue (FOR UPDATE SKIP LOCKED) drained
by the worker, the assembler (house-style + skills + task → prompt), the BYOK model call, and
output parsed into an action + risk tag captured on the run. Nothing executes yet (gate is M5).
Verified: ArchitectureTests 8/8, IntegrationTests 29/29.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SharedKernel contracts (so Assembler stays decoupled): IAgentRunContextProvider (agent +
task) and ISkillCatalog (skill prompts by key). Implemented by OrgBoard (AgentRunContextProvider)
and Skills (SkillCatalog).
Assembler:
- PromptAssembler builds house-style + identity + the agent's skill bodies + the task, and
derives the primary action + risk from the agent's first skill. RAG/working-memory join at M6.
- AgentRunExecutor (real): resolve context + skills → assemble → resolve BYOK config (with
fallback) → call IModelClient → parse into action + risk → capture all on the AgentRun.
Verified: build green; ArchitectureTests 8/8; IntegrationTests 29/29 — incl. the M4 acceptance:
assigning a Spec task to Aria (PO, gated, stub BYOK) yields a Completed run with the assembled
prompt (skill body + task title), action "write-spec", risk "Draft", and model output. Nothing
executes — the gate is M5.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SharedKernel: IWorkerModule seam (RegisterWorker runs in the worker host only).
Bootstrap: AddTeamUpWorkerServices; the worker host now wires it.
Assembler module (schema "assembler", InitialAssembler migration):
- Job (Pending→Processing→Done/Failed) + AgentRun (Queued→Running→Completed/Failed) entities.
- JobQueue: enqueue + ClaimNextAsync using `FOR UPDATE SKIP LOCKED` in a transaction.
- AgentRunExecutor (Increment-1 placeholder — real assemble/model/parse lands in Increment 2).
- JobProcessor BackgroundService drains the queue on the worker host (web off the model path).
- POST /api/assembler/runs enqueues a run; GET /api/assembler/runs/{id} reads it.
Verified: build green; ArchitectureTests 8/8 (Assembler references only SharedKernel);
IntegrationTests 28/28 incl. enqueue→claim(SKIP LOCKED)→process→Completed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Encrypted owner-only API configs (AES-256-GCM, key never returned), model adapters with a
connection test, the Agent bound to a seat (skills, autonomy dial, model config, docs) that
flips a seat to AI, and the seat-configurator UI. Verified: build green, ArchitectureTests
8/8, IntegrationTests 27/27, client build clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A "AI seats" page (shadcn, on the design language): manage BYOK model connections (add +
test; the key is write-only), create seats on a team, and configure an agent per seat — name,
the color-graded autonomy dial (draft slate / gated indigo / auto teal), a model connection,
skill toggles from the registry, and docs. Navigable AppShell sidebar (Board / AI seats).
Verified: client `npm run build` clean (1890 modules, tsc + vite).
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>
SharedKernel: Autonomy dial enum; IModelClient (ModelRequest/ModelCompletion);
IApiConfigResolver (+ ApiConfigSummary/ResolvedApiConfig) — server-side, decrypted.
Integrations module:
- ApiConfig entity (org-scoped) + IntegrationsDbContext (schema "integrations") +
InitialIntegrations migration; the key is AES-256-GCM encrypted at rest (key derived from
Encryption:MasterKey) and never returned to a client.
- Model adapters: StubModelClient (no-network, provider "stub"/"echo"), an OpenAI-compatible
HTTP adapter, and a ModelClientRouter; ApiConfigResolver decrypts server-side only.
- Endpoints: POST/GET/DELETE /api/integrations/api-configs and POST .../{id}/test. Create/
test/delete require ManageApiKeys (owner); listing requires ConfigureAgents (assign-only,
no key). Dev master key in appsettings; override Encryption__MasterKey in prod.
Verified: build green; ArchitectureTests 8/8 (Integrations references only SharedKernel);
IntegrationTests 26/26 incl. a BYOK flow — key never appears in any response, the connection
test succeeds (stub), and a Member is 403'd from create + list.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>