Repository navigation
Wire declarative capabilities (surfaces/runtime/workflow/tools) through create + update — the missing authoring path (#51) #141
Description
Context
Research (2026-08-03) confirmed the Coder agent is already fully capability-driven at runtime — every consumer (coding routes, CodingSessionWorkflow, browser-runner, console Coding tab, agent-do tools, MCP) branches on agentCapabilities() (surfaces/runtime/workflow/tools), not the "coder" slug. The lone slug === "coder" check in lib/agent-capabilities.ts:300 is a legacy fallback, never consulted once config.capabilities is present. A D1 row with the right config.capabilities behaves identically to Coder with zero platform code changes — already proven by repo-chat (migrations 0032/0050) and Coder's own GitHub tools (0054), all defined as pure data.
The connector/tool layer is likewise sufficient: the #84 epic is complete (unified registry, 7 connectors, consent gate, auto-exposed to runtime+API+MCP), and the coding delegation tools (list_coding_repos/read_terminal/send_to_cli) are auto-injected on the coding surface.
The one missing piece is the authoring path. Capabilities can only be set today via SQL migrations:
POST /agentsaccepts name/slug/description/category/model/personality/goal — notcapabilities.PUT /agents/:idallows 8 columns — not surfaces/runtime/workflow/tools.PUT /agents/:id/capabilitiesaccepts onlycustomSurfaces.- The formal
AgentDefinition/sanitizeAgentDefinitionvalidator was built then removed as unwired dead code (commitf471ee1, PR feat(agents): formal declarative agent-definition schema (#51) #62) — "wiring deferred to the next PR that never came."
Scope (this issue)
Wire the declarative power fields through the existing owner-only capability routes + create:
sanitizeDeclaredCapabilities(input)inlib/agent-capabilities.ts— validatesurfaces[](∈KNOWN_SURFACES),runtime(∈{browser,coding,null}),workflow(∈{JOB_APPLY,CODING_SESSION,INSURANCE_QUOTES,null}),tools[](via existingsanitizeToolList). Re-introduceKNOWN_RUNTIMES/KNOWN_WORKFLOWSas validation sets. Drop unknowns silently (same philosophy as the read-side filter). Composes existing sanitizers — do not re-validatecustomSurfaces/settingsSchema(their dedicated routes own those).- Extend
PUT /agents/:id/capabilitiesto also accept + mergesurfaces/runtime/workflow/tools(keepcustomSurfaceshandling as-is), andGET /agents/:id/capabilitiesto return them. - Extend
POST /agentswith an optional sanitizedcapabilitiesobject at creation. - Console: a capabilities editor in
AgentDetail.tsx(surfaces multiselect, runtime select, workflow select, tools multiselect fromTOOL_CATALOG), reusing the same GET/PUT pattern as the existing customSurfaces/settingsSchema editors.
Critical assessment / risks
- Closed-enum validation is the safety boundary.
surfaces/runtime/workfloware closed unions — a creator can only pick capabilities the platform already implements. No arbitrary code, no new blast radius. This is why wiring them is safe now whilecustomSurfaces(which loads a code bundle into the console origin) stays a separate, more-guarded path. - Replicating Coder needs NO new vocabulary —
coding/coding/CODING_SESSIONare known values. A genuinely new agent type (novel surface + its own workflow) still needs a monorepo PR to extend the enums + add the workflow binding — tracked by [3P] Tier-1: declarative agent schema + open tool catalog + shared runtime #51, explicitly out of scope here. - Trust gating is deferred, not solved. Declaring
runtime:"coding"/workflow:"CODING_SESSION"lets an agent's Pilot drive a CLI/browser on a subscriber's machine (consent-based: the subscriber runspags up, Pro-gated — same risk profile as Coder itself). Acceptable only because agent creation is operator-only today (epic Epic: first-party exemplary agents → mature the platform → open to third parties (demand-gated) #58 is demand-gated/blocked). Before third-party creators may self-declare runtime/workflow, the trust model ([Epic] Open browser-agent creation to creators — BLOCKED on a trust model #74/[browser][trust] Trust & permission model for browser agents (design prerequisite) #75) must land — see the companion issue. - Coherence is intentionally not over-constrained. We validate each field against its enum independently and allow partial combos (repo-chat is a valid
surface:repo, runtime:null, workflow:null). We do NOT forcesurfaces:["coding"] ⇒ runtime:"coding".lintAgentClaimsalready warns on capability/description mismatch at create. - No
AgentDefinitionmega-schema resurrection. feat(agents): formal declarative agent-definition schema (#51) #62 died because it was a validator with no consumer. This issue wires the existing per-field sanitizers into the existing routes — the minimum that makes capabilities authorable — rather than a speculative full-definition struct.
Acceptance criteria
-
sanitizeDeclaredCapabilitiesunit-tested (valid pass-through, unknown surface/runtime/workflow dropped, tools capped/deduped, junk → undefined fields). -
POST /agentswithcapabilitiespersists a validconfig.capabilities;GET/PUT /agents/:id/capabilitiesround-trip surfaces/runtime/workflow/tools + preserve customSurfaces/settingsSchema. - Creating an agent with
{surfaces:["coding"],runtime:"coding",workflow:"CODING_SESSION"}via API alone yields a working Coder-equivalent (coding tab, session, tools) with no code change. - Console capabilities editor reads/writes the fields.
- Owner/admin-gated; unknown enum values rejected.
Refs: #51, #58, #62 (removed dead code), #84 (connectors, done).
Activity
feat(agents): wire declarative capabilities through create + update (#…
serge-ivo commentedon Aug 2, 2026
Shipped in
52e8eb1(deploy-api + deploy-host green).What landed
sanitizeDeclaredCapabilities()— validates surfaces/runtime/workflow against the closed enums + tools viasanitizeToolList; returns only present keys (clean partial PATCH).POST /agentsaccepts an optionalcapabilitiesobject at creation.GET/PUT /agents/:id/capabilitiesround-trip surfaces/runtime/workflow/tools; PUT merges per-key and no longer wipescustomSurfaceson a capabilities-only PATCH (bug fixed en route).AgentDetail→ Capabilities editor (surfaces checkboxes, runtime/workflow selects, tool allowlist).Acceptance — all met
sanitizeDeclaredCapabilitiesunit-tested (valid pass-through, unknown surface/runtime/workflow dropped, tools capped/deduped/cleared).{surfaces:[coding],runtime:coding,workflow:CODING_SESSION}agent created via API alone resolves to a Coder-equivalent — verified live (declared caps returned exactly; junk tool dropped; deleted cleanly).1714 tests green. Opening this authoring path to third-party creators remains gated on the trust model — #142.
feat(agents): capabilities update path + MCP passthrough; enable brow…
docs: connector-manifest design + refresh agent-platform strategy/plan
fix(agent): a declared-tools agent was described as having tools it l…
fix(pipeline): a step is now bounded by what its agent declares (#381)…