A Claude Code plugin that runs a software factory loop for coding agents:
flowchart TD
setup["/factory:setup"] -. once per repo .-> spec["/factory:spec"]
spec --> plan["/factory:plan"] --> implement["/factory:implement"]
implement --> simplify["/factory:simplify"] --> verify{"/factory:verify"}
verify -- fails --> implement
verify -- green --> pr["/factory:pr"] --> review["/factory:review"]
pr --> steward["/factory:steward"]
/factory:run <size> drives that loop end to end and stops only at the human
gates. The point is to cut the babysitting. The human agrees a spec and a plan,
then the agent works slices one at a time or in parallel worktrees, each slice
ending in a verification loop that it cannot talk its way out of, and each
landing as one PR in a stack.
The docs site at https://drew-simmons.github.io/factory has a guide on when to reach for factory and one page per skill.
The skills are thin, owned wrappers. The method inside them comes from
upstream skills by Matt Pocock, the Cursor pstack team, Addy Osmani, and
CodeRabbit, vendored verbatim under upstream/ and pinned by content hash,
plus Drew's own tools: poly-crap,
lawbook, and
verify-loop.
From the marketplace in this repo:
claude plugin marketplace add drew-simmons/factoryclaude plugin install factory@drew-simmonsFor local development, load the checkout in place:
claude --plugin-dir /path/to/factoryTools the skills call: git, jq, poly-crap, lawbook, and one of
gh, glab, or acli for the tracker. coderabbit is optional. The
SessionStart hook prints which ones are present.
| Skill | What it does | Writes |
|---|---|---|
setup |
Detects the stack and remote, asks what it cannot detect, writes factory.toml. |
factory.toml |
spec |
Aligns human and agent on numbered requirements, test seams, and open questions. No tracker. | docs/specs/<slug>/spec.md |
plan |
Slices the spec into tracer bullets with blockers, stacked branch names, and parallel waves; publishes to GitHub, GitLab, Jira, or local files after approval. | plan.md, tracker items |
implement |
One slice with TDD, or the whole frontier with implementer agents in worktrees. Ends in verify. Never commits red. | commits on <slug>/NN-<task> |
simplify |
Removes slop and needless complexity from the diff without changing behavior. Ends in verify. | edits |
verify |
Floor, typecheck, lint, format, lawbook, tests with coverage, poly-crap, in that order. Fix only what it names until exit 0. | .verify/ |
pr |
Opens one PR per slice against its parent branch with real evidence. Never draft, never merge. | a PR |
review |
Standards and spec axes in parallel read-only agents, plus CodeRabbit CLI when authenticated. Writes the handoff implement --from-review reads. |
review-NN.md, findings |
run |
Drives every stage a size needs (small, medium, large), stops only at the human gates, resumes from run.md. |
run.md |
steward |
Works the lowest unmerged PR of a stack through conflicts, review threads, and CI; restacks a slice whose parent merged. Never merges. | pushes, thread replies |
explain-diff |
Writes a rich, interactive HTML explanation of a change, diff, branch, or PR with background, intuition, code walkthrough, and quiz. Outside the loop. | .temp/<date>-explanation-<slug>.html |
Four skills say in their description that only the user may start them: setup,
plan (for publishing), pr, and run (which reaches pr). The frontmatter
stays within the Agent Skills spec, so there is no disable-model-invocation
key; the description and the first step carry the rule.
One file per repository, written by /factory:setup. Every key has a
default, so a short file is a correct file.
[factory]
spec_dir = "docs/specs"
base = "origin/main"
[tracker]
kind = "github" # github | gitlab | jira | local
[verify]
crap_threshold = 5
max_iterations = 5
exclude = ["vendor/*"]
[verify.commands]
test = "pnpm test -- --coverage"The full schema and the stack defaults are in skills/setup/references/factory-toml.md.
skills/verify/scripts/verify.sh is one command with one exit code: 0
clean, 1 a gate failed, 2 the loop itself is broken. Stage 0 rejects any
change that lowers the bar (a new suppression, a skipped or deleted test, a
lowered threshold). Stages 1 to 6 run cheapest first and stop sending model
requests on a red tree; stage 7 judges lawbook's prose standards on a
green tree when llm = true, on the lines the change touched when the
installed lawbook has --changed-lines, and a fail-level standard fails
the run.
On a planned slice branch every stage measures against the slice's
Parent from plan.md, not the whole stack. Findings land in .verify/
and in a live Hunk session when one
is open.
/factory:verify --loop and /factory:implement write
.factory/loop.local.md. While it exists, the plugin's Stop and SubagentStop
hooks rerun the script every time the turn tries to end and block on red with
the findings, up to max_iterations. Sessions without that file are never
touched.
upstream/upstream.json lists every vendored entry with its repo, ref,
resolved commit, paths, license, and a content hash. Vendored files are
never edited by hand; a wrapper's Translate section adapts them.
uv run --script scripts/sync-upstream.py checkuv run --script scripts/sync-upstream.py diff mattpocock-skills/tdduv run --script scripts/sync-upstream.py update mattpocock-skills/tdd --ref v1.4.0uv run --script scripts/sync-upstream.py verifycheck reports entries behind their ref and newer tags. diff shows the
upstream change since the pinned commit. update replaces the copy,
re-pins, and regenerates THIRD_PARTY_NOTICES.md; it refuses to run over a
hand-edited copy. verify runs in CI. A weekly workflow opens a PR when
upstream moves, with the diff in the body.
uv run pytestThe tests cover the verify script end to end, both hooks, and the
maintenance scripts. CI also runs shellcheck and the verify script itself on
this repository. .claude-plugin/plugin.json is the Claude Code manifest;
the root plugin.json is the same plugin in the agent-plugins.org schema.
claude plugin validate skills --strictclaude plugin eval . --threshold 0.8The eval case verify-runs-on-fixture needs --scaffold and Bash grants;
see the comment at the top of its scaffold.sh.
End-to-end runs of the whole loop, one headless session per skill against
a fixture repository on a throwaway GitHub remote, live in
simulations/ with a report per batch under
simulations/reports/. They spend real model budget and are not part of
CI.
The docs site is a Blume project under docs/
with pages in docs/content/:
pnpm -C docs devMerging to main cuts a release when the commits since the last v* tag
include a feat or fix. The release job in CI runs
scripts/release.py next (feat bumps minor, fix bumps patch, a ! or a
BREAKING CHANGE footer bumps major, applied as minor while the major is 0),
rewrites the version in the two plugin manifests, pyproject.toml, and
uv.lock, renames ## Unreleased in CHANGELOG.md to the new version,
commits chore(release): vX.Y.Z, tags it, and publishes a GitHub release
with that changelog section as the notes.
Add a bullet under ## Unreleased in the PR that earns it. When the section
has no bullets, the job writes one per feat and fix subject. Do not bump
the version by hand: the plugin.json version is what tells installed copies
to update, and the job refuses to run when the files and the last tag
disagree.
uv run --script scripts/release.py next --jsonMIT. Vendored files keep their own licenses; see THIRD_PARTY_NOTICES.md.