Matt Pocock Dev Workflows
A meta-skill packaging five engineering disciplines from Matt Pocock's skills repository (130K+ stars, TypeScript expert). These skills are designed to be small, composable, and adaptable — they work with any model on any codebase.
Overview
Matt Pocock built these skills to fix common failure modes with coding agents. The five sub-patterns here address five distinct failure modes:
| # | Failure Mode | Sub-Pattern | Trigger |
|---|---|---|---|
| 1 | The agent didn't do what you wanted (misalignment) | to-spec | Synthesize conversation into a spec on the tracker |
| 2 | The agent builds a ball of mud (code entropy) | codebase-design | Design deep modules with clean interfaces |
| 3 | The agent is way too verbose (no shared language) | domain-modeling | Build a shared domain glossary (CONTEXT.md) |
| 4 | The code doesn't work (no feedback loops) | diagnosing-bugs | Disciplined 6-phase debug loop |
| 5 | You can't tell if the change is good (no review discipline) | code-review | Two-axis review: Standards + Spec |
Each sub-pattern can be used independently. The meta-skill routes you to the right one based on what you're trying to do.
When to Use
Use this meta-skill when:
- Starting a new feature — combine
to-spec(capture requirements) +domain-modeling(establish terminology) +codebase-design(plan module interfaces) - Bug or regression — use
diagnosing-bugsexclusively; don't mix patterns - Reviewing code — use
code-reviewafter changes are made - Cleaning up architecture — use
codebase-designto find deepening candidates - Improving agent communication — use
domain-modelingto build shared language
Do NOT use when:
- The codebase has no CONTEXT.md and you just need a quick fix
- You need to scaffold a project from scratch (use
app-scaffoldinginstead) - You're exploring unknown unknowns in a codebase (use
finding-unknownsinstead) - You need to optimize model routing costs (use
model-routing-cost-optimizerinstead)
Workflow Selection Guide
┌─────────────────────────────────────────────────────────────┐
│ What do you need to do? │
├─────────────────────────────────────────────────────────────┤
│ │
│ "Turn this conversation into a plan" │
│ → to-spec: synthesize spec from discussion │
│ │
│ "Design how this module should work" │
│ → codebase-design: deep modules vocabulary + deepening │
│ │
│ "Build a shared language for this project" │
│ → domain-modeling: CONTEXT.md + ADRs │
│ │
│ "Something is broken / slow / throwing errors" │
│ → diagnosing-bugs: 6-phase disciplined debug loop │
│ │
│ "Review this code / PR / branch" │
│ → code-review: two-axis (Standards + Spec) │
│ │
└─────────────────────────────────────────────────────────────┘
Sub-Pattern 1: to-spec
Synthesize the current conversation and codebase understanding into a structured spec, then publish it to the project issue tracker. No interview — just synthesis of what you've already discussed.
When to Use
- After a planning conversation where requirements are already clear
- Before starting implementation (feeds into
implementworkflow) - When you need a written record of decisions before coding begins
How to Use
- Explore the repo to understand the current state
- Sketch the test seams (highest possible seam; prefer existing ones)
- Check seams with the user
- Write spec using the template below
- Publish to issue tracker with appropriate label
Spec Template
## Problem Statement
The problem from the user's perspective.
## Solution
The solution from the user's perspective.
## User Stories
1. As an <actor>, I want a <feature>, so that <benefit>
2. ...
## Implementation Decisions
- Modules to build/modify
- Module interfaces
- Technical clarifications
- Architectural decisions
- Schema changes
- API contracts
Do NOT include specific file paths or code snippets (except prototype-
validated state machines, reducers, schemas, or type shapes).
## Testing Decisions
- What makes a good test (external behavior, not implementation)
- Which modules will be tested
- Prior art (similar tests in the codebase)
## Out of Scope
## Further Notes
Sub-Pattern 2: codebase-design
Shared vocabulary and discipline for designing deep modules: a lot of behaviour behind a small interface, placed at a clean seam, testable through that interface.
When to Use
- Designing a new module's public API
- Refactoring a shallow module into a deeper one
- Deciding where a seam should go
- Making code more testable or AI-navigable
Glossary (Use these terms exactly)
| Term | Definition | Avoid |
|---|---|---|
| Module | Anything with an interface and implementation (function, class, package, tier-spanning slice) | unit, component, service |
| Interface | Everything a caller must know: type signature, invariants, ordering, error modes, config, perf | API, signature |
| Implementation | What's inside a module | — |
| Depth | Leverage at the interface: behaviour per unit of interface a caller must learn | — |
| Seam (Feathers) | Where behaviour can be altered without editing in that place | boundary |
| Adapter | Concrete thing that satisfies an interface at a seam | — |
| Leverage | Capability per unit of interface | — |
| Locality | Change/knowledge/verification concentrated in one place | — |
Deep vs Shallow
Deep module = small interface + lots of implementation (desired).
Shallow module = large interface + little implementation (avoid).
When designing an interface, ask:
- Can I reduce the number of methods?
- Can I simplify the parameters?
- Can I hide more complexity inside?
Principles
- Depth is a property of the interface, not the implementation. Internal seams are fine; they stay private.
- The deletion test. If the module vanishes, does complexity reappear across N callers? If yes, it earns its keep.
- The interface is the test surface. Callers and tests cross the same seam.
- One adapter means a hypothetical seam. Two adapters means a real one. Don't introduce a seam unless something varies across it.
Designing for Testability
- Accept dependencies, don't create them
- Return results, don't produce side effects
- Small surface area = fewer tests needed
Deepening Process (from DEEPENING.md)
Classify dependencies:
- In-process: pure computation, no I/O — always deepenable
- Local-substitutable: has local test stand-in (PGLite, in-memory FS)
- Remote but owned (Ports & Adapters): define a port, inject adapters
- True external (Mock): third-party services, inject mock adapters
Seam discipline:
- Internal vs external seams — don't expose internal seams just because tests use them
- Replace, don't layer: old unit tests on shallow modules become waste; delete them
Design It Twice (from DESIGN-IT-TWICE.md)
When designing alternative interfaces:
- Frame the problem space (constraints, dependencies, code sketch)
- Spawn 3+ sub-agents in parallel, each with a different design constraint:
- Agent 1: Minimize interface (1-3 entry points, max leverage)
- Agent 2: Maximize flexibility
- Agent 3: Optimize for the most common caller
- Agent 4 (optional): Ports & adapters design
- Present designs sequentially, compare by depth, locality, seam placement
- Give a strong opinionated recommendation or hybrid
Sub-Pattern 3: domain-modeling
Actively build and sharpen the project's domain model. Challenge terms against the glossary, stress-test with edge-case scenarios, and update CONTEXT.md and ADRs inline.
When to Use
- Discussing codebase terminology that feels fuzzy or overloaded
- Writing or editing a CONTEXT.md glossary
- Recording or editing an ADR for a non-trivial decision
- When the agent uses 20 words where 1 will do (shared language concision)
How to Use
File Structure (Single Context)
/
├── CONTEXT.md
├── docs/
│ └── adr/
│ ├── 0001-event-sourced-orders.md
│ └── 0002-postgres-for-write-model.md
└── src/
File Structure (Multiple Contexts)
/
├── CONTEXT-MAP.md
├── src/
│ ├── ordering/
│ │ ├── CONTEXT.md
│ │ └── docs/adr/
│ └── billing/
│ ├── CONTEXT.md
│ └── docs/adr/
Active Discipline
- Challenge against the glossary — When the user uses a term that conflicts with existing language in CONTEXT.md, call it out immediately
- Sharpen fuzzy language — Propose precise canonical terms for vague/overloaded ones
- Stress-test with concrete scenarios — Invent edge-case scenarios that force precision about boundaries between concepts
- Cross-reference with code — When the user states how something works, check whether the code agrees
- Update CONTEXT.md inline — Capture resolved terms immediately, not batched at the end
- Offer ADRs sparingly — Only when ALL three are true:
- Hard to reverse
- Surprising without context
- Result of a real trade-off
CONTEXT.md Format
# {Context Name}
{One or two sentence description}
## Language
**Term**:
{One or two sentence definition}
_Avoid_: Synonymous terms
**Customer**:
A person or organization that places orders.
_Avoid_: Client, buyer, account
Rules:
- Be opinionated: pick the best term, list others under
_Avoid_ - Keep definitions tight: one or two sentences
- Only include project-specific concepts, not general programming ones
- Group under subheadings when natural clusters emerge
ADR Format
# {Short title of the decision}
{1-3 sentences: context, decision, and why.}
An ADR can be a single paragraph. Optional sections (use sparingly): Status frontmatter, Considered Options, Consequences.
Sub-Pattern 4: code-review
Two-axis review of the diff between HEAD and a fixed point the user supplies. Both axes run as parallel sub-agents so they don't pollute each other's context.
When to Use
- Reviewing a branch or PR before merge
- Reviewing work-in-progress changes
- When the user asks "review since X" (commit, tag, branch, merge-base)
- After implementation is complete, before commit
How to Use
1. Pin the fixed point
Capture: git diff <fixed-point>...HEAD (three-dot) and git log <fixed-point>..HEAD --oneline
Confirm the ref resolves and the diff is non-empty.
2. Identify the spec source
Order of precedence:
- Issue references in commit messages (#123, Closes #45)
- A path the user passed as argument
- A spec file under docs/, specs/, or .scratch/ matching the branch name
- Ask the user; if none exists, Spec sub-agent reports "no spec available"
3. Identify the standards sources
Anything in the repo that documents how code should be written (CODING_STANDARDS.md, CONTRIBUTING.md). Plus the smell baseline below.
Smell Baseline (Fowler, Refactoring ch.3)
Each smell is a labelled heuristic, never a hard violation. Documented repo standards override the baseline.
- Mysterious Name — rename; if no honest name comes, design is murky
- Duplicated Code — extract shared shape
- Feature Envy — move method onto the data it envies
- Data Clumps — bundle travelling fields into one type
- Primitive Obsession — give domain concepts their own type
- Repeated Switches — replace with polymorphism or a shared map
- Shotgun Surgery — gather scattered edits into one module
- Divergent Change — split so each module changes for one reason
- Speculative Generality — delete abstractions added for needs the spec doesn't have
- Message Chains — hide the walk behind one method on the first object
- Middle Man — cut the delegator, call the real target direct
- Refused Bequest — drop inheritance, use composition
4. Spawn both sub-agents in parallel
Standards sub-agent: full diff + standards sources + smell baseline. Report per file/hunk: (a) violations citing the standard, (b) baseline smells. Distinguish hard violations from judgement calls. Under 400 words.
Spec sub-agent: diff + spec contents. Report: (a) missing requirements, (b) scope creep, (c) wrong-looking implementations. Quote the spec line for each. Under 400 words.
5. Aggregate
Present under ## Standards and ## Spec headings verbatim. End with one-line summary: total findings per axis and the worst issue within each axis. Don't merge or rerank across axes.
Sub-Pattern 5: diagnosing-bugs
A disciplined 6-phase loop for hard bugs and performance regressions. Skip phases only when explicitly justified.
When to Use
- The user says "diagnose this" or "debug this"
- Something is broken, throwing, failing, or slow
- Performance regression needs investigation
The Six Phases
Phase 1: Build a feedback loop
THIS IS THE SKILL. Everything else is mechanical. Spend disproportionate effort here.
Ways to construct one (in roughly this order):
- Failing test at the seam that reaches the bug
- Curl/HTTP script against a running dev server
- CLI invocation with fixture input
- Headless browser script (Playwright/Puppeteer)
- Replay a captured trace (HAR, payload, event log)
- Throwaway harness (minimal subset of system)
- Property/fuzz loop (1000 random inputs)
- Bisection harness (git bisect run -able)
- Differential loop (old vs new version)
- HITL bash script (last resort)
Tighten the loop: faster, sharper signal, more deterministic. Non-deterministic bugs: aim for higher reproduction rate (50% is debuggable; 1% is not).
Completion criteria — the loop is:
- Red-capable: asserts the user's exact symptom
- Deterministic: same verdict every run
- Fast: seconds not minutes
- Agent-runnable: you can run it unattended
Phase 2: Reproduce + minimise
Run the loop. Confirm it reproduces the user's symptom. Then shrink the repro to the smallest scenario that still goes red — cut inputs, callers, config, data one at a time. Done when every remaining element is load-bearing.
Phase 3: Hypothesise
Generate 3-5 ranked falsifiable hypotheses before testing any. Each must state a prediction: "If X is the cause, then changing Y will make the bug disappear."
Show the ranked list to the user before testing (cheap checkpoint).
Phase 4: Instrument
Test predictions by changing one variable at a time. Tool preference:
- Debugger/REPL inspection
- Targeted logs at boundary points (tag each with a unique prefix like
[DEBUG-a4f2]) - Never "log everything and grep"
For performance regressions: establish a baseline measurement first, then bisect.
Phase 5: Fix + regression test
Write the regression test BEFORE the fix, but only at a correct seam. If no correct seam exists, flag the architecture issue.
- Turn minimised repro into failing test at that seam
- Watch it fail
- Apply the fix
- Watch it pass
- Re-run the Phase 1 feedback loop against the original scenario
Phase 6: Cleanup
- Original repro no longer reproduces
- Regression test passes (or absence of seam documented)
- All
[DEBUG-...]instrumentation removed - Throwaway prototypes deleted or moved
- Correct hypothesis stated in commit/PR message
Redact Secrets
Every time you show commands, outputs, or captured artifacts: redact every secret first. Write <REDACTED> in place. Build loops against env vars, so credentials stay in the environment rather than in what you show.
Pitfalls
to-spec
- Interviewing the user when they asked for synthesis — DON'T interview, just synthesise what's been discussed
- Including file paths and code snippets that will become outdated quickly
- Missing the "Out of Scope" section — it's as important as what's in scope
codebase-design
- Introducing seams without two adapters (premature abstraction)
- Using "boundary" instead of "seam" (conflicts with DDD)
- Testing past the interface — tests should survive internal refactors
- Exposing internal seams through the public interface just because tests use them
domain-modeling
- Including general programming concepts in CONTEXT.md (only project-specific terms)
- Using CONTEXT.md as a spec or scratch pad — it is a glossary and nothing else
- Creating ADRs for easily-reversible decisions (wasteful)
- Adding implementation details to CONTEXT.md
code-review
- Merging or reranking findings from the two axes — they are deliberately separate
- Missing the spec source and proceeding without it
- Forgetting the smell baseline when the repo documents no standards
diagnosing-bugs
- Jumping straight to a hypothesis before building a red-capable feedback loop
- Proceeding to hypothesise without a tight loop
- Logging everything and grepping instead of targeted instrumentation
- Fixing without a regression test at a correct seam
- Leaving tagged debug logs (
[DEBUG-...]) in the codebase
Verification
Use the verification checklist for each sub-pattern:
to-spec
- Spec has all sections: Problem, Solution, User Stories, Implementation Decisions, Testing Decisions, Out of Scope
- User stories cover all aspects of the feature
- No file paths or code snippets (except prototype-validated shapes)
- Test seams identified and checked with user
- Published to issue tracker with appropriate label
codebase-design
- Interface is small (few methods, simple params)
- Module passes the deletion test
- Dependencies classified by category
- Two adapters for every introduced seam
- Adapter/interface separation correct
domain-modeling
- CONTEXT.md updated inline with resolved terms
- Each term has a tight definition and
_Avoid_list - No general programming concepts in glossary
- ADRs created only for hard-to-reverse, surprising, trade-off decisions
code-review
- Fixed point confirmed and diff non-empty
- Spec identified (or "no spec" noted)
- Standards sources identified
- Two parallel sub-agents spawned
- Findings presented under separate headings (Standards / Spec)
- No merging of findings across axes
diagnosing-bugs
- Phase 1 loop is red-capable and has been run at least once
- Phase 2: reproduced and minimised
- Phase 3: 3-5 falsifiable hypotheses ranked before testing
- Phase 4: one variable changed at a time, tagged logs
- Phase 5: regression test before fix (at correct seam)
- Phase 6: all debug tags removed, correct hypothesis in commit message
References
See the references/ directory for supporting files:
to-spec-template.md— Full spec templatecontext-format.md— CONTEXT.md format rulesadr-format.md— ADR format rulescodebase-design-glossary.md— Expanded glossarydeepening.md— Deepening process for dependency categoriesdesign-it-twice.md— Alternative interface design techniquecode-review-smell-baseline.md— Fowler smell baselinediagnosing-bugs-phases.md— Phase detail reference