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
{{ message }}
Repository navigation
[bug] The catalog claims lint runs on agent create but not on update — the path where descriptions actually change #362
lintAgentClaims (#66) is the catalog-integrity check: it flags a description promising a runtime
capability — browser automation, posting/publishing, a local runner, cron/scheduled runs — when the
agent's capabilities declare noruntime and noworkflow. Pure, heuristic, deliberately
overridable, and loud.
POST /v1/agents runs it (routes/agents.ts:385) and returns the warnings alongside the 201:
PUT /v1/agents/:id accepts description in its patch body and returns { success: true }. It never
calls the lint.
Why that is the path that matters
Description edits overwhelmingly happen on update, not create — copy gets rewritten as the agent
finds its audience, long after the capabilities were declared. So the realistic sequence is:
Create an agent with honest copy and no runtime → clean 201.
Later, rewrite the description to "runs a headless browser and posts on your behalf" → 200, no
warning, published to the catalog.
The check exists, is already imported in that file, and is simply not in the path where the thing it
checks actually changes. #66 framed this as "for a store, a description that overstates what the
agent does is an integrity bug, not polish" — and this is the one surface in the batch that faces buyers rather than the owner.
Fix
Call lintAgentClaims in the update handler with the post-patch description and the post-patch
capabilities, and return the warnings the same advisory way create does. Both routes should read the resolved values rather than only body.description — an update that changes capabilities while
leaving the copy alone can create the same mismatch from the other direction, and today neither route
would notice.
Advisory is the right strength; the header calls it heuristic and overridable and that should not
change. This is about the check being present, not about making it block.
Class: the same mismatch as #351, #353, #354, #358 — a surface accepting a claim the runtime cannot
back — seen from the creator side.
The claim held, exactly as written.PUT /v1/agents/:id accepted description and never called lintAgentClaims, while POST /v1/agents did. The half of #141 the ticket wondered about — sanitizeDeclaredCapabilities — was already wired into update; it was only the lint that was missing.
Both directions now, and from all three doors. lintResolvedAgentClaims reads the post-patch description against the post-patch capabilities, so it also catches the mismatch arrived at backwards: capabilities dropped under copy nobody touched. PUT /:id/capabilities is that door, so it reports the same way; create was moved onto the same call.
Resolved capabilities, not the declared block — agentCapabilities is the fact the runtime itself reads, and it falls back to the slug/category derivation for pre-registry agents. Linting only config.capabilities would have accused coder, whose honest copy promises a local runner backed entirely by that fallback, of overclaiming. There is a test for exactly that. Deriving from the same fact the executor reads is what stops the surfaces disagreeing (#354, #358).
Advisory and unchanged in strength: the warnings ride alongside the 200, the write always lands, and the heuristic stays overridable per #66's header. Documented on all three operations in store/openapi.yaml.
Activity
fix(api): the catalog claims lint runs where the copy actually changes (
test(api): drive both refusal paths, and document what the two now re…
serge-ivo commentedon Aug 7, 2026
Fixed on main — 455db2d (fix) + 4fc7e38 (tests + spec).
The claim held, exactly as written.
PUT /v1/agents/:idaccepteddescriptionand never calledlintAgentClaims, whilePOST /v1/agentsdid. The half of #141 the ticket wondered about —sanitizeDeclaredCapabilities— was already wired into update; it was only the lint that was missing.Both directions now, and from all three doors.
lintResolvedAgentClaimsreads the post-patch description against the post-patch capabilities, so it also catches the mismatch arrived at backwards: capabilities dropped under copy nobody touched.PUT /:id/capabilitiesis that door, so it reports the same way; create was moved onto the same call.Resolved capabilities, not the declared block —
agentCapabilitiesis the fact the runtime itself reads, and it falls back to the slug/category derivation for pre-registry agents. Linting onlyconfig.capabilitieswould have accusedcoder, whose honest copy promises a local runner backed entirely by that fallback, of overclaiming. There is a test for exactly that. Deriving from the same fact the executor reads is what stops the surfaces disagreeing (#354, #358).Advisory and unchanged in strength: the warnings ride alongside the 200, the write always lands, and the heuristic stays overridable per #66's header. Documented on all three operations in
store/openapi.yaml.CI green on 4fc7e38.
feat(capabilities): an agent declares what it may PASS, and the dispa…
fix(agents): the tmux Operator is a tmux agent by construction, not b…