For developers who build with coding agents · zoe-coding-skills by WISHGOODS

The way a product gets built by coding agents — without drifting

A repository built by agents, across many sessions, decays in a predictable way. zoe-coding-skills is three things you install in the repo: a skill that orients an agent in one read and refuses the second system, a guard that turns a rule into a build failure, and an index the agent can ask. Files, a hook and CI — not a server, not an account, not a key.

  • Zero dependencies in the guard
  • Works with any coding agent
  • Nothing leaves your machine
  • Apache-2.0
  • Node 22+

Why a repository built by agents decays

Not because of bad instructions. Instructions are the smallest material. It happens because nobody remembers, and nothing enforces.

A second copy of a subsystem

The first was not findable, so an agent built it again. Now there are two, and both are half right.

Documentation that describes last month

The code changed, the document did not. The next session reads "done: steps 1–2" and sets off down the wrong path.

A layer "in shadow" nobody reads

A flag that runs, writes and says nothing, for weeks. Without a read date, a shadow is a leak.

A quarantined test that outlived its reason

The test was silenced to get green. The reason was forgotten. The quarantine only grows.

What it is made of

Three things are installed with you and stay yours. The fourth is a hosted service, and it is never shipped.

skills/zoe-codingInstalled with you

The skill

An eight-step session protocol: orient, find a concrete anchor, check the map before you build, one falsifiable hypothesis, the smallest safe edit, the narrowest check, docs in the same change, a commit with the reason. Plus hard rules, document genres with one owner per fact, and twelve templates. Only proven methods, each with its source named.

@zoe-coding-skills/guardInstalled with you

The guard

Eleven policy rules that run at pre-commit and in CI. Every rule was born from an incident and carries it: zoe-guard list prints each rule with its why. It reads the git index and the files it is told to read, and prints. It never executes repository content, never touches the network, and never writes unless you ask. Zero dependencies.

@zoe-coding-skills/mcpInstalled with you

The index

An MCP server over stdio that answers six questions: what to read for this task, who owns a file, which document to update, which shadows are open, what the guard says, and record one decision. It supplies material, never a conclusion — every answer says "read the owning document".

stewardHosted, never shipped

The judgment

What to promote, what to delete, when to remind and when to stay silent, the audit that trusts the implementation over the docs, the calibration that accumulates across repositories. That is what the founder does by hand today. It will be a hosted service that receives structure only — ownership map, checkpoint states, dial dates, decisions, guard reports — and never code. The guard enforces the boundary: an import from steward/ fails the build.

Install in five steps

All of it is files in your repository. The guard passes on the day of adoption; you adopt one rule at a time. An unconfigured rule reports SKIP, never a failure.

1. Install the two packages

The guard and the MCP server are ordinary npm packages, as devDependencies. They need Node 22 or later and add no dependencies to your project.

shell
npm install --save-dev @zoe-coding-skills/guard @zoe-coding-skills/mcp

Not on npm yet — see "Where this stands". In early access you install from the repository with npm link, and exactly the same commands work.

2. Initialise the guard

init writes guard.config.json, an empty quarantine, an empty dials list, and one baseline per glob — what exists in the tree today. It never overwrites an existing file. Then edit the globs to match the repository: the services directory, the models, the plan documents.

shell
npx zoe-guard init          # guard.config.json, empty quarantine and dials, baselines from today's tree
npx zoe-guard               # passes on the day of adoption; unconfigured rules report SKIP
npx zoe-guard list          # every rule, with the incident behind it

3. Add the skill and the templates

The skill and the templates live in the repository, not in an npm package: clone it once (the same checkout npm link uses in early access), copy the skill into the agent’s skills directory, and start from the CLAUDE.md template: a read order, validation commands that actually exist, hard rules, and which document changes for which change. Write arc/code-architecture.md from the list the guard prints as undocumented, and run it until it passes. Record the adoption as the first ADR.

shell
git clone https://github.com/wishgoods/zoe-coding-skills ../zoe-coding-skills
mkdir -p .claude/skills
cp -r ../zoe-coding-skills/skills/zoe-coding .claude/skills/zoe-coding
cp .claude/skills/zoe-coding/templates/CLAUDE.md ./CLAUDE.md   # then fill the read order and the validation commands

The skill is Markdown in Claude Code’s skill format. Another agent reads the same file; only the location changes.

4. Connect the hook and CI

The hook is what the developer sees; CI is what nobody can skip. In CI the guard runs first and needs no dependencies, followed by typecheck, build and tests — from the CI template that came with the skill in the previous step.

shell
npx zoe-guard install-hook  # pre-commit runs `zoe-guard --staged`
mkdir -p .github/workflows
cp .claude/skills/zoe-coding/templates/ci.yml .github/workflows/guard.yml

Enforcement never depends on the agent. An MCP tool is a convenience the agent may skip; a hook is not.

5. Connect the index to your agent

One entry in the agent’s MCP configuration. In Claude Code that is .mcp.json at the project root; in any other MCP client, the same stdio command. The server reads the repository and answers; it does not listen on a network and has no authentication, because it belongs on the developer’s machine, attached to one repository.

.mcp.json
{
  "mcpServers": {
    "zoe-coding": { "command": "npx", "args": ["zoe-coding-mcp", "--root", "."] }
  }
}

What else to connect, beyond the library

Four connections, all inside your repository and your machine. Then — nothing.

A git hook

A pre-commit that runs zoe-guard --staged. install-hook writes it; a developer who prefers husky or lefthook adds the same line there.

CI

One GitHub Actions job from the template: the guard over every tracked file, and over the change against the base branch on a pull request.

The MCP server in your agent

One stdio entry in the agent’s MCP configuration. Claude Code, Cursor, or any other MCP client — the same command.

The skill in the skills directory

One directory of Markdown and templates. In Claude Code: .claude/skills/zoe-coding. Once the plugin leaves shadow, one marketplace install replaces the copy.

No account, no API key, no server of ours, no network. Nothing leaves your machine. The only hosted piece will be the steward — and it does not exist yet.

The eleven rules

Four work with no configuration at all. The rest wait for your globs in guard.config.json, and report SKIP until then.

  • no-tracked-envA .env that is not an example is tracked.
  • no-tracked-credentialsKeys, service-account files, or an .npmrc with a token are tracked.
  • no-tracked-build-outputdist/, build/, node_modules/, coverage and similar are tracked.
  • no-tracked-email-listA tracked file is mostly email addresses.
  • ownership-map-completeA file matching a subsystem glob is not named in any docs file.
  • baseline-is-a-line-in-timeA baseline file (a model, say) is neither on the baseline nor named in the docs.
  • plan-names-its-predecessorA new plan document references no other document.
  • quarantine-only-shrinksThe quarantine exceeds its ceiling, or an entry lacks a reason or a date.
  • shadow-has-a-read-dateA dial in shadow has no owner, no document, no read-by date — or the date has passed.
  • docs-in-same-changeA staged or PR change touches a subsystem and no docs file.
  • import-boundaryA file inside a boundary imports something it must not.

The six questions the index answers

Read-only, except one create-only ADR write. Word overlap and date comparison are the ceiling; no ranking, no recommendation.

  • orient(task)The read order from CLAUDE.md, subsystems and docs that share a word with the task, open checkpoint rows, shadows past their read-by date, the latest decisions.
  • owner_of(name)Every documentation line that names a file, service or model.
  • docs_to_update(files)For each changed file: its subsystem and the documents that name it. Undocumented is explicit.
  • open_shadows()Every dial in shadow with owner, document, read-by date and overdue flag.
  • record_decision(…)One new ADR under arc/decisions/, the decision text verbatim, never overwrites.
  • guard_status(mode)The guard’s report, with the incident behind each failing rule.

What was built so this can be trusted

A tool that runs on every commit and in every agent session should be boring. These are the boundaries, in code rather than in a promise.

The guard is deliberately dumb

It reads files, runs eleven pure checks, and prints. It never executes repository content, never touches the network, and writes only on init and install-hook. Zero dependencies — nothing to attack in the supply chain.

stdio only

The MCP server has no HTTP transport and will not get one. There is no authentication because there is no network; it belongs on the developer’s machine, attached to one repository.

Paths confined to the root

The root is resolved through symlinks once at start; every path the server touches is resolved against it and refused if it lands outside — by .. or by a symlink inside the tree.

One write

record_decision creates a new ADR file with a sanitised name, create-only. No update, no delete. The one external process is git ls-files.

Bounded inputs

Task text up to 2,000 characters, decision fields up to 20,000, at most 200 files per call.

No secret in the repo, and none in a document

Four always-on rules catch the obvious forms: .env, keys, build output, email lists. The skill forbids the rest — no real identifier, name or address in a document to make an example concrete.

Where this stands — honestly

The product is built and proven on a foreign repository. What is not yet true is written here, because you would find out on day one anyway.

  • Working: the guard — eleven rules, nineteen tests on real temporary repositories, an init that gets the repository passing on the day of adoption.
  • Working: the index — six tools, seven tests including a full MCP client round trip over stdio.
  • Working: the skill, twelve templates, ten proven methods each with its source.
  • Working: an acceptance test that installs the packages into a repository that has never heard of Zoe and proves they run there with nothing from the origin.
  • Not yet: publishing to npm. Both packages are ready (publishConfig, CHANGELOG, SECURITY, npm pack checked) and the publish itself is pending.
  • Not yet: installing the plugin from a marketplace. The manifest is written and in shadow until one real install.
  • Not yet: the number. How long a fresh agent takes to reach a correct first change in a foreign repository, with the skill and without it. The protocol is written; without that number there is no public release.
  • Not yet: the steward. It is built after the number, in another repository, and receives structure only.
  • Early access: the repository is private today. Want to try it on a repository of yours? Talk to us and you get access.

Questions

Does this only work with Claude Code?

No. The files, the hook and CI do not know which agent writes the code. The MCP server works with any MCP client. The skill is Markdown in Claude Code’s skill format — another agent reads the same file from a different place.

Does any of my code leave my machine?

No. Nothing touches the network: the guard reads and prints, the MCP server talks over stdio to the agent on your machine. When the steward arrives, it will receive structure only — names, states, dates — and never source, a diff or file contents. The exact list is a document in the repository.

Will it break my build on day one?

No. init generates a baseline from what exists in the tree today, and an unconfigured rule reports SKIP. The guard only starts to bite when you edit the globs — one rule at a time.

Can I write my own rules?

Rules are configured, not written: each takes your globs and lists in guard.config.json. A new rule enters only with the incident behind it — a rule without an incident is an opinion. If you hit something no rule covers, that is exactly what we want to hear.

Is it limited to TypeScript?

The guard works on file globs and Markdown documents — the language does not matter to it. The two packages themselves need Node 22 to run, and the CI template assumes npm; swap that step for your tooling.

What does it cost?

The packages and the skill are Apache-2.0: installed with you, yours. The steward will be the paid part, and its price is not set — it is built after there is a number.

What does this have to do with Zoe?

The methodology was extracted from the repository where Zoe is built: a guard with ten rules, an entry document with a read order, fifty-four architecture documents with one owner per fact, a quarantine that only shrinks, shadows with read dates. It worked, and was uncopyable only because it was tangled with the product. Now it is a separate product, and the acceptance test checks that nothing shipped names the origin.

Why give the tools away?

Because what is installed with the developer is readable and copyable anyway. What cannot be copied is the judgment that accumulates across repositories — and that stays hosted. The protection is being first with what accumulates, not a lock.

Want to try it on a repository of yours?

The repository is private until the publish. Tell us about the project — which agent, how many sessions a week, what has already decayed — and you get access.