Show HN: A TypeScript repo where AI agents can't break the architecture
This TypeScript repository demonstrates a system of tool-enforced rules to prevent AI agents from breaking the architecture while coding. It includes five key guardrails: dependency rule, mutation testing, test and spec protection, commit gating, and spec-driven development. The repo also serves as a template to bootstrap new projects and includes a benchmark exercise to evaluate agent performance.
Notifications You must be signed in to change notification settings
Fork 0
Star 1
BranchesTags
Open more actions menu
Folders and files
NameName
Last commit message
Last commit date
Latest commit
History
10 Commits
10 Commits
.claude
.claude
.github/workflows
.github/workflows
docs/adr
docs/adr
scripts
scripts
specs
specs
src
src
tests
tests
.dependency-cruiser.cjs
.dependency-cruiser.cjs
.gitignore
.gitignore
2026-07-13-143050-implemente-o-exerccio-de-benchmark-descrito-no-f.txt
2026-07-13-143050-implemente-o-exerccio-de-benchmark-descrito-no-f.txt
2026-07-13-144840-implemente-o-exerccio-de-benchmark-descrito-no-f.txt
2026-07-13-144840-implemente-o-exerccio-de-benchmark-descrito-no-f.txt
AGENTS.md
AGENTS.md
CLAUDE.md
CLAUDE.md
LICENSE
LICENSE
README.md
README.md
eslint.config.js
eslint.config.js
package-lock.json
package-lock.json
package.json
package.json
stryker.config.json
stryker.config.json
tsconfig.json
tsconfig.json
vitest.config.ts
vitest.config.ts
Repository files navigation
A reference TypeScript codebase engineered so AI agents produce good code in it — architecture as guardrails, not as documentation.
Most AI-assisted codebases degrade the same way: productivity jumps, and three months later there's duplicated logic in three files, tests that assert nothing, and an agent that breaks the code it wrote when asked to change it. That's not a model problem — it's a workflow problem. Prose conventions don't survive contact with agents (or with tired humans). Rules that are machines do.
This repo is a small but real invoicing API (draft → send → pay, money as integer cents, a proper state machine) built to demonstrate one thesis:
Every rule that matters must be enforced by a tool the agent cannot argue with.
The five guardrails
The dependency rule is a build failure, not a diagram. dependency-cruiser fails verify, the commit hook and CI on any illegal import. src/domain imports nothing — not even node builtins. The agent doesn't need to remember the architecture; violating it is impossible to merge.
Mutation testing catches tests that don't test. Coverage says a line ran. Stryker says the tests would notice if the line broke. CI breaks below 75% mutation score; the application layer currently scores 100%.
Tests and specs are protected from the agent. A Claude Code PreToolUse hook blocks agent edits to tests/ and specs/ unless a human explicitly grants an override. "Make the tests pass" can no longer be satisfied by deleting the tests (ADR 0004).
Commits are gated on the full verify suite. A hook runs typecheck + lint + deps + test on every git commit and feeds failures back to the agent — feedback loop, not just a wall.
Spec-driven development is a build gate, not a suggestion. One markdown spec per use case with Given/When/Then acceptance criteria; tests mirror them one it() per criterion — and npm run specs (inside verify, the commit hook and CI) fails on any use case without a spec, any orphan spec, and any criterion without its mirrored test. The golden path is npm run new -- : spec + mirrored test stub + use-case stub scaffolded with matching names, workflow printed.
Agent-native structure
AGENTS.md at the root (the open standard), under 300 lines, imperative, with exact commands — plus nested AGENTS.md files in src/domain, src/application and src/infrastructure carrying each layer's local invariants.
CLAUDE.md is one line pointing at AGENTS.md (portable across tools).
docs/adr/ records the why behind decisions, so agents stop relitigating them.
Deterministic seams everywhere: time and identity are ports (Clock, IdGenerator); new Date() and randomUUID() exist only in the composition root. Tests never sleep, never flake.
The benchmark exercise
The end of AGENTS.md contains a self-contained task (cancel-invoice) designed to verify whether any coding agent can work in this repo correctly: spec → tests → domain → use case → HTTP, verify green, nothing else touched. Point your agent at it and grade the diff. That's the whole point of this repository — it's not just an example, it's a test bench.
Start your next project from this one
This repo doubles as a template, and ships a Claude Code skill that does the transplant for you: it keeps the guardrail system (configs, hooks, CI, layer structure), removes the invoicing example, and grows your new domain spec-first inside it. It covers three project shapes, each with its own playbook in references/:
Backend API/service — this repo's own structure (backend.md)
Frontend app — React/Vite with the UI as an adapter around a pure, React-free domain; mutation testing targets domain/application, never components (frontend.md)
Monorepo — pnpm workspaces where layers become physical packages; packages/domain with an empty dependencies object is the loudest guardrail in the repo (monorepo.md)
One-time install (user-wide):
BASE=https://raw.githubusercontent.com/lucasgodt/open-agent-ready-typescript/main/.claude/skills/scaffold-agent-ready mkdir -p ~/.claude/skills/scaffold-agent-ready/references curl -sL $BASE/SKILL.md -o ~/.claude/skills/scaffold-agent-ready/SKILL.md for f in backend frontend monorepo; do curl -sL $BASE/references/$f.md -o ~/.claude/skills/scaffold-agent-ready/references/$f.md done
Then from any empty directory, in Claude Code:
Scaffold a new agent-ready [backend | frontend | monorepo] project for [your domain]
Prefer doing it by hand? The recipe is the same one the skill follows: clone, keep every config/hook/workflow file plus the layer skeleton, delete src domain contents + specs + tests of the example, and rebuild your domain following the spec-first workflow in AGENTS.md. GitHub's "Use this template" button also works for the mechanical copy.
Run it
npm install npm run verify # typecheck + lint + dependency rules + tests npm run dev # API on :3000 npm run mutation # Stryker (slower)
curl -s -X POST :3000/invoices -H 'content-type: application/json' \ -d '{"customerName":"ACME Ltda","currency":"BRL"}'
Honest limitations
The test-protection hook is Claude Code–specific; other agents need an equivalent gate. Mutation testing in CI is the tool-agnostic backstop.
JSON-file persistence is deliberately boring and not concurrent-safe across processes (ADR 0003). Swapping in a real database is one adapter + one line in the composition root — which is precisely the demonstration.
Mutation survivors that remain are error-message string mutants; the contract is the error code, asserted everywhere, not the prose.
License
MIT
About
No description or website provided.
Topics
typescript
mutation-testing
clean-architecture
ai-agents
claude-code
agents-md
spec-driven-development
Resources
Readme
License
MIT license
Uh oh!
There was an error while loading. Please reload this page.
Activity
Stars
1 star
Watchers
1 watching
Forks
0 forks
Report repository
Releases
No releases published
Packages 0
Uh oh!
There was an error while loading. Please reload this page.
Contributors
Uh oh!
There was an error while loading. Please reload this page.
Languages
TypeScript 76.9%
JavaScript 17.9%
Shell 5.2%