DEV Community

Tomas Grasl
Tomas Grasl

Posted on

Same skeleton, different last gate: reading Anthropic's commerce-agents with my own agent open in the other window

Anthropic shipped commerce-agents: a reference shopping agent and merchant agent, three runtime paths, a Claude Code plugin.

I do not build e-shops. I have an agent over Jira, GitLab, Sentry, mail and around 120 repositories. It writes analyses into Jira, reviews merge requests, checks mailer templates, audits worklogs. Code is the smaller part of the job.

I read their repo for a full day and kept thinking: I have this too. Just as a sentence in a markdown file.

The skeleton is the same. What is not the same is who stands at the end of the chain, and that one question decides how much of your agent is prose and how much of it is code.

Four layers, both sides

Strip the domain away and both repos are the same four layers:

  • Policy: who the agent is, what it must never do.
  • Capabilities: what it can call.
  • Procedures: how repeated work gets done.
  • Knowledge and state: what it knows about the domain, and where the work currently stands.

In my repo that maps to CLAUDE.md (8 hard rules), a folder of commands, a few local skills plus plugins from an internal marketplace, and docs/ plus tasks/. There is not a single line of production code in it. Production code lives in the 120 repos. This one is the cockpit.

In theirs it maps to the agent prompt, tool definitions, flows and the vertical knowledge packs. Retail, travel, telecom, ticketing.

Different domain, same shape. That part was easy to accept.

The difference: who is the last gate

At my keyboard, I am the last gate. Before the agent writes anything into Jira or posts a review comment, it shows me the draft and waits. Before anything gets deployed, it runs into the fact that I am the one who clicks.

Their agent talks to a customer who has never heard of Claude Code. Nobody sits in between.

That is the whole difference, and everything else follows from it. Every rule I keep as a sentence in CLAUDE.md, they have as code:

Provenance gate. The agent can only write against an ID it actually read in this session. Not one it remembers from an earlier run, and definitely not one that appeared inside some text it was given. Product descriptions, reviews, customer mail: all of that is input, and input can contain instructions that look exactly like yours.

Staged change. The model never applies anything. It proposes, a human commits. The interesting part is that this is not a permission check somewhere in the flow, it is the shape of the API: there is no code path where the model's output goes straight through.

Fencing untrusted text. Every piece of foreign content gets wrapped so it cannot be read as instruction. Boring, mechanical, and the thing everyone skips because "the model is smart enough".

Tests that run against prompt bytes, not against the model. This is the one that took me longest to appreciate. They are not testing whether the model behaves correctly. They are testing that the assembled prompt does not contain what it should not contain. Deterministic, no model in the loop, runs in CI in milliseconds.

One line from their docs is the most useful thing I read in a month: a rule in the prompt is one injection or one bad sample away from being skipped.

I have that verified from the other side.

Three weeks of prose quietly leaking

Because a human sits at my keyboard, prose felt like enough. For three weeks my advisory rules leaked, in small ways I only saw when I went looking:

  • The rule says "when I say go, it is go". The agent asked a second time anyway, after I had already approved a draft. That is not caution, that is a stall.
  • The rule says every status transition gets a worklog and every note gets a ticket link. Some notes went in without links.
  • The rule says short messages. Long status walls kept coming.

None of these is dramatic on its own. Together they are the same failure mode the Anthropic docs describe, just without an attacker: a sentence in a prompt is a suggestion the model is free to deprioritize when the context gets long.

So I ported two things the same day.

A hook instead of a sentence. Writing to Jira now goes through a hook that only lets the call through if the issue key was read in this session, and always via a dialog I click. Same rule as before, except now it is not a rule, it is the only available path.

Roughly, in pseudo-code:

// simplified: the real one lives in a Claude Code hook
export function beforeJiraWrite(call: ToolCall, session: SessionLog) {
  const key = call.input.issueKey;

  if (!session.readIssueKeys.has(key)) {
    return deny(`${key} was not read in this session. Fetch it first.`);
  }

  return askUser(`Write to ${key}?`, call); // no silent path exists
}
Enter fullscreen mode Exit fullscreen mode

A check script for my own text. Commands validated against the README, the team roster against the people files, regexes for secrets, in-progress tasks without a ticket link. First run: 26 findings. I had spent three weeks writing rules about verification and had never once verified my own repo.

Where the two designs diverge, and why

The differences are not about anyone being smarter. They fall out of a single constraint: their agent talks to a stranger, mine talks to me.

commerce-agents my cockpit
Gates hooks and CI tests confirmation before every write
Learning evals one dated line with a ticket number per failure
Verification evals written by the same agent that wrote the flow e2e verifier gets only acceptance criteria and a URL, never the diff
Subagents avoided, latency matters in a chat used for heavy reads, waiting is fine, context bloat is not

Their "skills over subagents" advice is correct for a customer chat where every second is visible. In a cockpit I do not care if a check takes 40 seconds. I care that a worklog dump is 30k tokens and has no business being in the main session.

The learning mechanism is the one I am keeping as it is. Every failure ends up as one line with a date and a ticket number in docs/conventions.md. Two real ones, so this is not abstract:

  • A deploy tag shaped like a number with a dot is a valid YAML float. The ConfigMap rejected it and production went down. That is now a documented trap with a fix pattern that every other repo points at.
  • A monthly worklog check reported 45 hours missing. Reality was 19. The cause: the MCP endpoint returns at most 20 worklogs per issue and does not paginate. The lesson line now says where totals may come from and where they may not.

The repo learns, the model does not. That is the entire mechanism, and it costs one line per screw-up.

The part worth taking

The interesting question about agents is not whether the model can write the code. It can, and that debate is boring now.

The interesting question is where the gates stand and who is last in the chain. Anthropic had to answer it in code because nobody sits between their agent and a stranger. I assumed prose was enough because I sit right there. Prose is enough right up to the moment you notice it is not, and you usually notice from a diff you did not want.

Repo: github.com/anthropics/commerce-agents. It says "reference implementation, not maintained, no contributions" right at the top. Honest. Take the mechanisms, not the code.

Top comments (1)

Collapse
 
reidmarlow profile image
Reid Marlow

The subagent isolation for heavy reads is the cleanest pattern here. In multi-repo cockpit workflows, letting a tool call dump raw log streams or ticket histories into the root session ruins attention within three turns. The subtle catch with subagents is the return payload. If the child session hands back an open-ended narrative summary instead of a bounded schema or diff, the parent context still bloats right back up.