Repository navigation
Description
[Catalog] Audit every published agent — keep / fix / unpublish
Tracking issue for a data-driven catalog cleanup. A live pull (2026-08-01) showed 22 published agents, all first-party (creator: operator), 0 external creators, 0 external users, lifetime AI spend $0.86 / 69 calls over 4 days, with real usage concentrated on one agent (Coder, 47 calls — the operator dogfooding). The catalog also contains smoke-test fixtures and agents whose descriptions promise capabilities they don't have.
Do
Produce a table for every published agent: slug · subscribers · 30d calls · store_type · declared capabilities (surfaces/runtime/workflow) · description-matches-capabilities? · verdict. Verdicts: keep (works + used), fix (works, needs description/cleanup), unpublish (test/dupe/vaporware).
Known findings to action (children)
- Smoke tests in the live store → unpublish (#c2)
- Description ≠ capability (Creator OS, QA Automation, job-application-assistant) → fix + add lint (#c3)
- Duplicate/dogfood agents + instances → collapse (#c4)
Acceptance
- One audit doc/table covering all published agents with the columns above.
- Every agent has a keep/fix/unpublish decision.
- The three child issues are filed and linked.
Evidence: GET /v1/admin/agents + list_agents + usage_summary (2026-08-01).
Children
- [Catalog] Unpublish smoke-test agents from the live store #65 Unpublish smoke tests
- [Catalog] Fix description-vs-capability integrity + add a claims lint #66 Description-vs-capability + lint
- [Catalog] Collapse duplicate + dogfood agents and instances #67 Collapse dupes/dogfood
Activity
fix(catalog): close the two doors that let the catalog re-clutter (#64,
serge-ivo commentedon Aug 6, 2026
Catalog audit — complete. Public catalog 29 → 13.
Live pull 2026-08-06 (
GET /v1/agents,/v1/admin/agents,/v1/admin/instances,GET /v1/usage?days=30). Every agent in the store is first-party;coderis owned by theproagentstoreseed account, all 37 others by the operator. Still 0 external creators; the only non-operator instance rows are the operator's own second identities (sivochkin@gmail.com, GitHubserge-ivo).The bar applied: would a first-time visitor think this is a real product? An agent stays if it has a real description, a capability that actually exists, and a plausible use case.
KEEP — 13
codercoder-reposurfaces:[coding] runtime:coding workflow:CODING_SESSION+ 6 toolscoder-leadfacebook-friend-confirmerruntime:browser workflow:BROWSER_TASKsmall-business-website-lead-finderlead-outreach-tj6qrrtmux-operatorsurfaces:[tmux] runtime:coding+ 6terminal_*toolslocal-repo-chatruntime:coding+ 4repo_*toolsrepo-chat(local checkout vs GitHub).repo-chatsurfaces:[repo]+ 3 declared toolsdoc-chatlanguage-buddysettingsSchema(migration 0041)settingsSchema+ voice-language reference.job-application-assistantsurfaces:[apply] runtime:browser workflow:JOB_APPLYsite-builderUNPUBLISH →
draft— 16 (done, nothing deleted)Every one is now
visibility:"draft". Drafting only gatesPOST /v1/instances/:agentId/subscribe; existing instances, chat and runs are untouched (verified — no other route readsagents.visibility). Fully reversible, and the rows survive, which matters because migrations 0033/0059/0072 useSELECT owner_id FROM agents WHERE slug='data-analyst'as their operator-account anchor.Self-declared test fixtures (3) — the description literally begins "Test agent for…". Published 2026-08-05, before the #65 guard; the guard's whole-word
testmarker catches all three, so they cannot come back accidentally.terminal-operator,iterm-operator,kitty-operatorVaporware —
configis{},worker_namenull,cron_schedulenull, 0 instances, 0 usage (11). Each description promises a capability that does not exist anywhere in the platform for that agent:site-monitor— "every hour… webhook alerts": no cron, no webhookcompetitor-intel— "daily": no cronseo-auditor— "daily crawl": no croncontent-pipeline— "daily": no cronsupport-escalator— "daily summary": no cronlead-qualifier— "receives leads via webhook": no webhookinvoice-parser—store_type:tool, "POST invoice text": no endpoint, no workerdata-analyst— "generates SQL, runs queries": no such capabilityemail-drafter— no capability at allchatbot— lowercase generic name, scaffold descriptionqa-automation— 0 instances, 0 usage, empty config, and it advertises ProAppStore apps, a sibling store, in the PAGS catalogVaporware with a dogfood instance (2) — drafted, instance left running:
creator-os-agent— promises "scheduled news scans… per-platform rate limits with a retry queue… publishing through your own accounts";config:{}, no runtime, no workflow, no cron, no connectors. 1 instance (23 msgs, 8 KB docs), 0 30d usage. Also has acreator-ostwin already sitting in draft.meeting-notes— "Webhook receives transcripts… Daily digest cron"; none of it exists. Its 1 instance belongs tosivochkin@gmail.com— see the question below.FIX (not unpublish) — for #66
job-application-assistant— "Rented job application assistant… uses the approved local browser runner taskjob.apply_basicfor basic resume-upload forms." That is internal task-type vocabulary on the storefront, and "Rented" reads as a placeholder. The agent works; the copy doesn't.Prevention — shipped (cec87d8)
POST /v1/batch/bulk-visibilitybypassed the #65 guard entirely — it was only wired ontoPUT /v1/agents/:id, so anything the single-agent route refused could still be published in bulk from the same session. That is precisely how this cleanup would have undone itself. Now guarded per agent and refused as a batch, with the sameallowTestAgentoverride; un-publishing is never blocked. 6 tests inworkers/api/src/routes/batch.test.ts.No further lint proposed: the #65 guard covers the fixture class, and
lintAgentClaims(#66) already covers the description-vs-capability class.Questions for the owner — NOT acted on
tmux-operator(real product description, seeded by migration 0072, most usage) and drafted the three whose descriptions say "Test agent for the … backend". But the tools are the genericterminal_*set covering tmux/kitty/iTerm2, so the surviving agent is arguably mis-named — "Terminal Operator" with the generic copy is the better storefront entry. Renaming it means diverging from migration 0072's seed. Your call.lead-outreach-tj6qrr. Genuine agent, scaffolded slug.PUT /v1/agents/:iddoes not acceptslug, so renaming needs a migration — and it breaks the public URL/agents/lead-outreach-tj6qrr/. Left published as-is.meeting-notes. Drafted as vaporware, but its one instance belongs tosivochkin@gmail.com. If that is not you, someone outside the operator account has a subscription to an agent that does nothing — worth a look either way.site-builderat 0 subscribers. Kept on merit (newest, fully declarative, migration-seeded). Flagging it because it is the only survivor with no usage at all.All three acceptance boxes are met: the table covers all 29 formerly-published agents, every one has a keep/fix/unpublish decision with a reason, and #65/#66/#67 are filed and linked. Leaving this tracking issue open — it's the parent of #66 (still open) and #67 (awaiting your ruling on the instance sets), and of the four questions above.
fix(templates): every scaffolded agent's deploy has failed since the …
fix(catalog): spell two categories the way the storefront filters them (
serge-ivo commentedon Aug 6, 2026
Re-audit 2026-08-06 (later same day) — the audit above is done; here is what it got wrong
I did not redo the table above. I verified it against live state and re-ran the guard/lint over the catalog as it stands right now. The cleanup landed and mostly holds — but it introduced a live storefront regression, missed a newly-published agent, and its usage evidence is stale.
Evidence:
GET https://api.proagentstore.online/v1/agents(14 rows),my_agents(38 rows),usage_summary(range:"all"),agent_analytics,vector_stats, andblockPublishReason/lintAgentClaimsrun over every published row.1. The cleanup broke the storefront filters — 5 of 9 buttons now tell visitors the store is empty
This is the highest-value finding, and it is a direct consequence of drafting 16 agents.
store/index.htmlfilters on an exact string match and falls through to the empty state:…and that empty state reads “Be the first to publish — No agents published yet.”
Live right now, against the 14 published agents:
Every chat/data/creative agent was one of the commodity rows drafted in this cleanup, so those three buttons went dead the moment it landed. Workers/Tools match 0 because all 14 published rows are
store_type:'agent'.So the first visitor this catalog was cleaned up for can click 5 of the 9 filter buttons and be told the store has nothing in it — and invited to be the first to publish — on a store with 14 agents. That is exactly the "don't embarrass the platform" failure the audit was for.
2. 9 of the 14 published agents are unreachable by any category filter
Same exact-match filter, against categories the hardcoded button row doesn't offer:
codeproductivitydeveloper-toolsSalescodingsocialeducationgeneralThere are three different category vocabularies in the codebase and no shared constant:
store/index.html)["general","chat","code","data","creative","productivity"](store/console/src/pages/AgentDetail.tsx:11) — note it offersgeneral, which the store cannot filterApplied (migration
0084, pushed — the only change I made): the two that were genuinely wrong data rather than missing buttons.coding→code. Same concept, two spellings;codeis what the store button, the console picker and the other three coding agents use.tmux-operatorwas the one coding agent missing from the "Code" filter purely because of the spelling.Sales→sales. The table's only capitalized category.I deliberately did not re-label
developer-tools/education/social/general. Those are good data; the button row is the bug, and degrading accurate categories to fit a stale hardcoded list would hide it.Safety checked before writing it:
categoryfeeds only the storefront chip/filter and the fallback capability derivation inlib/agent-capabilities.ts:477, which is short-circuited (line 459) for any agent declaring acapabilities.surfacesarray.tmux-operatordeclaressurfaces:["tmux"], so its resolved capabilities are unchanged. The fallback's category rules arecodeandinsurance; neitherSalesnorsalesmatches, so the Sales agents are unaffected.Recommended, not applied —
store/index.htmlis outside the files I was scoped to: derive the category buttons from the loaded agents and hide any type/category button matching zero. ~10 lines, and it fixes both tables above permanently and makes every future catalog cleanup self-correcting instead of silently emptying the storefront. Worth doing before any external visitor arrives.3.
mcp-clientis published and is not in the audit tableCreated 2026-08-06 02:50, after the table above was written. Published, 2 subscribers, 16 calls. The KEEP table has 13 rows; the live catalog has 14. Verdict in the table below.
4.
job-application-assistantis published and the #65 guard would block it todayI ran
blockPublishReasonover all 14 published agents. Exactly one hit, and it's the flagship apply agent:It survives only because it is already published — the guard fires on
nextVisibility === 'published', and nothing has sent that since. Any attempt to re-publish it (after a draft, or via/v1/batch/bulk-visibility) now 400s withoutallowTestAgent:true.This is a guard false positive, and it collapses neatly into the #66 copy fix already wanted for this same agent: rewriting “Runs a safe fill-only test by default and stops before Submit” as e.g. “Does a safe fill-only dry run by default and stops before Submit” removes the internal vocabulary and clears the guard in one edit. I did not touch published copy — owner's call.
lintAgentClaimsover all 14 published: 0 violations.5. The usage evidence in the issue body is stale by ~50×
#64 says “$0.86 / 69 calls over 4 days”, concentrated on one agent. Live
usage_summary(range:"all"):2,862 calls · ~$42.30 estimated · 20 subscriptions across 14 agents.
And it is no longer one agent — 11 of 14 have real usage:
Still all the owner's own traffic — 0 external users — so the shop-window framing stands. But #67's premise that “the real functioning catalog is ~4–5 agents” no longer holds.
Verdict on the 14 published agents as of now
codercoder-repocoder-leadtmux-operatorcoding→ codelocal-repo-chatrepo-chatsite-builderdoc-chatlanguage-buddysmall-business-website-lead-findermcp-clientlead-outreach-tj6qrrjob-application-assistantfacebook-friend-confirmerThe one unpublish I'd add:
facebook-friend-confirmerThe audit above kept it on usage alone (117 calls). Usage is the wrong test here — it's all the owner's own dogfooding, and the question this catalog has to answer is what a first visitor thinks.
It is a published, public storefront listing for an agent that automates a logged-in Facebook account — confirming friend requests and “optionally adds a few suggested friends” by driving the owner's real browser session. That is against Meta's platform terms, and it is the only
socialagent in the store. For a marketplace that wants to open to third-party creators, having that as a public catalog entry is a standing reputational and ToS exposure that no amount of dogfood traffic justifies.Recommendation: set
visibility:"draft". As this issue already established, drafting only gatesPOST /v1/instances/:agentId/subscribe— the owner's existing instance, its chats and its browser runs keep working untouched. Fully reversible. Not applied: unpublishing a working agent is the owner's call, not mine.Cosmetic, but it is the first impression: 8 of 14 cards are the same tile
store/index.htmlrendersconst icon = a.icon || '⚡'oniconBg = a.icon_bg || '#7c3aed'. Eight published agents haveicon:"", so a majority of the storefront grid is the identical purple ⚡ tile: mcp-client, tmux-operator, lead-outreach, facebook-friend-confirmer, small-business-website-lead-finder, doc-chat, language-buddy, job-application-assistant.Cheap and reversible (
PUT /v1/agents/:id {icon}), but it's eight aesthetic choices on the owner's live catalog, so I've listed it rather than picked emoji.What I changed vs. recommended
Changed — 1 commit (
fix(catalog): spell two categories the way the storefront filters them, migration0084_normalize_catalog_categories.sql): two narrow, idempotentUPDATEs. No schema change, no capability change, no visibility change, nothing deleted.pnpm typecheckclean, 3713/3713 tests pass, biome unaffected (SQL is not linted; the 30 pre-existing errors are onmainalready).Recommended, not applied: the storefront filter fix (§1–2),
facebook-friend-confirmer→ draft, thejob-application-assistantcopy edit (§4, also closes #66's item), the 8 missing icons, andlead-outreach-tj6qrr's slug/category.Was the ticket still accurate? Partly. Its ask was already satisfied earlier today. Its evidence is stale by ~50× on spend and wrong on the “one agent has all the usage” premise. And its acceptance criteria are met only if you don't count
mcp-client, which was published after the table was written — which is itself the argument for the derived-filter fix: a hand-maintained snapshot of a live catalog is stale the same day.fix(store): the storefront tells visitors it is empty when it is not
serge-ivo commentedon Aug 7, 2026
Third audit pass — 2026-08-08. Catalog is 15 published. Read-only; I changed nothing.
Two audits already ran on 2026-08-06. This pass re-verifies both against live state, and it finds one class of defect neither of them looked for: an agent that works for its owner and is dead on arrival for anyone who subscribes to it. Two published agents are in that state.
All access through the configured MCP server per
AGENTS.md—list_agents,my_agents,my_instances,agent_analytics,usage_summary(range:"all"),list_pipeline_runs,list_connections,list_errors. No REST, no DB, no writes. Repo cross-reference againstmain@db8a2af.What moved since 2026-08-06
portal-watchis new and published (seeded migration0087, created 2026-08-06 19:41). Neither prior table has it. 15 published, not 14.b0d5486replaced the hardcoded button rows withrenderFilters()countingstore_type/categoryoff the live catalog. That was §1 of the second audit and it is closed. (I could not confirm the deployed HTML:https://proagentstore.online/returns 403 to my fetch. The fix is inmain's history and host deploys on push, so I am reporting it as fixed in source, not verified in production.)job-application-assistantstill trips the guard,facebook-friend-confirmeris still published, the same 8 cards still have no icon,lead-outreach-tj6qrrstill has its scaffold slug.The three findings that matter
1. Two published agents hand a new subscriber an empty chat box
POST /:agentId/subscribecopiesagents.config.pipelinesinto the new instance —defaultPipelinesFor()inworkers/api/src/routes/instances.ts:71, and the comment there states the reason exactly:That is precisely the state of two published agents:
agents.configsmall-business-website-lead-finder{}933ebec5…, pipelinelead_finder— 45 leads from Launceston on 2026-08-04, verified vialist_pipeline_runslead-outreach-tj6qrr{}3c09069a…, pipelinedraft_outreach— 5 completed runs fed by thelead.createdconnectionBoth work. Both work only for the owner's own instance, because the behaviour was attached to the instance by hand and never promoted to the agent row. Anyone who subscribes from the storefront today gets a plain chat agent with base tools and no pipeline, no
leadscollection, and no way to do the thing the card promises.site-builderis the control case and does it right — its config carriespipelines, and migration0057embeds both definitions.It is worse than an oversight for the lead finder specifically:
workers/api/src/lib/pipelines/lead-finder.jsonexists in the repo, is the epic #94 capstone, and is proven end-to-end inlead-finder.test.tsagainst the real runner. Its own README says so:So the reference definition is written, tested and version-controlled, and the published catalog row it describes carries nothing.
draft_outreachis worse still — there is no reference JSON for it anywhere in the repo, so the second link of the lead chain exists only as live instance data: untested, unversioned, and lost if that instance is ever cancelled.Fix: seed both into
agents.config.pipelinesby migration, the way0057does forsite-builder, and extendseed-drift.test.tsto cover them (today it pinssite-builderonly). Exportdraft_outreachfrom instance3c09069a…toworkers/api/src/lib/pipelines/lead-outreach.jsonfirst — that is the only copy.2.
lead_findercrashes on any city big enough to matter, and the failure is invisible from the storefrontlist_errors(sourcepipeline-run), all on instance933ebec5…:Every subsequent successful run is a small one — Hobart and Launceston at
radius: 900, 83–116 places seen. The crashing step names (s3-flatten-1,s4-map-1) match the referencelead-finder.jsonshape exactly —geocode → fan_out → http_request → flatten → map → enrich → map → filter → dedupe_upsert, index 3 beingflattenand index 4map. There is nosliceanywhere in that chain, so the payload carried between steps grows with the city and hits Cloudflare's 1MiB Workflow step limit. Thesliceprimitive that caps exactly this ("the missing top N: cap a list before a per-item connector call so a long source isn't unbounded spend") already exists and is not used. (I read the reference JSON, not the live instance's copy — no read-only MCP tool returns an instance's pipeline definition. The step names make them the same shape; I did not diff them byte for byte.)This is the single agent in the catalog whose card names a general capability ("Search by city and business type") that demonstrably fails on the first city a visitor would try.
Fix: add
sliceafterflatteninlead-finder.json, bounded by a subscriber setting, and seed it per finding 1.3. The catalog's own answer to "is anyone looking at this?" is structurally unavailable
agent_analyticsreturnsfunnel: {views, trials, subscribes}. Across every agent I checked —coder(739 calls, 2 subs),coder-repo(6 subs),portal-watch,site-builder,meeting-notes—viewsandtrialsare 0 without exception, whilesubscribesis correct.trialsis dead by construction: nothing inworkers/api/srcever writesevent = 'trial_start'. The public trial route/v1/public/agents/:id/trywrites nousagerow at all.viewsis written byGET /v1/public/agents/:id(routes/public.ts:33) — but it bindsuser_id = ''into a column declareduser_id TEXT NOT NULL REFERENCES users(id)(0001_init.sql:58), inside awaitUntil(...).catch(() => {}). If D1 enforces the foreign key, every view insert fails and is swallowed.store/agents/detail.html:465tries the public route first for every visitor including the owner, so a genuine zero would mean nobody — not even the owner, mid-audit — has opened an agent page. I lean strongly toward the FK, but I could not prove it: confirming requires a direct D1 query, whichAGENTS.mdforbids and which no read-only MCP tool exposes.Either way the operational conclusion is the same and it is the important one: this audit cannot tell you whether anyone browses the store, and neither can you. Every "is anyone using it" judgement below rests on subscriptions and token usage, both of which are the owner's own traffic.
Verdicts — 15 published agents
Guard + lint were run over all 15 by replicating
blockPublishReason(lib/test-agent-guard.ts) andlintAgentClaims(lib/agent-claims-lint.ts) verbatim against each agent's live description and declared capabilities. Result: 1 guard hit, 0 lint violations.coder-repocoding/CODING_SESSION+ 7 tools + surfaceOptions + settingsSchemacoder-leadtmux-operatorsurfaces:[tmux],runtime:coding, 6terminal_*toolslocal-repo-chatruntime:coding+ 4repo_*toolsrepo-chatsurfaces:[repo]+ 3 declared toolsdoc-chatlanguage-buddysettingsSchema(migration 0041)portal-watchruntime:browser/BROWSER_TASK+browserTask.readOnly+ settingsSchemasite-buildermcp-clientmcp_list_tools+mcp_call_tool+ settingsSchemasmall-business-website-lead-finder{}lead-outreach-tj6qrr{}job-application-assistantsurfaces:[apply]/browser/JOB_APPLYcodercoding/CODING_SESSION, no tool allowlistfacebook-friend-confirmerruntime:browser/BROWSER_TASK,tools:[]KEEP 9 · FIX 4 · UNPUBLISH 2.
The nine KEEPs, briefly
coder-repois the catalog's best entry and the busiest: 6 instances, one per repo, exactly the shape its card describes, with the fullest declaration in the store (tools +surfaceOptions+ a 4-fieldsettingsSchemaincluding the merge-authority control from0091).coder-leadsits over it and is genuinely used.tmux-operatorpicked up a second subscriber since the last audit ("Heartfull (tmux)") and its category spelling was fixed in0084; itsconfigstill carries nothing butcapabilities— no identity, no welcome message — which is why it reads thinner on the card than it behaves.repo-chatandlocal-repo-chatare the read-only pair and are correctly distinct (GitHub API vs. your own checkout over the runner); both declare their tools properly andrepo-chatremains the "built the creator way" reference.doc-chatandlanguage-buddyare low-traffic but honest: they promise only what platform primitives already deliver, andlintAgentClaimsagrees.portal-watchis the strongest new entry and deserves saying so. It is the only agent in the catalog whose card states its own limits ("It can only ever look: the runtime blocks every Pay, Submit, Send, Delete and Confirm before the click reaches the page"), and the claim is backed in config —browserTask: {readOnly: true}— not just in prose. It is the model for how the rest of these should read.site-builderkeeps its place on merit at 0 subscribers: fully declarative, seeded, drift-tested. But note the consequence — with no instance, the third link of the lead chain has never run.list_connectionson the lead finder shows exactly one edge,lead.created → draft_outreach. Thesite.livewiring documented as the chain's payoff does not exist in live data because there is nothing to wire it to.The four FIXes
job-application-assistant— this is the one the guard stops. Its description contains "Runs a safe fill-only test by default", whichtestAgentMarkermatches as a whole word, soblockPublishReasonreturns a 400 for any attempt to re-publish it; it survives only because it is already published and nothing has sentvisibility:"published"since. This is the same one-line edit #66 already wants — "Does a safe fill-only dry run by default and stops before Submit" removes the internal vocabulary and clears the guard. Two further things, both new here: it has 0 calls all-time across 2 subscribers, so the flagship apply pipeline has not been exercised once since usage tracking began on 2026-07-14; and itsmodelcolumn is@cf/meta/llama-3.3-70b-instruct-fp8-fastwhile every other published agent isclaude-sonnet-4-6. The model is harmless in practice — it is inTOOL_CAPABLE_MODELS, andrunAgentAihardcodesclaude-sonnet-4-6whenever a BYOK Anthropic key exists — but it is visible on the public card and it makes the flagship look like the one agent running a small open model.small-business-website-lead-finderandlead-outreach-tj6qrr— findings 1 and 2 above. Additionallylead-outreach-tj6qrrstill carries its scaffold slug in the public URL andcategory: "general", the only agent in the catalog with either.mcp-client— works (16 calls,mcp_list_tools/mcp_call_toolsucceeding on instancedfc1cf92…), but the storefront copy is written for someone who already knows the platform: "Configure its Streamable HTTP endpoint on the private instance, store its bearer token under the MCP key slot … through ProAgentStore's consent-gated MCP connector." Three internal terms in one sentence. Nothing to fix in the capability; rewrite the card.The two UNPUBLISHes
coder→ draft. This is the six-overlapping-coding-agents problem, and the repo has already made the call in code.workers/api/src/lib/first-party-agents.tsnames itLEGACY_CODERand comments: "The legacy hardcoded Coder: declares no tool allowlist, so it keeps the drive tools."coder-reposupersedes it on every axis — 6 subscribers to its 2, a declared tool allowlist,surfaceOptions, a realsettingsSchema— andcoder-leadsupplies the multi-repo casecoderwas covering by accident. It is also the only agent in the store attributed to a different creator (proagentstore, with no avatar), so the flagship card is the one that looks least like it belongs to anyone.Drafting gates
POST /:agentId/subscribeand nothing else, so both existing instances ("Coder", "Coder Home", 739 calls between them) keep working untouched, and it is one field to reverse. What this buys is the thing the catalog is actually for: a visitor sees five coding agents instead of six, and the first one is the one you should start with.facebook-friend-confirmer→ draft. The second audit recommended this and it was not actioned, so I am re-entering it with the evidence rather than dropping it. It is a public catalog listing for an agent that drives a logged-in Facebook session to confirm friend requests and "optionally adds a few suggested friends" — against Meta's platform terms, and the onlysocialentry in the store. Its 117 calls are entirely the owner's own dogfooding, which is not a usage argument for a shop window. Drafting costs the owner nothing: the instance, its chats and its browser runs are untouched.Cosmetic, and it is still the first thing a visitor sees
store/index.htmlrendersconst icon = a.icon || '⚡'oniconBg = a.icon_bg || '#7c3aed'. 8 of 15 published agents haveicon: ""—mcp-client,tmux-operator,lead-outreach-tj6qrr,facebook-friend-confirmer,small-business-website-lead-finder,doc-chat,language-buddy,job-application-assistant— so a clear majority of the grid is the identical purple ⚡ tile. Unchanged since 2026-08-06. EightPUT /v1/agents/:id {icon}calls; I have not picked the emoji because it is the owner's catalog.One dead field, worth knowing about
agents.statusis returned in the publicGET /v1/agentspayload for every agent. It is written once —'inactive'at INSERT, in both create paths (routes/agents.ts:331,:668) — and nothing ever updates it. The only rows readingactiveare the ones a seed migration wrote that way, which is why the split falls exactly along seeded-vs-API-created and not along anything meaningful: 8 published agents currently advertisestatus: "inactive"in the store's own API response, includingjob-application-assistantandtmux-operator. Nothing instore/renders it today, so this is latent rather than broken — but it is a public field that means nothing, and the next thing to render it will render a lie.Overlaps with #67 — actionable from this same evidence
27 active instances. Nothing recommended on 2026-08-06 was actioned, and one new near-duplicate has appeared.
ProAgentStore MCP clienta9ee6079…usage_summary). SiblingMCP client(dfc1cf92…) has 4 and is the live one. Its failedmcp_list_toolsand empty content were established on 2026-08-06 above; I re-verified only that it still exists with 1 call.Codex MCP Browser Test7867ed7e…usage_summaryentirely — 0 calls all-time. Its self-describing marker content is quoted in the 2026-08-06 comment; I did not re-read it.Google Drive Doc Chat Test3d51aceb…Terminal Operator·iTerm2 Operator·kitty Operatorda39100b…·8d21ea1a…·59cc5144…bdae7a27…/d40dbdf6…/01905f59…. Created, smoke-tested once, never used since. All three agents already drafted.Creator OSb619b3da…draftstatus makes it look disposable and it is not.Coder+Coder Homecd489be0…·12ebf1f0…Heartfull+Heartfull (tmux)f8ddc272…(coder-repo) ·cda75e28…(tmux-operator)coder-repo× 6Still unresolved from 2026-08-06:
meeting-noteshassubscribers: 1and that instance is not among the owner's 27 — someone outside the operator account holds a subscription to a draftedconfig:{}agent, with 0 chats and 0 executions. I could not identify them: that needs/v1/admin/*, which is behind the Cloudflare Access edge and whichAGENTS.mdputs out of bounds. Not touched.Also worth a separate issue:
pump_test, a leftover test pipeline, is attached to the live lead-finder instance and appears in its run history (3 runs). Harmless, but it will be copied into every subscriber's instance the moment finding 1 is fixed by promoting that instance's pipelines wholesale. Promotelead_finderonly.Correction to the usage figures on this issue
usage_summary(range:"all")today: 3,347 calls,costMicros889,238,209 — but onlychargedCostMicros3,771,185 (~$3.77) is money anyone was actually charged. The ~$889 headline is notional list-price arithmetic, and$842 of it is a single Claude Code engine ($42.30 estimated" was the same notional figure before that engine's rows landed; quoting either as spend overstates it by two orders of magnitude. 11 of 15 published agents have real usage; all of it is still the owner's own.claude-opus-5[1m], 113.8M cache-read tokens, payerunknown) running on a subscription. The second audit's "fix(pipeline): the lead-finder sweeps a capital city, and says what i…
serge-ivo commentedon Aug 8, 2026
Fourth pass — 2026-08-08, evening. Read-only, nothing changed. Two of the third pass's three findings have moved, and one of them is now wrong as written.
The third pass (2026-08-07 21:06Z) is a good audit and I did not redo its table. I re-verified it
against live state and against
main@64598dd, ~21 hours later. In that window six commitslanded that touch this issue directly, and one of them inverted the meaning of
config: {}—which is the finding this pass exists for.
Evidence: MCP
list_agents(15 rows),my_agents(39),my_instances(28),usage_summary(range:"all"),agent_analytics× 15,list_pipeline_runs,list_errors,coding_repos_list; pluscurl https://proagentstore.online/andgit showon the six commits. No writes, no REST mutations.1.
config: {}stopped meaning "unconstrained" today — and it took the lead finder down with itThis is new since the third pass and it is the most consequential thing on the board.
#381 shipped this morning (
b11a740, 2026-08-08 07:41 +1000): a pipeline step is now bounded bywhat its agent declares. The gate is
declaredToolsFor(lib/pipeline-tool-policy.ts:113) and it isexplicit about the empty case:
#396(1905259, 10:33 +1000) then moved the refusal to attach time. Both are correct. Theconsequence is that
config: {}is no longer a neutral state — it is now an assertion that theagent may run zero connector tools, and
small-business-website-lead-finder's whole behaviour isone
http_requeststep.6b37070's own commit message says so, unprompted:Correction to a fact in circulation: the refusal dates from today, not from 2026-08-06. I
checked the commit dates (
b11a740c:2026-08-08 07:41:50 +1000;1905259c:10:33:44). The lastlead_finderrun is 2026-08-06 04:38 UTC and it completed (83 seen / 45 added), so no run wasactually lost — the exposure window is hours, not days. That does not soften the finding, because the
same shape is still live on three other published agents (§3).
The agent row now carries a 16-tool
capabilities.tools(verified live:http_requestplus the KB /files / collections set). That was the right call and it is not a narrowing in practice —
toolNamesFor(agent-do-tools.ts:189-193) seeds the set fromBASEbefore adding the declarednames, so the always-on base tools survive.
search_knowledge/list_knowledge/read_knowledgeare in the 16, so the Drive/WorkDrive connector gate (
64598dd, #352) still passes for it.What is still broken and was not fixed by that declaration: the agent row has
capabilitiesandnothing else. No
pipelines. Third pass finding 1 stands unchanged.2. The Sydney crash is fixed — in a file that nothing in production reads
#394 closed today (
6b37070). It is a better diagnosis than the audit's: the audit prescribedsliceafterflatten, and the commit explains why that could not have worked (flattenis the stepthat fails; no later step shrinks an earlier step's journal entry). The real fix projects the four geo
strings inside the connector's own
responseMap, so Google'saddressComponentsarrays never cross astep boundary, plus a
sliceand amax_placescap with a visible "N were left unexamined" line.Measured: the fixed definition lives at
workers/api/src/lib/pipelines/lead-finder.json. Its onlyimporter in the whole tree is a test:
The reference now has 10 steps (
geocode · fan_out · http_request · flatten · slice · map · enrich · map · filter · dedupe_upsert). Every completed production run reports 8 steps. The commit saysthe same thing in its own words — "It does not touch the live instance's own copy of the pipeline …
which demonstrably differs from the reference."
So: the storefront card still promises "Search by city and business type", and Sydney still fails in
production. The fix exists, is tested, and is unreachable from the live agent. This is the sharpest
possible argument for finding 1 — a pipeline that lives only in one instance's config is a pipeline
that cannot be fixed.
3. Three more published agents are one connector step from the same refusal
Resolved capabilities read live off
/v1/instances/my/instances:capabilities.toolslead-outreach-tj6qrrnulldoc-chatnulllanguage-buddynullNone of the three uses a connector tool today, so none is broken. Declaring tools on them now would be
pure narrowing with no benefit, and I am not recommending it. What I am recommending is that the
platform stop letting a published agent carry
config: {}— see §7.4. The funnel is no longer structurally zero. Third pass finding 3 is delivered.
#383 closed today (
0a6abf7, migration0095agent_funnel_daily).routes/analytics.ts:63-69now reads views/trials from a table whose write can succeed, and names the exact defect the third pass
hypothesised — the
usage.user_idforeign-key violation inside a swallowed catch. The hypothesis wasright; the fix landed before the comment did.
Measured now, all 15 published agents:
tmux-operatorcoder-repoportal-watchlanguage-buddySo the third pass's conclusion — "this audit cannot tell you whether anyone browses the store, and
neither can you" — no longer holds. The counters work. They are near-zero because the store is
near-unvisited, which is a different and more useful fact.
What IS still dead, and nobody has filed it:
totalExecutionsandrecentExecutions. Both readagent_executions, and the onlyINSERTinto that table in the entire API isroutes/run.ts:98—POST /v1/agents/:id/run, the legacy direct-inference route. So the creator's analytics reportstotalExecutions: 0forsmall-business-website-lead-finder(13 pipeline runs on record) and forfacebook-friend-confirmer(123 metered calls). Every one of the 15 reads 0. Worth its own ticket:either feed it from
pipeline_runs+ runtime tasks, or stop rendering a counter that measures a routenobody calls.
5. The storefront filter fix is verified in production, not just in source
The third pass could only report it fixed in
mainbecausehttps://proagentstore.online/returned403 to its fetch. It serves 200 to a browser User-Agent, and the deployed HTML carries the fix:
The second pass's §1 storefront regression is closed, in production. That was the highest-value
finding on this issue and it is done.
6.
tmux-operatoris published, and #402's target ceiling cannot reach itTwo individually-correct decisions composing into a gap, which is the shape this board keeps
producing.
tmux_*tools on the tmux Operator instead ofthe generic
terminal_*six, so it is a tmux agent by construction rather than by name. Verifiedlive: its
capabilities.toolsis exactlytmux_list_sessions … tmux_kill_session.CONNECTOR_CONSTRAINTS(
lib/surface-options.ts:191) has exactly one key,terminal, and its own comment says so:"
terminalis the first and, today, only entry."So
targets: "single"+ a subscriber-bound target — the part of #402 written specifically for "anamed operator ('Heartfull tmux') should be
targets: "single". One pane, one job. A mis-selectedtarget here is a shell command on a real machine" — can be declared on the three drafted operators
and not on the one published one. Verified live:
iterm-operatorandkitty-operatorcarrysurfaceOptions.terminal.backends;tmux-operatorcarries nosurfaceOptionsat all, andtmux_run_commandisscope: "write"arbitrary shell behind a single per-connector consent row.Fix is small — add a
tmuxentry toCONNECTOR_CONSTRAINTSwith atargetsbinding on thesession/targetargument — and it is the thing #249 should buy instead of a tmux Coder backend. Ihave written it up there.
7. Zero agents declare a
statsSchema— the Stats surface has never had a catalog entry to renderChecked all 39 agent rows:
statsSchemaappears in none of them.#423(fixed today,7852232) established that the rollup had also been crashing on every cron tickfor 29.6 hours. Both facts are true and they are independent: even with the rollup healthy,
agent_stats_dailystays empty because nothing declares a schema to roll up. So#310/#311/#312/#313— a per-agent Stats tab, a card schema, an MCP configurator and a daily rollup — are shipped andhave never rendered a single card in production.
That is a catalog problem, not an engineering one, and it has an obvious owner: the same agent that
already needs work in §1–2.
small-business-website-lead-findershould be the referencestatsSchema— "leads found per day", "by suburb", "with/without a website" — the wayrepo-chatisthe reference for declared tools and
site-builderfor declarative pipelines. One agent config, andthe feature stops being theoretical.
Verdicts — 15 published agents, 2026-08-08 evening
Usage is all-time, summed from
usage_summary(range:"all")across each agent's agent-scoped row andits instances' rows (the ledger keys both ways; reading only one undercounts). All of it is still the
owner's own traffic — 0 external creators, 0 external users.
agents.configcoder-reposurfaceOptions.coding {repos:single, drive:false, copilot:false}, a real settingsSchema. 109 chats, 25 today.coder-leadlocal-repo-chatrepo-chat(own checkout over the runner vs GitHub API).repo-chatdoc-chat{}language-buddysettingsSchema+ voice-language reference. 50 chats, 1 trial.portal-watchbrowserTask.readOnly). Picked up its first trial.site-buildertmux-operatortargets:"single"cannot be declared on it. Also:configcarries nothing but capabilities (no identity, no welcome), no icon, andstatus: "inactive"on a public payload.lead-outreach-tj6qrr{}draft_outreachruns, all real, all fed by the pump — and the definition exists only in instance3c09069a…'s config. No reference JSON anywhere in the repo. Export it before anything else. Plus the scaffold slug in the public URL andcategory:"general".small-business-website-lead-finderstatsSchemacandidate.mcp-clientdfc1cf92…showmcp_list_tools/mcp_call_toolsucceeding against FreeAgentStore's MCP endpoint, which is a nice demonstration and worth saying on the card. The card instead says "the private instance", "the MCP key slot", "consent-gated MCP connector". Rewrite.job-application-assistantmodelcolumn is@cf/meta/llama-3.3-70b-instruct-fp8-fastwhile all 14 others readclaude-sonnet-4-6, and it has 127 chats but 0 metered calls (all pre-2026-07-14). One copy edit closes the guard and #66 together.codercd489be0…("Coder") has had no message since 2026-07-08.first-party-agents.tsalready calls itLEGACY_CODER;coder-repohas 7 subs to its 2 and the fuller declaration. It is also the only card attributed to a different creator (proagentstore, no avatar).facebook-friend-confirmersocialcard in the store. Its 123 calls are the owner's own. Drafting costs nothing: the instance, its chats and its browser runs are untouched.KEEP 8 · FIX 5 · UNPUBLISH 2. No agent changed verdict class since the third pass; two acquired new
reasons (
tmux-operator,small-business-website-lead-finder).Cheapest-first, so a partial fix ships
draft_outreachfrom instance3c09069a…toworkers/api/src/lib/pipelines/lead-outreach.json. It is the only copy of a working pipeline and it is one cancelled instance away from gone. Zero risk, do it first.lead_finder(the fixed 10-step definition) anddraft_outreachonto their agent rows by migration, the way0057does forsite-builder, and extendseed-drift.test.tsto cover them — today it pinssite-builderonly. Do not promote instance933ebec5…'s pipelines wholesale: it also carriespump_test, a leftover with 3 runs, which would then be copied into every subscriber's instance.job-application-assistant— "a safe fill-only dry run" — clears the [Catalog] Unpublish smoke-test agents from the live store #65 guard and [Catalog] Fix description-vs-capability integrity + add a claims lint #66's item in the same line.tmuxentry toCONNECTOR_CONSTRAINTS(§6) so the published operator can be bound to one session.statsSchemaon the lead finder (§7) so the Stats surface has a first tenant.mcp-client,tmux-operator,lead-outreach-tj6qrr,facebook-friend-confirmer,small-business-website-lead-finder,doc-chat,language-buddy,job-application-assistant). EightPUT /v1/agents/:id {icon}calls; they are the owner's aesthetic choices, so I have not picked them.Alternatives considered and rejected
capabilities.toolsonlead-outreach-tj6qrr,doc-chatandlanguage-buddynow, for consistency. Rejected: none of them reaches a connector tool, so it is narrowing with no benefit and three more rows to keep correct. The right guard is at publish time (below), not per agent.config: {}. Tempting after §1, and I am not proposing it:doc-chatandlanguage-buddyare legitimately configuration-free, andlintAgentClaims([bug] The catalog claims lint runs on agent create but not on update — the path where descriptions actually change #362) already catches the case that actually harms a visitor — a description promising something the capabilities do not back. The narrower rule that is worth writing is "a published agent whose behaviour is a pipeline must carry that pipeline on the agent row", whichseed-drift.test.tscan assert directly.lead.createdrouted byagent_connectionsis the pump's reference wiring, and 100draft_outreachruns prove it works. Collapsing it would delete the platform's only live demonstration of agent-to-agent choreography.Corrections to figures on this issue
usage_summary(range:"all"), measured now: 3,602 calls ·costMicros955,247,356 ·chargedCostMicros7,185,088.So the honest spend number is ~$7.19, not ~$955 and not the ~$42 the second pass quoted. By payer:
byok-api414 calls / $7.18 (real money),platform96 calls / $0.005, andunknown3,092 calls /$948 — which is a Claude Code engine on a subscription (
claude-opus-5[1m], 115M cache-read tokens,67 calls, $849.78 notional) plus
claude-opus-5(12 calls, $54.73). Anyone quotingcostMicrosasspend is out by two orders of magnitude; quote
chargedCostMicros.11 of 15 published agents have real usage. Zero external users. The shop-window framing still stands.
Acceptance
The three original boxes were met on 2026-08-06 and stay met — the table above covers all 15 published
agents with a verdict and a reason, and #65/#66/#67 are filed and linked. Leave this open: #66 is
open, #67 has fresh evidence today (companion comment there), and items 1, 2 and 5 above are unfiled
work that belongs to this parent.
Verified by reading; not verified: I did not open a coding session, run a pipeline, or trigger a
browser task — every one of those spends the owner's tokens or writes production data.
serge-ivo commentedon Aug 18, 2026
Fifth pass — 2026-08-18. Read-only. Three of the fourth pass's six cheapest-first items have landed; the one it called "zero risk, do it first" has not
Ten days on. I did not redo the verdict table — I checked what moved, against production and
origin/main@6ceec4f.Done since the fourth pass
migrations/0111_seed_lead_finder_pipeline.sqlseeds the fixed 10-steplead_finderonto the agent row, and its header states the mechanism precisely: "the fixed definition landed in a file production never loads — the only importers of lead-finder.json in the whole tree are two tests, andloadPipelinereadsagent_instances.config.pipelines[key]." Confirmed live:small-business-website-lead-finderno longer hasconfig: {}.CONNECTOR_CONSTRAINTSnow has two keys —terminal(lib/surface-options.ts:214) andtmux(:235) — so §6's finding is closed and the published Operator can be bound to one session.statsSchema. It isfacebook-friend-confirmer— the agent this issue has recommended drafting three times. So the Stats surface has a first tenant and it is the one entry two audits asked to remove.Not done — and item 1 is the one that matters
Item 1 — export
draft_outreachbefore it can be lost — has not happened.workers/api/src/lib/pipelines/contains exactlylead-finder.json,site-builder.json,site-deploy.json(+ their tests and the README). There is nolead-outreach.json.And the agent row is still empty:
lead-outreach-tj6qrris one of only two published agents whoseconfigis{}(the other isdoc-chat, which is legitimately configuration-free). So the second link of the lead chain — 100+ completeddraft_outreachruns, the platform's only live demonstration of agent-to-agent choreography — still exists only as instance data on3c09069a…, untested, unversioned, and one cancelled subscription away from gone.Ten days ago this was written up as "Zero risk, do it first." It is the only item on that list that cannot be redone from the repo if it is lost.
(I could not re-read the instance's pipeline definition to confirm byte-for-byte that it is still there —
GET /v1/instances/my/instancesdoes not return instance config, and no read-only MCP tool returns a pipeline definition. What is verified is that the agent row is still{}and that no reference JSON exists in the tree.)job-application-assistant's copy still contains the whole-wordtestthatblockPublishReasonrefuses, so it remains un-republishable.One new published agent, and it belongs in this inventory
tmux-coder(agent_tmux_coder, migration0123, #515) — the catalog is 16, not 15. It was seeded published deliberately, withlintAgentClaimsand a 22-test seed guard, so it is a clean addition rather than drift. It has one subscribed instance (AIPA tmux Coder,25501ef7) whose last activity is 2026-08-12 11:44 — the day it was created. Six days idle. Worth knowing before the next pass reads it as a working agent.Recommendation for this tracking issue
The audit work here has been thorough four times over and the ask is long since satisfied. What keeps it open is a small list of unfiled follow-ups, and a tracking issue is a poor home for them — item 1 has now survived two audits by being on a list rather than on a ticket.
Suggest: file item 1 as its own one-line issue today, file the
job-application-assistantcopy edit onto #66's successor, and close this. Its verdict tables are the durable artefact and they stay readable whether it is open or shut.Verified: the pipelines directory contents,
surface-options.ts:214/235, migration0111's presence and header, the 16-row published catalog, the twoconfig: {}published agents, the singlestatsSchemaholder, and25501ef7's last-activity timestamp. Not verified: the icon count and the live contents of instance3c09069a…'s config. Not touched: nothing was published, drafted, edited or cancelled.serge-ivo commentedon Aug 18, 2026
Closing — the audit ask has been satisfied four times over, and what kept this open was a list of unfiled follow-ups, which a tracking issue is a poor home for. Item 1 had survived two audits by being an item on a list rather than a ticket.
Item 1 is now #706 — the
lead-outreachpipeline existing only as instance data on3c09069a, with no reference JSON and an empty agent row. Filed as P1 because it carries a loss risk nothing else on this list did: every other pipeline can be rebuilt from the repo, that one cannot.Remaining items, recorded here rather than lost:
job-application-assistant's copy still contains the whole-wordtestthatblockPublishReasonrefuses, so it stays un-republishable. A copy edit.Also worth carrying forward from the last pass: the published catalogue is 16, not 15 —
tmux-coder(agent_tmux_coder, migration0123, #515) was seeded published deliberately, withlintAgentClaimsand a 22-test seed guard, so it is a clean addition rather than drift. Its single instance (25501ef7) has been idle since the day it was created.The verdict tables in this issue are the durable artefact and stay readable closed.
feat(coder): an unusable checkout offers the field that fixes it, on …