Metis
Write code that favors plain data, pure logic, clear call sites, and early architectural thinking. These are strong defaults, not rigid laws: follow the surrounding codebase, framework constraints, and language norms when they clearly matter more.
Apply sections by phase instead of holding everything at once:
- Designing or starting a task: Design principles, LLM agent process
- Implementing: Working rules, Implementation rules, plus the SOLID checklist for non-trivial modules
- Writing tests: Testing checklist
- Reviewing a diff or PR: Code review mode
- Before claiming done, committing, or pushing: Final verification checklist
Design principles
- Start from the call site, by wishful thinking: pretend the perfect helpers already exist, name them the way you would want to call them, and get the top-level usage reading cleanly. If the calling code reads awkwardly, the abstractions are wrong — and you find out before building anything.
- Prefer plain data plus focused functions, modules, or systems over behavior-heavy objects. Draw boundaries around what systems do, not what entities are.
- Choose the simplest state model that matches reality: discriminated unions for mutually exclusive states, composable data for orthogonal features, and a plain flat record when neither pressure exists — do not over-architect the simple case. Core domain state gets a named, typed shape — a dataclass, struct, or union — while raw dicts and strings stay at the boundary, not in the core.
- Isolate mutation and I/O near the edges. Orchestration decides what happens; inner helpers do narrow, understandable work.
- Push ifs up, fors down. Keep high-level control flow in parents and leaf functions low-branch and easy to test.
- Parse, don't validate: at each trust boundary — parsing, persistence, external APIs — convert untrusted data once into a typed shape that cannot represent the invalid states, so downstream code never re-checks it. Past the boundary, assert internal invariants whose failure means a programming error: state transitions, function contracts, positive and negative space.
- Prefer explicit, behavior-focused tests without indirection that hides intent.
- Sanity-check the likely bottleneck first — network, disk, memory, then CPU. Prefer architecture changes over late micro-optimizations.
- Design for the hardest real requirement first, then simplify downward. Do not architect for the easy case and try to scale it up later.
- When elements of a batch can invalidate each other — duplicates, conflicts, cross-record constraints — classify the whole batch before applying any element, even when applying incrementally looks cleaner.
- Define errors out of existence: when a contract choice can make a failure case impossible — an operation that is naturally idempotent, a range that clamps, a delete that succeeds when the target is already gone — prefer it over raising and forcing every caller to handle the case.
- A side effect that crosses a boundary — a send, a charge, a write — needs a stable identity (idempotency key, dedupe token) that its owner atomically deduplicates, so retries and replays are safe.
LLM agent process
- Define expected behavior before locking in the implementation. When appropriate, write a local behavior check first — an integration test, macro behavior test, contract, acceptance check, or top-level usage sketch — and let the implementation conform to it. Do not treat tests as post hoc justification. Do not force strict TDD while the design is still moving, but prefer behavior-first when it reduces ambiguity.
- Trace invariants before adding defensive checks: if a parser, type, or earlier boundary already guarantees the value, another check is a bug of its own. Add one only where data crosses a trust boundary, the invariant can drift, or the contract should be explicit.
- Distinguish essential from accidental complexity. Existing workarounds, hacks, and tech debt in the codebase are not patterns to preserve unless they encode a real constraint — check what a workaround is for before replicating it in new code.
- Detect thrash and re-derive. If you have fixed the same bug more than twice in different ways, stop iterating on patches: restate the intended behavior, re-read the plan or spec, and derive the fix from that understanding instead.
- Reuse before you invent. Before writing a new helper, type, or constant, search the codebase for an existing one that already does the job; call or extend it instead of creating a near-duplicate.
Implementation rules (when implementing or fixing)
- For every requirement, write the failing behavior check first when a test harness exists; watch it fail, fix, watch it pass. Commit the check with the fix — a fix without a guarding test is half done. A small set of behavior-pinning tests beats a large redundant suite; assertion count is not a merit signal.
- Fix causes, not sites: when two symptoms share a root, restructure the root; when a defect class exists once, look for its siblings before finishing — the same stale check or missing boundary usually appears more than once.
- Optimize for the next change: after the fix works, ask what the next feature in this area costs; if your structure makes it expensive (touching many branches or classes), restructure to data plus one system now, while context is loaded.
- Long task lists do not suspend quality: the last requirement gets the same test, assertion, and naming discipline as the first. Do not drop the quality pass because the functional list is long.
- Leave the campsite cleaner: delete dead code and scaffolding you find mid-task if it is inside the code you already changed, and never commit generated artifacts (bytecode, build output) with your change.
Working rules
- Prefer pure functions; introduce mutation when it clearly improves correctness, interoperability, or performance.
- Prefer data transformations over deep object hierarchies.
- Prefer small, explicit abstractions that read well at the call site, and code that is easy to verify by reading.
- Prefer deep modules: a simple interface over substantial functionality. If a helper's interface is nearly as complex as what it hides, inline it or deepen it.
- Keep invariants close to the operation that depends on them; do not validate early and rely on it much later if the data can drift.
- Hide awkward external APIs behind an adapter so the rest of the code speaks the interface you wish existed.
- Prefer boundary validation over trusting implicit assumptions.
- Prefer self-explaining code with clear, not bloated, names. Comments explain why — a non-obvious invariant, tradeoff, or reason for an unusual approach — never what the code already says. Default to no comment; when one is needed, keep it to one line unless it documents genuinely complex behavior.
- Remove AI-slop comments and style inconsistent with the surrounding file.
- Adapt to the existing team style instead of forcing this skill mechanically into every file.
SOLID checklist
For non-trivial design, implementation, refactoring, or review, run SOLID as a practical checklist; skip or adapt items when the framework, language, or repo makes them inappropriate.
- S: one clear reason to change; split orchestration, parsing, persistence, and domain rules when tangled.
- O: add actually-needed or clearly imminent behavior through a focused function, variant, adapter, or module rather than fragile edits across many branches; never pre-build extension points for imaginary futures.
- L: every implementation or variant honors the advertised contract without special-case surprises.
- I: interfaces narrow enough that callers depend only on operations they actually use.
- D: high-level policy depends on stable abstractions, plain data, or ports — not low-level I/O clients and framework details.
SOLID is not an excuse for class hierarchies, factories, or ceremony. Prefer the simplest structure that preserves the intent.
Pattern cues
Full do/don't code for each cue lives in references/examples.md; read it when the task is complex or ambiguous.
- Call-site-first: write
register_user() the way you wish it read, then implement parse_signup_form(), ensure_email_available(), and save_user() to match — never shape the caller around helper internals.
- Plain data plus systems:
Trade as a dataclass with validate_trade() / price_trade() / execute_trade(), not a Trade -> OptionTrade -> CoveredCallTrade hierarchy where one feature touches many classes.
- Unions for exclusive states:
PaymentMethod = CardPayment | CashPayment | BankTransfer, not inheritance plus isinstance chains.
- Ifs up, fors down: the parent partitions and decides; leaves loop over homogeneous work.
- Boundary parsing, internal invariants: parse untrusted data into a typed shape at the edge; past it, assert positive and negative space (
amount > 0, flags & RESERVED_MASK == 0).
- Explicit tests: one behavior visible per test; loops and branching in a test hide mistakes in the harness instead of the implementation.
Two contrasts worth keeping in front of you. Ifs up, fors down — good:
def process_items(items):
credits = [i for i in items if i.kind == "credit"]
debits = [i for i in items if i.kind == "debit"]
if credits:
apply_credits(credits)
if debits:
apply_debits(debits)
Bad: one loop where every iteration re-decides if item.kind == "credit": ... elif item.kind == "debit": ..., so no leaf is testable alone.
Explicit tests — good:
def test_parse_signup_form_rejects_missing_email():
result = parse_signup_form({"password": "secret"})
assert result == {"error": "email_required"}
Bad:
for case in cases:
result = parse_signup_form(case.input)
if case.want_error and result.ok:
raise AssertionError("expected error")
Testing checklist
Tests are code: minimize test logic to minimize test bugs.
- Spend test effort on parsers, state machines, business rules, transformations, integration seams, and failure modes — not trivial getters or one-line passthroughs.
- Decide what correct behavior looks like before implementing. When practical, run a red-green loop: watch a check fail, make it pass, rerun to confirm.
- Prefer integration, macro-behavior, contract, or acceptance tests over unit tests that mirror implementation details.
- Adjust tests as understanding improves, but never move the goalposts to make a broken implementation look correct; if expected behavior changes, state why.
- Because you are an LLM, do not optimize for a narrow harness while missing the real contract. Tests expose intended behavior; they are not a reward function to game.
- Use table-driven or parameterized tests only when they genuinely improve coverage or maintainability.
- Keep failing output obvious: a reader should see what behavior broke without reconstructing test control flow.
- Treat LLM-authored tests as temporary scaffolding. Before committing, keep only tests that guard stable behavior, prevent a real regression, or fit the repo's test style; delete the rest.
Code review mode
Use this when reviewing a diff, PR, or another agent's work. For a small diff, combine the lenses below into one careful pass; when the diff is large or complex, make several passes, each asking one lens's question — do not check every rule in one read. Load references/review-examples.md first (compact review-time contrasts for replay safety, comment discipline, and cleanup); load other references only when a lens needs more depth.
Lens passes, in order:
- Correctness and contracts — does the change do what it claims; do all variants honor the advertised contract (L); is untrusted data parsed where it crosses a trust boundary; are internal invariants asserted; are failure paths handled. Distinguish validation of untrusted data at a trust boundary from assertions of internal invariants whose failure means a programming error: missing internal-invariant protection on state transitions and cross-record contracts is report-worthy substance, while validation that duplicates what a parser, type, or earlier boundary already guarantees is noise.
- Data and state — plain data vs behavior-heavy objects; unions for mutually exclusive states; mutation and I/O isolated at the edges.
- Control flow and API shape — call sites read cleanly; ifs up, fors down; S/O/I/D; no speculative abstractions. For every surface defect you find here, prescribe the STRUCTURAL remedy, not the cosmetic one: a bloated signature wants a config object or a split of responsibilities, not keyword-only markers; a method doing parsing+shaping+transport+error policy wants those responsibilities separated (pure builders, an I/O port the caller can fake, policy left with the caller); a hard-wired dependency wants a seam because forty callers must test against it. Name the new shape concretely.
- Tests and slop — the Testing checklist, plus: comments that narrate code or restate the obvious, multi-line comments that should be one line, duplicated defensive checks, dead scaffolding, casts that dodge type errors, doc spam.
Findings:
- Verify before reporting. Trace the invariant upstream and downstream first; do not flag "missing validation" that a parser, type, or earlier boundary already guarantees.
- Report each finding as
file:line, severity (blocking / should-fix / nit), and one sentence stating the problem and the fix. No essays.
- Tag each finding with the lens or rule that produced it, e.g.
[lens 2: data and state] or [rule: trace invariants]. Producing the tag forces a systematic sweep of every lens; drop tags only when the surrounding tooling requires a fixed format.
- Quality findings from lenses 2–4 are not padding. Report state-modeling, hierarchy, control-flow, test-logic, and comment defects at should-fix or nit severity even when blocking correctness findings dominate the review. A lens may legitimately produce no findings; do not manufacture one to fill a category.
Sub-agent fan-out, only when both hold: a sub-agent or task tool exists in your environment, and the diff is large (roughly more than 400 changed lines or 8 files):
- Spawn at most one agent per lens, max 4. Give each only the diff, its lens's checklist above, and the matching reference file from the list at the end of this skill — not the whole skill.
- Each agent returns findings in the format above.
- Dedupe overlapping findings, then verify each against the actual code before reporting; isolated reviewers produce false positives.
- Never fan out for small diffs. Sequential lens passes are cheaper and more accurate there.
Final verification checklist
Before claiming done, committing, or pushing:
- Re-read the user request and confirm the implementation matches the intended behavior.
- Run the relevant checks, tests, build, or validation gate. If no useful check exists, say so explicitly.
- Read the command output before claiming success; a started command is not a passed command.
- Review the diff for AI slop: narrating comments, duplicated null checks, abnormal defensive code, speculative abstractions, broad rewrites, casts that dodge type errors, test or doc spam.
- Keep only tests and docs that earn their place; remove scaffolding that only helped you think.
Long-running sessions
For substantial multi-step work, use at most two local coordination files:
- When continuing a task, check for
plan.md and implementation-journal.md; read plan.md first.
- If no plan exists and the task is substantial, create
plan.md with the macro plan, intended behavior, important boundaries, validation gates, and testing approach.
- After the user accepts
plan.md, do not edit it without permission.
- Record checkpoints, verification results, surprises, and deviations (with reasons) in
implementation-journal.md.
- At the end of a completed task, briefly ask whether to delete either note or archive anything useful.
- Do not commit or push these notes; prefer
.git/info/exclude over the repo's .gitignore.
When to relax the defaults
Relax when the codebase has a strong local convention that would be expensive to fight, the framework prefers a different structure, an object-oriented interface is the natural integration boundary, mutation is the clearest correct option, or generated code, DSLs, or third-party APIs impose a different shape. Preserve the spirit: clear responsibilities, understandable state transitions, readable tests, intentional API shape.
Read these references when needed
- For plain-data architecture, unions, and system boundaries (review lens 2):
references/architecture.md
- For call-site-first API design (review lens 3):
references/api-design.md
- For testing style and tradeoffs (review lens 4):
references/testing.md
- For boundary parsing, internal invariants, and performance framing (review lens 1):
references/performance-and-safety.md
- For optional concrete do/don't examples when the task is complex or ambiguous:
references/examples.md
- For compact review-time contrasts when reviewing a diff or PR:
references/review-examples.md
1---2name: metis3description: Use when an LLM is doing non-trivial coding work, including implementing features, fixing bugs, refactoring, designing APIs or module boundaries, writing tests, reviewing code, or preparing to commit. Guides the model toward plain data, top-down API design, simple control flow, SOLID without ceremony, boundary parsing and internal invariants, behavior-first testing, final verification, anti-slop cleanup, and a tiered lens-based code review. Not needed for trivial one-line edits, pure prose, or rote mechanical changes.4---56# Metis78Write code that favors plain data, pure logic, clear call sites, and early architectural thinking. These are strong defaults, not rigid laws: follow the surrounding codebase, framework constraints, and language norms when they clearly matter more.910Apply sections by phase instead of holding everything at once:1112- Designing or starting a task: Design principles, LLM agent process13- Implementing: Working rules, Implementation rules, plus the SOLID checklist for non-trivial modules14- Writing tests: Testing checklist15- Reviewing a diff or PR: Code review mode16- Before claiming done, committing, or pushing: Final verification checklist1718## Design principles19201. Start from the call site, by wishful thinking: pretend the perfect helpers already exist, name them the way you would want to call them, and get the top-level usage reading cleanly. If the calling code reads awkwardly, the abstractions are wrong — and you find out before building anything.212. Prefer plain data plus focused functions, modules, or systems over behavior-heavy objects. Draw boundaries around what systems do, not what entities are.223. Choose the simplest state model that matches reality: discriminated unions for mutually exclusive states, composable data for orthogonal features, and a plain flat record when neither pressure exists — do not over-architect the simple case. Core domain state gets a named, typed shape — a dataclass, struct, or union — while raw dicts and strings stay at the boundary, not in the core.234. Isolate mutation and I/O near the edges. Orchestration decides what happens; inner helpers do narrow, understandable work.245. Push ifs up, fors down. Keep high-level control flow in parents and leaf functions low-branch and easy to test.256. Parse, don't validate: at each trust boundary — parsing, persistence, external APIs — convert untrusted data once into a typed shape that cannot represent the invalid states, so downstream code never re-checks it. Past the boundary, assert internal invariants whose failure means a programming error: state transitions, function contracts, positive and negative space.267. Prefer explicit, behavior-focused tests without indirection that hides intent.278. Sanity-check the likely bottleneck first — network, disk, memory, then CPU. Prefer architecture changes over late micro-optimizations.289. Design for the hardest real requirement first, then simplify downward. Do not architect for the easy case and try to scale it up later.2910. When elements of a batch can invalidate each other — duplicates, conflicts, cross-record constraints — classify the whole batch before applying any element, even when applying incrementally looks cleaner.3011. Define errors out of existence: when a contract choice can make a failure case impossible — an operation that is naturally idempotent, a range that clamps, a delete that succeeds when the target is already gone — prefer it over raising and forcing every caller to handle the case.3112. A side effect that crosses a boundary — a send, a charge, a write — needs a stable identity (idempotency key, dedupe token) that its owner atomically deduplicates, so retries and replays are safe.3233## LLM agent process34351. Define expected behavior before locking in the implementation. When appropriate, write a local behavior check first — an integration test, macro behavior test, contract, acceptance check, or top-level usage sketch — and let the implementation conform to it. Do not treat tests as post hoc justification. Do not force strict TDD while the design is still moving, but prefer behavior-first when it reduces ambiguity.362. Trace invariants before adding defensive checks: if a parser, type, or earlier boundary already guarantees the value, another check is a bug of its own. Add one only where data crosses a trust boundary, the invariant can drift, or the contract should be explicit.373. Distinguish essential from accidental complexity. Existing workarounds, hacks, and tech debt in the codebase are not patterns to preserve unless they encode a real constraint — check what a workaround is for before replicating it in new code.384. Detect thrash and re-derive. If you have fixed the same bug more than twice in different ways, stop iterating on patches: restate the intended behavior, re-read the plan or spec, and derive the fix from that understanding instead.395. Reuse before you invent. Before writing a new helper, type, or constant, search the codebase for an existing one that already does the job; call or extend it instead of creating a near-duplicate.4041## Implementation rules (when implementing or fixing)42431. For every requirement, write the failing behavior check first when a test harness exists; watch it fail, fix, watch it pass. Commit the check with the fix — a fix without a guarding test is half done. A small set of behavior-pinning tests beats a large redundant suite; assertion count is not a merit signal.442. Fix causes, not sites: when two symptoms share a root, restructure the root; when a defect class exists once, look for its siblings before finishing — the same stale check or missing boundary usually appears more than once.453. Optimize for the next change: after the fix works, ask what the next feature in this area costs; if your structure makes it expensive (touching many branches or classes), restructure to data plus one system now, while context is loaded.464. Long task lists do not suspend quality: the last requirement gets the same test, assertion, and naming discipline as the first. Do not drop the quality pass because the functional list is long.475. Leave the campsite cleaner: delete dead code and scaffolding you find mid-task if it is inside the code you already changed, and never commit generated artifacts (bytecode, build output) with your change.4849## Working rules5051- Prefer pure functions; introduce mutation when it clearly improves correctness, interoperability, or performance.52- Prefer data transformations over deep object hierarchies.53- Prefer small, explicit abstractions that read well at the call site, and code that is easy to verify by reading.54- Prefer deep modules: a simple interface over substantial functionality. If a helper's interface is nearly as complex as what it hides, inline it or deepen it.55- Keep invariants close to the operation that depends on them; do not validate early and rely on it much later if the data can drift.56- Hide awkward external APIs behind an adapter so the rest of the code speaks the interface you wish existed.57- Prefer boundary validation over trusting implicit assumptions.58- Prefer self-explaining code with clear, not bloated, names. Comments explain why — a non-obvious invariant, tradeoff, or reason for an unusual approach — never what the code already says. Default to no comment; when one is needed, keep it to one line unless it documents genuinely complex behavior.59- Remove AI-slop comments and style inconsistent with the surrounding file.60- Adapt to the existing team style instead of forcing this skill mechanically into every file.6162## SOLID checklist6364For non-trivial design, implementation, refactoring, or review, run SOLID as a practical checklist; skip or adapt items when the framework, language, or repo makes them inappropriate.6566- S: one clear reason to change; split orchestration, parsing, persistence, and domain rules when tangled.67- O: add actually-needed or clearly imminent behavior through a focused function, variant, adapter, or module rather than fragile edits across many branches; never pre-build extension points for imaginary futures.68- L: every implementation or variant honors the advertised contract without special-case surprises.69- I: interfaces narrow enough that callers depend only on operations they actually use.70- D: high-level policy depends on stable abstractions, plain data, or ports — not low-level I/O clients and framework details.7172SOLID is not an excuse for class hierarchies, factories, or ceremony. Prefer the simplest structure that preserves the intent.7374## Pattern cues7576Full do/don't code for each cue lives in `references/examples.md`; read it when the task is complex or ambiguous.7778- Call-site-first: write `register_user()` the way you wish it read, then implement `parse_signup_form()`, `ensure_email_available()`, and `save_user()` to match — never shape the caller around helper internals.79- Plain data plus systems: `Trade` as a dataclass with `validate_trade()` / `price_trade()` / `execute_trade()`, not a `Trade -> OptionTrade -> CoveredCallTrade` hierarchy where one feature touches many classes.80- Unions for exclusive states: `PaymentMethod = CardPayment | CashPayment | BankTransfer`, not inheritance plus isinstance chains.81- Ifs up, fors down: the parent partitions and decides; leaves loop over homogeneous work.82- Boundary parsing, internal invariants: parse untrusted data into a typed shape at the edge; past it, assert positive and negative space (`amount > 0`, `flags & RESERVED_MASK == 0`).83- Explicit tests: one behavior visible per test; loops and branching in a test hide mistakes in the harness instead of the implementation.8485Two contrasts worth keeping in front of you. Ifs up, fors down — good:8687```python88def process_items(items):89 credits = [i for i in items if i.kind == "credit"]90 debits = [i for i in items if i.kind == "debit"]91 if credits:92 apply_credits(credits)93 if debits:94 apply_debits(debits)95```9697Bad: one loop where every iteration re-decides `if item.kind == "credit": ... elif item.kind == "debit": ...`, so no leaf is testable alone.9899Explicit tests — good:100101```python102def test_parse_signup_form_rejects_missing_email():103 result = parse_signup_form({"password": "secret"})104 assert result == {"error": "email_required"}105```106107Bad:108109```python110for case in cases:111 result = parse_signup_form(case.input)112 if case.want_error and result.ok:113 raise AssertionError("expected error")114```115116## Testing checklist117118Tests are code: minimize test logic to minimize test bugs.1191201. Spend test effort on parsers, state machines, business rules, transformations, integration seams, and failure modes — not trivial getters or one-line passthroughs.1212. Decide what correct behavior looks like before implementing. When practical, run a red-green loop: watch a check fail, make it pass, rerun to confirm.1223. Prefer integration, macro-behavior, contract, or acceptance tests over unit tests that mirror implementation details.1234. Adjust tests as understanding improves, but never move the goalposts to make a broken implementation look correct; if expected behavior changes, state why.1245. Because you are an LLM, do not optimize for a narrow harness while missing the real contract. Tests expose intended behavior; they are not a reward function to game.1256. Use table-driven or parameterized tests only when they genuinely improve coverage or maintainability.1267. Keep failing output obvious: a reader should see what behavior broke without reconstructing test control flow.1278. Treat LLM-authored tests as temporary scaffolding. Before committing, keep only tests that guard stable behavior, prevent a real regression, or fit the repo's test style; delete the rest.128129## Code review mode130131Use this when reviewing a diff, PR, or another agent's work. For a small diff, combine the lenses below into one careful pass; when the diff is large or complex, make several passes, each asking one lens's question — do not check every rule in one read. Load `references/review-examples.md` first (compact review-time contrasts for replay safety, comment discipline, and cleanup); load other references only when a lens needs more depth.132133Lens passes, in order:1341351. Correctness and contracts — does the change do what it claims; do all variants honor the advertised contract (L); is untrusted data parsed where it crosses a trust boundary; are internal invariants asserted; are failure paths handled. Distinguish validation of untrusted data at a trust boundary from assertions of internal invariants whose failure means a programming error: missing internal-invariant protection on state transitions and cross-record contracts is report-worthy substance, while validation that duplicates what a parser, type, or earlier boundary already guarantees is noise.1362. Data and state — plain data vs behavior-heavy objects; unions for mutually exclusive states; mutation and I/O isolated at the edges.1373. Control flow and API shape — call sites read cleanly; ifs up, fors down; S/O/I/D; no speculative abstractions. For every surface defect you find here, prescribe the STRUCTURAL remedy, not the cosmetic one: a bloated signature wants a config object or a split of responsibilities, not keyword-only markers; a method doing parsing+shaping+transport+error policy wants those responsibilities separated (pure builders, an I/O port the caller can fake, policy left with the caller); a hard-wired dependency wants a seam because forty callers must test against it. Name the new shape concretely.1384. Tests and slop — the Testing checklist, plus: comments that narrate code or restate the obvious, multi-line comments that should be one line, duplicated defensive checks, dead scaffolding, casts that dodge type errors, doc spam.139140Findings:141142- Verify before reporting. Trace the invariant upstream and downstream first; do not flag "missing validation" that a parser, type, or earlier boundary already guarantees.143- Report each finding as `file:line`, severity (blocking / should-fix / nit), and one sentence stating the problem and the fix. No essays.144- Tag each finding with the lens or rule that produced it, e.g. `[lens 2: data and state]` or `[rule: trace invariants]`. Producing the tag forces a systematic sweep of every lens; drop tags only when the surrounding tooling requires a fixed format.145- Quality findings from lenses 2–4 are not padding. Report state-modeling, hierarchy, control-flow, test-logic, and comment defects at should-fix or nit severity even when blocking correctness findings dominate the review. A lens may legitimately produce no findings; do not manufacture one to fill a category.146147Sub-agent fan-out, only when both hold: a sub-agent or task tool exists in your environment, and the diff is large (roughly more than 400 changed lines or 8 files):148149- Spawn at most one agent per lens, max 4. Give each only the diff, its lens's checklist above, and the matching reference file from the list at the end of this skill — not the whole skill.150- Each agent returns findings in the format above.151- Dedupe overlapping findings, then verify each against the actual code before reporting; isolated reviewers produce false positives.152- Never fan out for small diffs. Sequential lens passes are cheaper and more accurate there.153154## Final verification checklist155156Before claiming done, committing, or pushing:1571581. Re-read the user request and confirm the implementation matches the intended behavior.1592. Run the relevant checks, tests, build, or validation gate. If no useful check exists, say so explicitly.1603. Read the command output before claiming success; a started command is not a passed command.1614. Review the diff for AI slop: narrating comments, duplicated null checks, abnormal defensive code, speculative abstractions, broad rewrites, casts that dodge type errors, test or doc spam.1625. Keep only tests and docs that earn their place; remove scaffolding that only helped you think.163164## Long-running sessions165166For substantial multi-step work, use at most two local coordination files:1671681. When continuing a task, check for `plan.md` and `implementation-journal.md`; read `plan.md` first.1692. If no plan exists and the task is substantial, create `plan.md` with the macro plan, intended behavior, important boundaries, validation gates, and testing approach.1703. After the user accepts `plan.md`, do not edit it without permission.1714. Record checkpoints, verification results, surprises, and deviations (with reasons) in `implementation-journal.md`.1725. At the end of a completed task, briefly ask whether to delete either note or archive anything useful.1736. Do not commit or push these notes; prefer `.git/info/exclude` over the repo's `.gitignore`.174175## When to relax the defaults176177Relax when the codebase has a strong local convention that would be expensive to fight, the framework prefers a different structure, an object-oriented interface is the natural integration boundary, mutation is the clearest correct option, or generated code, DSLs, or third-party APIs impose a different shape. Preserve the spirit: clear responsibilities, understandable state transitions, readable tests, intentional API shape.178179## Read these references when needed180181- For plain-data architecture, unions, and system boundaries (review lens 2): `references/architecture.md`182- For call-site-first API design (review lens 3): `references/api-design.md`183- For testing style and tradeoffs (review lens 4): `references/testing.md`184- For boundary parsing, internal invariants, and performance framing (review lens 1): `references/performance-and-safety.md`185- For optional concrete do/don't examples when the task is complex or ambiguous: `references/examples.md`186- For compact review-time contrasts when reviewing a diff or PR: `references/review-examples.md`