You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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 /agents accepts name/slug/description/category/model/personality/goal — notcapabilities.
PUT /agents/:id allows 8 columns — not surfaces/runtime/workflow/tools.
PUT /agents/:id/capabilities accepts onlycustomSurfaces.
Wire the declarative power fields through the existing owner-only capability routes + create:
sanitizeDeclaredCapabilities(input) in lib/agent-capabilities.ts — validate surfaces[] (∈ KNOWN_SURFACES), runtime (∈ {browser,coding,null}), workflow (∈ {JOB_APPLY,CODING_SESSION,INSURANCE_QUOTES,null}), tools[] (via existing sanitizeToolList). Re-introduce KNOWN_RUNTIMES/KNOWN_WORKFLOWS as validation sets. Drop unknowns silently (same philosophy as the read-side filter). Composes existing sanitizers — do not re-validate customSurfaces/settingsSchema (their dedicated routes own those).
Extend PUT /agents/:id/capabilities to also accept + merge surfaces/runtime/workflow/tools (keep customSurfaces handling as-is), and GET /agents/:id/capabilities to return them.
Extend POST /agents with an optional sanitized capabilities object at creation.
Console: a capabilities editor in AgentDetail.tsx (surfaces multiselect, runtime select, workflow select, tools multiselect from TOOL_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/workflow are 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 while customSurfaces (which loads a code bundle into the console origin) stays a separate, more-guarded path.
Replicating Coder needs NO new vocabulary — coding/coding/CODING_SESSION are 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.
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 force surfaces:["coding"] ⇒ runtime:"coding". lintAgentClaims already warns on capability/description mismatch at create.
No AgentDefinition mega-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.
POST /agents with capabilities persists a valid config.capabilities; GET/PUT /agents/:id/capabilities round-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).
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 onagentCapabilities()(surfaces/runtime/workflow/tools), not the"coder"slug. The loneslug === "coder"check inlib/agent-capabilities.ts:300is a legacy fallback, never consulted onceconfig.capabilitiesis present. A D1 row with the rightconfig.capabilitiesbehaves 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.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).PUT /agents/:id/capabilitiesto also accept + mergesurfaces/runtime/workflow/tools(keepcustomSurfaceshandling as-is), andGET /agents/:id/capabilitiesto return them.POST /agentswith an optional sanitizedcapabilitiesobject at creation.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
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.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.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.surface:repo, runtime:null, workflow:null). We do NOT forcesurfaces:["coding"] ⇒ runtime:"coding".lintAgentClaimsalready warns on capability/description mismatch at create.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.{surfaces:["coding"],runtime:"coding",workflow:"CODING_SESSION"}via API alone yields a working Coder-equivalent (coding tab, session, tools) with no code change.Refs: #51, #58, #62 (removed dead code), #84 (connectors, done).