How I build software with AI — a spec-driven workflow plus the context-engineering pieces (skills, subagents, rules and docs) that make AI output consistent and maintainable instead of generic.
This repo is a sanitized, self-contained look at how I actually work. The examples are generic on purpose; the patterns are what matter.
I don't prompt ad hoc. I work in four reviewable phases, built on the Superpowers workflow for Claude Code:
- Brainstorm — explore the problem and options with the AI before committing to anything.
- Spec — write a short, surgical spec: problem, inputs, outputs, edge cases, acceptance, tests. See
specs/. - Implementation plan — turn the spec into a file map, a backwards-compatibility pass, and checkbox steps. See
specs/implementation-plans/. - Implement — execute the plan task-by-task, often with parallel subagents for independent work, and tests as the guardrail.
Each phase is a reviewable artifact, so the AI stays aligned with intent and the output is something I can actually trust.
See it in action: docs/CASE_STUDY.md walks through
the PR that shipped most of what's in this repo — including two real bugs the
process caught before merge, not a sanitized success story.
The biggest lever for good AI output is the context you give it, not the prompt. I keep that context in version control:
AGENTS.md— a single source of truth for project rules, indexed so the AI (and humans) can load the right doc at the right time.CLAUDE.md— the Claude Code entry point. Deliberately thin: it redirects toAGENTS.mdso the rules live in one place instead of being duplicated per tool. ASessionStarthook in.claude/primes branch and workflow context automatically.docs/— the standardsAGENTS.mdpoints to (architecture, git hooks, development setup, React guidelines)..claude/commands/— slash commands for repeatable ops;new-specscaffolds a spec + implementation-plan pair from the house templates..claude/skills/— reusable, plain-English skills for recurring tasks (commit, PR description, safe rollout, scaffold a module) with the safety rules baked in. Each skill is a folder (<name>/SKILL.mdplus colocated resources, e.g.scaffold-module/templates/), and skills carry a## Lessonschangelog of the failures they've absorbed — see below..claude/agents/— focused subagents (a test writer, a standards reviewer) that run independently and in parallel..claude/workflows/—parallel-review: a runnable, multi-agent orchestration script — three reviewers (correctness, security, this project's own standards) fan out in parallel, then every finding goes through an independent skeptic before it's reported. This is the literal code behind the "parallel subagents" claim above, not just a description of it.generate-testsreuses the same orchestration to backfill tests across many untested modules at once..claude/settings.json— a scoped permission allowlist and a session-start hook that primes context automatically..husky/— the git hooksdocs/GIT_HOOKS.mddocuments, actually wired up:pre-commitruns lint-staged,commit-msgblocks commits whose message or branch name doesn't conform,post-checkoutwarns on a bad branch name,pre-pushruns the test suite.
Two rules govern all of the above:
Keep the always-loaded context minimal. CLAUDE.md is a handful of lines and
AGENTS.md stays under a page, because every word in them is paid for in every single
session. Models already know TypeScript and React; the context documents only what they
can't know — this project's conventions, decisions, and workflow. Everything else loads on
demand: docs through the index in AGENTS.md, skills through their own trigger
descriptions (a skill costs one description line until it's actually needed).
Treat context files like code: failures get fixes. When a session goes wrong in a way
a skill or doc should have prevented, the
improve-skill skill patches the responsible
file with the smallest rule that would have prevented the failure, and logs it in that
skill's ## Lessons section — date, failure, rule. Skills converge on bulletproof instead
of the same correction being repeated across sessions, and the audit trail shows why
every rule exists (see the Lessons in
scaffold-module, grown out of the bugs in the
case study).
The whole harness is also a Claude Code plugin — the manifest in
.claude-plugin/ points at the same .claude/ folders this repo uses
itself, so there's exactly one copy of everything. Install:
/plugin marketplace add HenryCordes/ai-engineering-workflow
/plugin install ai-engineering-workflow@devartist
You get the skills (commit, pr-description, safe-rollout, scaffold-module,
improve-skill — Lessons changelogs included), the subagents (write-test,
review-standards) and the new-spec command. Repo-local wiring (the SessionStart hook,
settings.json permissions, git hooks) deliberately stays out of the plugin — that's your
project's business. Note scaffold-module assumes this repo's module layout; the rest is
project-agnostic.
And CI holds both rules to account. Stated rules drift unless something enforces them,
so the same pipeline that runs lint and tests also runs
check-context-budget — the build fails when
CLAUDE.md, AGENTS.md, or any skill description outgrows its budget, forcing a
deliberate "move this to an on-demand doc" decision instead of silent bloat — and
check-links, which fails on any broken relative link, because
a doc index or skill pointing at a moved file is a broken import. Run them locally with
pnpm check:context and pnpm check:links.
Three worked examples live in src/, each taking the same spec →
plan → implement path to a different kind of problem:
src/feature-flags/— sync, pure: a typeduseFeatureFlaghook with no I/O, tested without fake timers or mocks.src/http/— async, with a real I/O boundary: afetchWithRetrywrapper with exponential backoff, tested with an injectedfetchand fake timers instead of real waiting.src/llm-extract/— a nondeterministic boundary: typed field extraction from unstructured text (receipts) via an injected LLM client, with schema validation, bounded repair-retries on malformed model output, and — the part that matters — a golden-set eval that measures per-field accuracy against a threshold instead of assuming the LLM got it right. Unit tests run on a scripted fake; the real-API eval (llmExtract.eval.test.ts) activates only whenANTHROPIC_API_KEYis set, so CI needs no secrets.
To run them yourself you need Node 20+ and pnpm 10+ (the exact version
this repo was built against is pinned via packageManager in
package.json):
pnpm install # install dependencies
pnpm test # Vitest — 41 unit + hook tests (+1 gated eval)
pnpm typecheck # tsc --noEmit (strict)
pnpm lint # ESLint (flat config)
pnpm format:check # PrettierThe toolchain is intentionally minimal — Vitest, TypeScript, and ESLint/Prettier —
just enough to prove the examples without standing up a full Next.js app. The
same four commands run in CI on every push and pull request — see
.github/workflows/ci.yml.
I value DRY, KISS and SOLID — held with judgment, not dogma. I avoid premature abstraction (a wrong abstraction costs more than a little duplication) and apply SOLID's spirit — single responsibility, composition — over ceremony. Quality is measured by what users feel, backed by tests, not by how clever the code looks.
| Path | What it shows |
|---|---|
specs/ |
Two worked spec → implementation-plan pairs (a typed feature-flag hook; an async retry wrapper) |
src/feature-flags/ |
The sync/pure example — hook + tests, green and typed |
src/http/ |
The async/I-O-boundary example — retry wrapper + tests using fake timers |
AGENTS.md |
The single-source-of-truth context pattern |
CLAUDE.md |
The thin Claude Code entry that redirects to AGENTS.md |
docs/ |
Standards referenced by AGENTS.md |
docs/ARCHITECTURE.md |
How the repo is laid out — worked examples, docs, and agent tooling |
.claude/commands/ |
Slash commands — new-spec scaffolds a spec + plan pair |
.claude/skills/ |
Reusable task skills with safety rails, each with a ## Lessons changelog (incl. scaffold-module + templates) |
.claude/skills/improve-skill/ |
The hardening loop — session failures become permanent skill fixes |
.claude/agents/ |
Independent, parallelizable subagents (write-test, review-standards) |
.claude/ |
Permissions + session-start hook |
.husky/ |
Real git hooks matching docs/GIT_HOOKS.md — not just documentation |
scripts/ |
CI guardrails for the context itself — budget + link checks |
.claude-plugin/ |
Plugin + marketplace manifests — install this harness into your own repo |
.github/ |
CI workflow + PR template the skills/docs reference |
.editorconfig |
Editor-level formatting baseline matching docs/DEVELOPMENT.md |
.claude/workflows/parallel-review.js |
A runnable multi-agent workflow: parallel reviewers + adversarial verification |
.claude/workflows/generate-tests.js |
A parallel workflow that backfills tests for untested modules |
docs/CASE_STUDY.md |
The workflow's first real PR, including the bugs it caught before merge |
Built with Claude Code and the Superpowers workflow extension.
By Henry Cordes — devartist.nl · LinkedIn