Code Like Michael
Default activation (read this first)
If you are about to write, change, review, verify, or architect code — including greenfield projects, bug fixes, refactors, tests, or CLI tools — read and apply this skill now. The user does not need to mention it. This is the default execution policy unless they explicitly ask for a different style.
Before your first line of code:
- Read the codebase context — target file/module, adjacent tests, call sites, config path, and local conventions. Find the smallest seam to change. Do not hallucinate a greenfield-shaped solution into an existing repo.
- Read this skill and skim
references/examples/ for dimensions relevant to your task.
- If the task is greenfield, run the size tripwires and greenfield self-check below before presenting.
- Plan proportionate verification. Identify the changed behaviour and consumer boundary, then choose the smallest check that can disprove each material claim. For ordinary code, this is normally a focused regression plus the owning package or suite; use direct browser, device, runtime, or real-consumer evidence when that is the acceptance boundary.
- Repair what you touch. Anti-patterns inside the functions you edit get fixed as part of the change (see "Maintaining Existing Code").
- Treat first-pass output as a draft to reshape, not an artefact to preserve.
This skill converts labelled examples in references/examples/ into concrete coding decisions.
Anti-slop tripwires
AI-generated code often looks "architected" before it has earned the right to exist. Stop and reshape when you notice:
Size discipline (greenfield)
Before presenting greenfield work, count production files and LOC (exclude tests, generated files, migrations, fixtures, and docs). If over budget, stop and justify every file and layer. Delete or merge anything without an immediate reason. If still over budget, state why before presenting.
| Task complexity |
Reasonable production shape |
Slop warning signs |
| Small utility / single pipeline (e.g. CSV→JSON CLI) |
3–5 files, 80–350 LOC |
8+ files, 500+ LOC, service/repository/factory layers |
| Medium CLI / workflow tool |
5–8 files, 250–500 LOC |
12+ files, 800+ LOC, plugin systems, generic command buses |
| Bug fix / narrow refactor |
Minimal delta to task |
Drive-by renames, new abstraction layers, unrelated files |
If a file cannot justify independent existence ("one reason to change"), merge it back. Compactness is a tripwire, not permission for density theatre.
Abstraction pressure gate
Interfaces, layers, registries, frameworks, and separate modules — do not introduce unless at least one is true right now:
- ≥2 real call sites need the same logic, or
- a genuine unstable boundary (network, filesystem, clock, env, process, hardware), or
- a domain invariant needs one obvious home, or
- lifecycle/ownership cannot be expressed safely in concrete code.
Reject: interfaces with one implementation, Manager/Service/Repository pass-through wrappers, plugin registries before plugins exist.
Domain/boundary types (UserId, AppConfig, ParsedRow, request/response models) — introduce when they parse loose input once, make illegal states harder to represent, or name a real concept. Reuse pressure is not required for types at boundaries.
Rationalisation tripwires
| Excuse |
Reality |
| "This will scale later" |
Scaling pressure is not present yet. Keep the seam visible, not abstract. |
| "The repo already has this pattern" |
Nearby code is evidence, not permission. Copy only patterns that are still good. |
| "A flag keeps it flexible" |
Core workflows must be default and tested. Flags are for output shape, filtering, verbosity, dry-run — not hiding essential behaviour. |
| "This interface helps testing" |
Test real behaviour first. Introduce seams at true external boundaries. |
| "It's only generated scaffolding" |
Generated code gets a higher cleanup bar before presentation. |
| "The existing tests still pass" |
They never exercised the behaviour you changed. Passing is silence, not evidence. |
| "The suite doesn't cover this area anyway" |
You are standing in a coverage gap. Add the test for what you changed; don't inherit the gap. |
| "I can't run the tests in this environment" |
Write them anyway, state UNVERIFIED prominently, and show the exact command to run. |
Scope and trust
- V1 narrow, not a toy: cut speculative features, but keep the trust spine — typed models, validation, useful errors, real tests, honest CLI behaviour.
- No opt-in core workflows: do not make essential behaviour depend on a flag users (or tests) will forget to pass. Optional flags are fine for rendering, filtering, verbosity, dry-run, and output format.
- Return typed outcomes: do not require callers to inspect mutable post-call state (
last_result, error fields, hidden accumulators). Internal caches are fine when invalidation is clear and correctness does not depend on callers clearing/reading them.
- Don't canonise nearby bad code: inspect existing code for useful patterns, but harden bad seams you touch — do not copy
utils dumps, scattered env reads, or placeholder layers just because they are local.
- Higher bar for generated code: use structural or drift checks plus the real consumer or render path where that is the acceptance boundary. More generated files do not justify indiscriminate test breadth.
- Delete scaffolding before claiming done: remove unused files, exports, placeholder TODOs, speculative flags, empty barrels, and dead tests that only assert wiring.
Greenfield self-check (include before presenting)
Production files: N
Production LOC: N
New abstractions: [list each + pressure-gate reason]
Over budget? [yes/no — if yes, justify]
Checks run: [pytest/cargo/etc.]
When to Use
Always, for any coding task, unless the user explicitly requests a different style.
Especially when the work needs to feel deliberately authored in Michael's style, not merely correct:
- new features or bug fixes where architecture choices matter
- refactors that touch boundaries, config, IO, module layout, or CLI shape
- review passes where you need to distinguish
works from fits this repo
- internal tools and utility CLIs that should feel operator-friendly rather than script-like
Do not treat this as permission for decorative rewrites. Prefer narrow, task-shaped changes unless the request explicitly asks for broader restructuring.
Ground Truth
Treat these files as source-of-truth calibration:
references/examples/ (labelled examples; highest authority)
references/examples/greenfield-size-discipline.md (LOC/file-count anchors for greenfield and small refactors)
references/dimensions.md (20 dimensions)
references/annotations-rubric.md (anchor definitions)
When uncertain, prefer consistency with labelled examples over generic best practices.
Style North Star
Write code that is:
- Concrete first, abstract second: extract only when an abstraction clearly earns its keep.
- Boundary strict: parse into typed/domain models early; avoid "stringly" and loose dictionary contracts.
- Thin at the edges: entrypoints orchestrate, domain modules decide, adapters perform IO.
- Operationally explicit: deterministic tooling, obvious command paths, documented and typed configuration.
- Easy to reason about: guard clauses, meaningful names, comments that explain intent and constraints.
Non-Negotiables (Default)
Unless the user explicitly asks otherwise, treat these as MUST-level defaults:
- No runtime env reads in random application code.
- Load config once near startup, parse into a typed config object, inject downstream.
- No placeholder abstractions.
- "Class with one pass-through method" and speculative repository interfaces are usually rejected.
- No broad leaky surfaces by default.
- Keep exports narrow, enforce invariants with constructors/factories and domain types.
- No deeply nested control flow unless unavoidable.
- Prefer early returns and branch flattening.
- No generic/opaque error handling when domain context matters.
- Keep cause + context; prefer typed or structured error paths.
- Test real behaviour, not mocked choreography.
- Prefer real implementations where cheap, then fakes/in-memory adapters, then local services or testcontainers, then spies, and only narrow mocks for genuinely awkward external boundaries.
- Heavy monkeypatching is usually design feedback: push side effects to the edges, inject dependencies explicitly, and keep the core behaviour real.
- Do not patch the code under test just to make a test pass. Test the public behaviour and observable outcome instead.
- Changed behaviour gets proportionate evidence.
- A bug fix normally includes a focused regression that fails before the fix and passes after, followed by the owning package or suite.
- A new feature or flag normally includes a behaviour test covering the user-visible contract.
- When the actual boundary is a browser, device, runtime, protocol peer, generated consumer, or renderer, exercise that boundary directly as well as any useful structural check.
- If an automated regression is genuinely impractical, say why, perform the closest direct verification, and do not claim the work is covered.
- "Existing tests still pass" is not evidence for behaviour those tests never exercised.
Proportionate Verification
This skill owns implementation verification. Independent review cadence belongs to risk-calibrated-agent-reviews; review is not a substitute for evidence.
- Name the claim and boundary. Identify the changed behaviour, the consumer that relies on it, and the failure that would disprove the material claim.
- Start with the smallest useful check. For ordinary changes, run the focused regression and the owning package or suite. Do not begin with the full repository merely because it exists.
- Exercise the real acceptance boundary. Use browser, device, runtime, protocol-peer, or other real-consumer evidence when that is where correctness becomes observable.
- Treat generated artefacts as a producer-consumer pair. Run the repository's structural or drift check, then exercise the generated output through its real consumer or renderer.
- Broaden only for a reason. Wider integration, race, compatibility, or repository-wide checks are warranted by material blast radius, safety-sensitive behaviour, protocols, generated contracts, or an explicit repository gate.
- Reuse still-valid evidence. Do not rerun a check while the relevant tree, artefact, dependencies, and environment are unchanged. Rerun only the evidence invalidated by a correction or state change.
- Do not wait for routine CI. Wait only when CI is an acceptance gate for the requested outcome. A push does not itself invalidate equivalent local evidence.
- Stop when the claims are covered. Once each material claim has adequate evidence at its owning boundary, further suites, repeated review, and CI watching are churn rather than assurance.
Testing and Mocking Defaults
See references/testing-without-mock-theatre.md for the full testing philosophy.
When writing or reviewing tests, default to these rules:
- Replace only true external boundaries.
- Databases, filesystems, networks, clocks, queues, hardware APIs, browser/runtime boundaries, and third-party services are fair seams.
- Core domain logic and the thing under test should usually stay real.
- Prefer dependency injection over monkeypatching.
- Favour constructors, parameters, typed seams, and in-memory implementations over mutating module globals or import state mid-test.
- Never patch the code under test.
- Patching internals of the subject under test turns the test into an implementation lock-in exercise.
- Prefer observable outcomes over call choreography.
- Assert on returned values, persisted state, emitted domain events, rendered output, or other real effects.
- Be suspicious of tests whose whole value is
assert_called_once_with(...) on an internal collaborator.
- Keep test concerns out of production code.
- Reject test-only branches, test-only env vars, hidden global knobs, and "test mode" flags unless there is a strong operational reason.
- Bias toward deterministic, hermetic, parallel-safe tests.
- No shared global state, unbounded sleeps, real wall-clock assumptions, or ambient environment mutation without tight isolation.
Maintaining Existing Code
Maintenance and feature work on an existing codebase has its own discipline, whether or not the codebase already follows this style.
- Prefer the smallest coherent change, not the smallest textual diff.
- "I only changed three lines" is not a substitute for judgement.
- Repair the local contract you touch.
- Fix anti-patterns that sit inside the same edited function/path when they directly affect correctness, testability, or the operator contract — env reads in loops, progress chatter polluting machine-readable stdout, stringly payloads you are already reshaping.
- This is not cleanup; it is not leaving a known-bad seam in your own blast radius.
- Do not broaden into file-wide renovation.
- Code you are not touching stays untouched unless the requested change cannot be made safely without it. Legacy code often has accidental behaviours that broad cleanup will break.
- Match conventions when the codebase is healthy.
- If the repo already has typed models, a config loader, and seams, new code flows through them. Do not bolt special cases onto the entrypoint when a domain type or existing seam is the obvious home.
- Verify the changed behaviour at the owning boundary.
- Normally add a focused regression for a bug or behaviour test for a feature, then run the owning package or suite.
- If the boundary cannot be represented adequately in an automated test, use the closest real consumer, browser, device, or runtime evidence and state the remaining limitation.
- If the existing suite is mock-theatre, do not imitate it for new tests — write behaviour-shaped tests (real files via tmp dirs, real entrypoint invocation) and leave the old tests alone.
- Report verification status honestly.
- Lead your summary with what you ran and the result. If you could not run the checks, say UNVERIFIED prominently — do not bury it. A failing test is a blocker to report, never a footnote to leave behind.
Language-Specific Defaults
The same philosophy applies across languages, but tactics differ.
Rust
- Prefer iterator pipelines for straightforward transformations.
- Prefer typed errors over
String errors for domain flows.
- Keep
main thin; use clap derive-based CLI modelling.
- Prefer domain newtypes/enums over raw primitives for constrained values.
- Avoid excess
let mut; mutate only where it pays for clarity/perf.
Go
- Prefer simple, concrete code over heavyweight repository layering.
- Validate boundary values explicitly (zero values are common failure mode).
- Avoid
flag for complex CLIs; use explicit command parsers like kong and subcommands.
- Prefer explicit dependency injection for testability, but avoid interface explosion.
- Handle errors with context; avoid ambiguous
errors.New("failed").
Python
- Prefer typed models (for example Pydantic/dataclasses at boundaries) over
Dict[str, Any] contracts.
- Keep side effects at edges; pure core transformations in dedicated functions.
- Use straightforward control flow and explicit invariants.
- Prefer meaningful exceptions with context over vague
ValueError("bad input").
TypeScript
- Centralise config in one typed loader; avoid distributed
process.env reads.
- Prefer explicit domain types/unions at boundaries.
- Avoid throwing raw strings.
- Keep CLIs and handlers as orchestration shells, not business-logic dumps.
- Create seams for external IO/time/randomness where tests benefit.
Internal CLI and Operator Tooling Defaults
When the code is a CLI or internal operator tool, apply these additional defaults.
See references/internal-cli-philosophy.md for the full rationale and examples.
- Treat the CLI as a serious operator boundary.
- It is not a thin wrapper around random functions.
- Its job is to make a messy system operable.
- Shape commands around operator tasks, not the source tree.
- Command paths should be guessable from the job to be done.
- Repeated snippets and tribal-knowledge workflows often want a first-class subcommand.
- Keep entrypoints and handlers thin.
- Process-wide setup, parse and validate arguments, assemble dependencies, dispatch, render result.
- Do not hide the system's main understanding inside the CLI shell.
- Parse loose inputs early into typed objects.
- Paths, URLs, request payloads, config, and option combinations should be normalised and validated at the boundary.
- Teach through help text.
--help is part of the interface contract.
- Encode invariants, examples, caveats, and adjacent command hints where the operator will actually look.
- Civilise awkward backends and protocols.
- Normalise weird shapes, reject bad combinations up front, and expose a task-shaped command instead of leaking raw API ceremony.
- Tell the truth.
- No fake flags, no silent fallbacks, no misleading success, no accepting malformed input just to fail later.
- Serve humans, scripts, and agents at the same time.
- Human-readable defaults are good.
- Stable JSON or machine-readable output should exist where automation wants it.
- Keep progress and chatter off structured stdout.
Dimension Application Rules
Use this as a quick execution map while coding.
- Transformation Style: favour declarative transforms when linear and clear.
- Control Flow Shape: guard clauses first; flatten branch trees.
- Mutation Budget: immutable by default, mutation only where local and useful.
- Error Semantics: preserve cause + context; avoid generic failure labels.
- Boundary Contracts: parse, then operate; avoid loosely typed pass-through payloads.
- Naming: identifiers should encode domain intent, not implementation trivia.
- Abstraction Threshold: extract only when the abstraction pressure gate is satisfied; for small modules (<150 LOC total), prefer fewer files.
- Commenting: explain "why/constraint/tradeoff", never narrate obvious mechanics.
- Module Cohesion: one module, one reason to change.
- Dependency Directionality: avoid layering theatre and direction violations.
- Boundary Surface Area: minimal public API; rich internal domain modelling.
- Cross-Cutting Placement: keep logs/metrics/auth at deliberate seams.
- Testability: inject unstable dependencies (clock, network, random, env).
- Concurrency Discipline: prefer well-known primitives/libraries over bespoke concurrency scaffolding.
- Entry-Point Architecture: thin CLI/service entrypoints that delegate.
- Repo Topology: organise by feature/responsibility, not generic buckets.
- Config Strategy: one typed config load path near startup.
- IO Isolation: separate pure domain logic from transport/storage.
- Tooling Contract: explicit, reproducible scripts and pinned toolchain versions.
- Evolution Posture: migrations and deprecations where compatibility matters.
Anti-Patterns to Reject by Default
Flag these unless a clear task-specific reason exists:
util/helpers dumping grounds with unrelated concerns
- Deeply nested
if/else trees where early returns would simplify
- Generic names (
x, data, thing, doStuff) in domain code
- Runtime env access from request handlers/domain functions
- "Stringly typed" domain fields when constrained types are known
- Entry-point files containing domain/business logic
- CLI surfaces organised around package names instead of operator tasks
- Help text omitting invariants, examples, or dangerous constraints.
- Fake or placeholder flags that imply behaviour the tool does not implement
- Mixing machine-readable stdout with human progress noise
- Comments that duplicate the code line-by-line
- Hard-coded network/time dependencies in logic that should be testable
- Solving a generic nearby problem instead of the actual local problem
- Tests that assert mocked choreography rather than observable behaviour
- Heavy monkeypatching that papers over hidden dependencies instead of fixing the seam
- Patching the code under test or mutating import/module globals halfway through a test
- Test-only production branches, flags, env vars, or hidden knobs added just to make tests pass
- Speculative options, unused helpers, or "future-proofing" left behind
- Bypassing existing config/logging/tracing/auth/IO seams instead of using them
- Architecture nouns outnumbering domain nouns (
Service, Repository, Manager before real pressure)
- Optional flags that make core workflow behaviour opt-in or create large untested alternate paths
- Mutable post-call inspection state instead of returned typed results (
last_result, inspect-after-call patterns)
- Copying nearby bad patterns (utils dumps, scattered env reads) because they exist in the repo
- Greenfield file/LOC counts in slop territory per the size tripwires above
Implementation Workflow (Agent)
When this skill is active, follow this sequence:
- Classify the change across micro/meso/macro dimensions.
- Design boundaries first: identify domain types, seams, and entrypoint responsibilities.
- Implement concretely with minimal necessary abstraction.
- Reshape first-pass output as a draft, not an artefact to preserve. Apply this default sequence until the code looks deliberately authored for this repository:
- count files and LOC — delete excess structure if over greenfield budget
- delete unjustified abstractions (apply the abstraction pressure gate)
- recover local domain names
- move validation to the correct boundary
- preserve cause and context in errors
- test the real seam, not its scaffolding
- confirm every remaining file has a reason to exist
- Run a style self-audit using the checklist below before presenting.
Prefer surgical changes. Do not reformat, rename, repartition modules, or introduce new architecture unless it directly supports the requested change.
Pre-Response Self-Audit Checklist
Before returning code, verify:
- Are boundaries typed and explicit?
- Is config loaded centrally and injected?
- Are entrypoints thin?
- Is control flow flattened where possible?
- Are names domain-meaningful?
- Are comments high-signal (why/constraints) rather than narration?
- Are abstractions justified by real complexity/reuse?
- Are IO/time/env dependencies isolated enough for testing?
- Are errors specific and context-bearing?
- Is the repo/module shape moving toward cohesive responsibility boundaries?
- For greenfield work: are file count and LOC within the size tripwires?
- Did every new abstraction pass the pressure gate (≥2 call sites, unstable boundary, domain invariant, or ownership need)?
- Does every material claim have proportionate evidence at its owning consumer boundary, with a focused regression where practical?
- Do any tests monkeypatch module globals where an injection seam exists (including seams you just built)?
- Did you run the checks, and does your summary state the result honestly (or UNVERIFIED)?
If two style goals conflict, choose the option that:
- strengthens boundary correctness,
- keeps execution model explicit,
- reduces accidental complexity.
Review Mode Guidance
When reviewing code, prioritise findings in this order:
- Broken/weak boundaries (contracts, validation, domain typing)
- Architecture drift (fat entrypoints, mixed responsibilities, leaky surfaces)
- Testability regressions (hard-coded side effects, missing seams)
- Error/context quality
- Readability and naming quality
Keep feedback concrete and propose specific reshaping steps, not abstract style advice.
1---2name: code-like-michael3description: Use when writing, changing, reviewing, testing, verifying, refactoring, or architecting code, including greenfield apps, CLIs, bug fixes, and PR reviews. Applies Michael's default coding style: typed boundaries, thin entrypoints, concrete-first design, anti-ceremony abstractions, proportionate evidence, and operator-shaped interfaces.4---56# Code Like Michael78## Default activation (read this first)910**If you are about to write, change, review, verify, or architect code — including greenfield projects, bug fixes, refactors, tests, or CLI tools — read and apply this skill now.** The user does not need to mention it. This is the default execution policy unless they explicitly ask for a different style.1112Before your first line of code:13141. **Read the codebase context** — target file/module, adjacent tests, call sites, config path, and local conventions. Find the smallest seam to change. Do not hallucinate a greenfield-shaped solution into an existing repo.152. **Read this skill** and skim `references/examples/` for dimensions relevant to your task.163. If the task is greenfield, run the **size tripwires** and **greenfield self-check** below before presenting.174. **Plan proportionate verification.** Identify the changed behaviour and consumer boundary, then choose the smallest check that can disprove each material claim. For ordinary code, this is normally a focused regression plus the owning package or suite; use direct browser, device, runtime, or real-consumer evidence when that is the acceptance boundary.185. **Repair what you touch.** Anti-patterns inside the functions you edit get fixed as part of the change (see "Maintaining Existing Code").196. Treat first-pass output as a **draft to reshape**, not an artefact to preserve.2021This skill converts labelled examples in `references/examples/` into concrete coding decisions.2223## Anti-slop tripwires2425AI-generated code often looks "architected" before it has earned the right to exist. Stop and reshape when you notice:2627### Size discipline (greenfield)2829Before presenting greenfield work, count **production** files and LOC (exclude tests, generated files, migrations, fixtures, and docs). If over budget, **stop and justify every file and layer**. Delete or merge anything without an immediate reason. If still over budget, state why before presenting.3031| Task complexity | Reasonable production shape | Slop warning signs |32|-----------------|----------------------------|-------------------|33| Small utility / single pipeline (e.g. CSV→JSON CLI) | 3–5 files, 80–350 LOC | 8+ files, 500+ LOC, service/repository/factory layers |34| Medium CLI / workflow tool | 5–8 files, 250–500 LOC | 12+ files, 800+ LOC, plugin systems, generic command buses |35| Bug fix / narrow refactor | Minimal delta to task | Drive-by renames, new abstraction layers, unrelated files |3637If a file cannot justify independent existence ("one reason to change"), merge it back. Compactness is a tripwire, not permission for density theatre.3839### Abstraction pressure gate4041**Interfaces, layers, registries, frameworks, and separate modules** — do not introduce unless at least one is true **right now**:4243- **≥2 real call sites** need the same logic, or44- a **genuine unstable boundary** (network, filesystem, clock, env, process, hardware), or45- a **domain invariant** needs one obvious home, or46- **lifecycle/ownership** cannot be expressed safely in concrete code.4748Reject: interfaces with one implementation, `Manager`/`Service`/`Repository` pass-through wrappers, plugin registries before plugins exist.4950**Domain/boundary types** (`UserId`, `AppConfig`, `ParsedRow`, request/response models) — introduce when they parse loose input once, make illegal states harder to represent, or name a real concept. Reuse pressure is not required for types at boundaries.5152### Rationalisation tripwires5354| Excuse | Reality |55|--------|---------|56| "This will scale later" | Scaling pressure is not present yet. Keep the seam visible, not abstract. |57| "The repo already has this pattern" | Nearby code is evidence, not permission. Copy only patterns that are still good. |58| "A flag keeps it flexible" | Core workflows must be default and tested. Flags are for output shape, filtering, verbosity, dry-run — not hiding essential behaviour. |59| "This interface helps testing" | Test real behaviour first. Introduce seams at true external boundaries. |60| "It's only generated scaffolding" | Generated code gets a **higher** cleanup bar before presentation. |61| "The existing tests still pass" | They never exercised the behaviour you changed. Passing is silence, not evidence. |62| "The suite doesn't cover this area anyway" | You are standing in a coverage gap. Add the test for what you changed; don't inherit the gap. |63| "I can't run the tests in this environment" | Write them anyway, state UNVERIFIED prominently, and show the exact command to run. |6465### Scope and trust6667- **V1 narrow, not a toy**: cut speculative features, but keep the trust spine — typed models, validation, useful errors, real tests, honest CLI behaviour.68- **No opt-in core workflows**: do not make essential behaviour depend on a flag users (or tests) will forget to pass. Optional flags are fine for rendering, filtering, verbosity, dry-run, and output format.69- **Return typed outcomes**: do not require callers to inspect mutable post-call state (`last_result`, `error` fields, hidden accumulators). Internal caches are fine when invalidation is clear and correctness does not depend on callers clearing/reading them.70- **Don't canonise nearby bad code**: inspect existing code for useful patterns, but harden bad seams you touch — do not copy `utils` dumps, scattered env reads, or placeholder layers just because they are local.71- **Higher bar for generated code**: use structural or drift checks plus the real consumer or render path where that is the acceptance boundary. More generated files do not justify indiscriminate test breadth.72- **Delete scaffolding before claiming done**: remove unused files, exports, placeholder TODOs, speculative flags, empty barrels, and dead tests that only assert wiring.7374### Greenfield self-check (include before presenting)7576```77Production files: N78Production LOC: N79New abstractions: [list each + pressure-gate reason]80Over budget? [yes/no — if yes, justify]81Checks run: [pytest/cargo/etc.]82```8384## When to Use8586**Always**, for any coding task, unless the user explicitly requests a different style.8788Especially when the work needs to feel deliberately authored in Michael's style, not merely correct:8990- new features or bug fixes where architecture choices matter91- refactors that touch boundaries, config, IO, module layout, or CLI shape92- review passes where you need to distinguish `works` from `fits this repo`93- internal tools and utility CLIs that should feel operator-friendly rather than script-like9495Do not treat this as permission for decorative rewrites. Prefer narrow, task-shaped changes unless the request explicitly asks for broader restructuring.9697## Ground Truth9899Treat these files as source-of-truth calibration:100101- `references/examples/` (labelled examples; highest authority)102- `references/examples/greenfield-size-discipline.md` (LOC/file-count anchors for greenfield and small refactors)103- `references/dimensions.md` (20 dimensions)104- `references/annotations-rubric.md` (anchor definitions)105106When uncertain, prefer consistency with labelled examples over generic best practices.107108## Style North Star109110Write code that is:1111121. **Concrete first, abstract second**: extract only when an abstraction clearly earns its keep.1132. **Boundary strict**: parse into typed/domain models early; avoid "stringly" and loose dictionary contracts.1143. **Thin at the edges**: entrypoints orchestrate, domain modules decide, adapters perform IO.1154. **Operationally explicit**: deterministic tooling, obvious command paths, documented and typed configuration.1165. **Easy to reason about**: guard clauses, meaningful names, comments that explain intent and constraints.117118## Non-Negotiables (Default)119120Unless the user explicitly asks otherwise, treat these as MUST-level defaults:1211221. **No runtime env reads in random application code.**123 - Load config once near startup, parse into a typed config object, inject downstream.1242. **No placeholder abstractions.**125 - "Class with one pass-through method" and speculative repository interfaces are usually rejected.1263. **No broad leaky surfaces by default.**127 - Keep exports narrow, enforce invariants with constructors/factories and domain types.1284. **No deeply nested control flow unless unavoidable.**129 - Prefer early returns and branch flattening.1305. **No generic/opaque error handling when domain context matters.**131 - Keep cause + context; prefer typed or structured error paths.1326. **Test real behaviour, not mocked choreography.**133 - Prefer real implementations where cheap, then fakes/in-memory adapters, then local services or testcontainers, then spies, and only narrow mocks for genuinely awkward external boundaries.134 - Heavy monkeypatching is usually design feedback: push side effects to the edges, inject dependencies explicitly, and keep the core behaviour real.135 - Do not patch the code under test just to make a test pass. Test the public behaviour and observable outcome instead.1367. **Changed behaviour gets proportionate evidence.**137 - A bug fix normally includes a focused regression that fails before the fix and passes after, followed by the owning package or suite.138 - A new feature or flag normally includes a behaviour test covering the user-visible contract.139 - When the actual boundary is a browser, device, runtime, protocol peer, generated consumer, or renderer, exercise that boundary directly as well as any useful structural check.140 - If an automated regression is genuinely impractical, say why, perform the closest direct verification, and do not claim the work is covered.141 - "Existing tests still pass" is not evidence for behaviour those tests never exercised.142143## Proportionate Verification144145This skill owns implementation verification. Independent review cadence belongs to `risk-calibrated-agent-reviews`; review is not a substitute for evidence.1461471. **Name the claim and boundary.** Identify the changed behaviour, the consumer that relies on it, and the failure that would disprove the material claim.1482. **Start with the smallest useful check.** For ordinary changes, run the focused regression and the owning package or suite. Do not begin with the full repository merely because it exists.1493. **Exercise the real acceptance boundary.** Use browser, device, runtime, protocol-peer, or other real-consumer evidence when that is where correctness becomes observable.1504. **Treat generated artefacts as a producer-consumer pair.** Run the repository's structural or drift check, then exercise the generated output through its real consumer or renderer.1515. **Broaden only for a reason.** Wider integration, race, compatibility, or repository-wide checks are warranted by material blast radius, safety-sensitive behaviour, protocols, generated contracts, or an explicit repository gate.1526. **Reuse still-valid evidence.** Do not rerun a check while the relevant tree, artefact, dependencies, and environment are unchanged. Rerun only the evidence invalidated by a correction or state change.1537. **Do not wait for routine CI.** Wait only when CI is an acceptance gate for the requested outcome. A push does not itself invalidate equivalent local evidence.1548. **Stop when the claims are covered.** Once each material claim has adequate evidence at its owning boundary, further suites, repeated review, and CI watching are churn rather than assurance.155156## Testing and Mocking Defaults157158See `references/testing-without-mock-theatre.md` for the full testing philosophy.159160When writing or reviewing tests, default to these rules:1611621. **Replace only true external boundaries.**163 - Databases, filesystems, networks, clocks, queues, hardware APIs, browser/runtime boundaries, and third-party services are fair seams.164 - Core domain logic and the thing under test should usually stay real.1652. **Prefer dependency injection over monkeypatching.**166 - Favour constructors, parameters, typed seams, and in-memory implementations over mutating module globals or import state mid-test.1673. **Never patch the code under test.**168 - Patching internals of the subject under test turns the test into an implementation lock-in exercise.1694. **Prefer observable outcomes over call choreography.**170 - Assert on returned values, persisted state, emitted domain events, rendered output, or other real effects.171 - Be suspicious of tests whose whole value is `assert_called_once_with(...)` on an internal collaborator.1725. **Keep test concerns out of production code.**173 - Reject test-only branches, test-only env vars, hidden global knobs, and "test mode" flags unless there is a strong operational reason.1746. **Bias toward deterministic, hermetic, parallel-safe tests.**175 - No shared global state, unbounded sleeps, real wall-clock assumptions, or ambient environment mutation without tight isolation.176177## Maintaining Existing Code178179Maintenance and feature work on an existing codebase has its own discipline, whether or not the codebase already follows this style.1801811. **Prefer the smallest coherent change, not the smallest textual diff.**182 - "I only changed three lines" is not a substitute for judgement.1832. **Repair the local contract you touch.**184 - Fix anti-patterns that sit inside the same edited function/path when they directly affect correctness, testability, or the operator contract — env reads in loops, progress chatter polluting machine-readable stdout, stringly payloads you are already reshaping.185 - This is not cleanup; it is not leaving a known-bad seam in your own blast radius.1863. **Do not broaden into file-wide renovation.**187 - Code you are not touching stays untouched unless the requested change cannot be made safely without it. Legacy code often has accidental behaviours that broad cleanup will break.1884. **Match conventions when the codebase is healthy.**189 - If the repo already has typed models, a config loader, and seams, new code flows through them. Do not bolt special cases onto the entrypoint when a domain type or existing seam is the obvious home.1905. **Verify the changed behaviour at the owning boundary.**191 - Normally add a focused regression for a bug or behaviour test for a feature, then run the owning package or suite.192 - If the boundary cannot be represented adequately in an automated test, use the closest real consumer, browser, device, or runtime evidence and state the remaining limitation.193 - If the existing suite is mock-theatre, do not imitate it for new tests — write behaviour-shaped tests (real files via tmp dirs, real entrypoint invocation) and leave the old tests alone.1946. **Report verification status honestly.**195 - Lead your summary with what you ran and the result. If you could not run the checks, say **UNVERIFIED** prominently — do not bury it. A failing test is a blocker to report, never a footnote to leave behind.196197## Language-Specific Defaults198199The same philosophy applies across languages, but tactics differ.200201### Rust202203- Prefer iterator pipelines for straightforward transformations.204- Prefer typed errors over `String` errors for domain flows.205- Keep `main` thin; use `clap` derive-based CLI modelling.206- Prefer domain newtypes/enums over raw primitives for constrained values.207- Avoid excess `let mut`; mutate only where it pays for clarity/perf.208209### Go210211- Prefer simple, concrete code over heavyweight repository layering.212- Validate boundary values explicitly (zero values are common failure mode).213- Avoid `flag` for complex CLIs; use explicit command parsers like `kong` and subcommands.214- Prefer explicit dependency injection for testability, but avoid interface explosion.215- Handle errors with context; avoid ambiguous `errors.New("failed")`.216217### Python218219- Prefer typed models (for example Pydantic/dataclasses at boundaries) over `Dict[str, Any]` contracts.220- Keep side effects at edges; pure core transformations in dedicated functions.221- Use straightforward control flow and explicit invariants.222- Prefer meaningful exceptions with context over vague `ValueError("bad input")`.223224### TypeScript225226- Centralise config in one typed loader; avoid distributed `process.env` reads.227- Prefer explicit domain types/unions at boundaries.228- Avoid throwing raw strings.229- Keep CLIs and handlers as orchestration shells, not business-logic dumps.230- Create seams for external IO/time/randomness where tests benefit.231232## Internal CLI and Operator Tooling Defaults233234When the code is a CLI or internal operator tool, apply these additional defaults.235236See `references/internal-cli-philosophy.md` for the full rationale and examples.2372381. **Treat the CLI as a serious operator boundary.**239 - It is not a thin wrapper around random functions.240 - Its job is to make a messy system operable.2412. **Shape commands around operator tasks, not the source tree.**242 - Command paths should be guessable from the job to be done.243 - Repeated snippets and tribal-knowledge workflows often want a first-class subcommand.2443. **Keep entrypoints and handlers thin.**245 - Process-wide setup, parse and validate arguments, assemble dependencies, dispatch, render result.246 - Do not hide the system's main understanding inside the CLI shell.2474. **Parse loose inputs early into typed objects.**248 - Paths, URLs, request payloads, config, and option combinations should be normalised and validated at the boundary.2495. **Teach through help text.**250 - `--help` is part of the interface contract.251 - Encode invariants, examples, caveats, and adjacent command hints where the operator will actually look.2526. **Civilise awkward backends and protocols.**253 - Normalise weird shapes, reject bad combinations up front, and expose a task-shaped command instead of leaking raw API ceremony.2547. **Tell the truth.**255 - No fake flags, no silent fallbacks, no misleading success, no accepting malformed input just to fail later.2568. **Serve humans, scripts, and agents at the same time.**257 - Human-readable defaults are good.258 - Stable JSON or machine-readable output should exist where automation wants it.259 - Keep progress and chatter off structured stdout.260261## Dimension Application Rules262263Use this as a quick execution map while coding.2642651. **Transformation Style**: favour declarative transforms when linear and clear.2662. **Control Flow Shape**: guard clauses first; flatten branch trees.2673. **Mutation Budget**: immutable by default, mutation only where local and useful.2684. **Error Semantics**: preserve cause + context; avoid generic failure labels.2695. **Boundary Contracts**: parse, then operate; avoid loosely typed pass-through payloads.2706. **Naming**: identifiers should encode domain intent, not implementation trivia.2717. **Abstraction Threshold**: extract only when the abstraction pressure gate is satisfied; for small modules (<150 LOC total), prefer fewer files.2728. **Commenting**: explain "why/constraint/tradeoff", never narrate obvious mechanics.2739. **Module Cohesion**: one module, one reason to change.27410. **Dependency Directionality**: avoid layering theatre and direction violations.27511. **Boundary Surface Area**: minimal public API; rich internal domain modelling.27612. **Cross-Cutting Placement**: keep logs/metrics/auth at deliberate seams.27713. **Testability**: inject unstable dependencies (clock, network, random, env).27814. **Concurrency Discipline**: prefer well-known primitives/libraries over bespoke concurrency scaffolding.27915. **Entry-Point Architecture**: thin CLI/service entrypoints that delegate.28016. **Repo Topology**: organise by feature/responsibility, not generic buckets.28117. **Config Strategy**: one typed config load path near startup.28218. **IO Isolation**: separate pure domain logic from transport/storage.28319. **Tooling Contract**: explicit, reproducible scripts and pinned toolchain versions.28420. **Evolution Posture**: migrations and deprecations where compatibility matters.285286## Anti-Patterns to Reject by Default287288Flag these unless a clear task-specific reason exists:289290- `util`/`helpers` dumping grounds with unrelated concerns291- Deeply nested `if/else` trees where early returns would simplify292- Generic names (`x`, `data`, `thing`, `doStuff`) in domain code293- Runtime env access from request handlers/domain functions294- "Stringly typed" domain fields when constrained types are known295- Entry-point files containing domain/business logic296- CLI surfaces organised around package names instead of operator tasks297- Help text omitting invariants, examples, or dangerous constraints.298- Fake or placeholder flags that imply behaviour the tool does not implement299- Mixing machine-readable stdout with human progress noise300- Comments that duplicate the code line-by-line301- Hard-coded network/time dependencies in logic that should be testable302- Solving a generic nearby problem instead of the actual local problem303- Tests that assert mocked choreography rather than observable behaviour304- Heavy monkeypatching that papers over hidden dependencies instead of fixing the seam305- Patching the code under test or mutating import/module globals halfway through a test306- Test-only production branches, flags, env vars, or hidden knobs added just to make tests pass307- Speculative options, unused helpers, or "future-proofing" left behind308- Bypassing existing config/logging/tracing/auth/IO seams instead of using them309- Architecture nouns outnumbering domain nouns (`Service`, `Repository`, `Manager` before real pressure)310- Optional flags that make core workflow behaviour opt-in or create large untested alternate paths311- Mutable post-call inspection state instead of returned typed results (`last_result`, inspect-after-call patterns)312- Copying nearby bad patterns (utils dumps, scattered env reads) because they exist in the repo313- Greenfield file/LOC counts in slop territory per the size tripwires above314315## Implementation Workflow (Agent)316317When this skill is active, follow this sequence:3183191. **Classify the change** across micro/meso/macro dimensions.3202. **Design boundaries first**: identify domain types, seams, and entrypoint responsibilities.3213. **Implement concretely** with minimal necessary abstraction.3224. **Reshape first-pass output as a draft**, not an artefact to preserve. Apply this default sequence until the code looks deliberately authored for this repository:323 1. count files and LOC — delete excess structure if over greenfield budget324 2. delete unjustified abstractions (apply the abstraction pressure gate)325 3. recover local domain names326 4. move validation to the correct boundary327 5. preserve cause and context in errors328 6. test the real seam, not its scaffolding329 7. confirm every remaining file has a reason to exist3305. **Run a style self-audit** using the checklist below before presenting.331332Prefer surgical changes. Do not reformat, rename, repartition modules, or introduce new architecture unless it directly supports the requested change.333334## Pre-Response Self-Audit Checklist335336Before returning code, verify:337338- Are boundaries typed and explicit?339- Is config loaded centrally and injected?340- Are entrypoints thin?341- Is control flow flattened where possible?342- Are names domain-meaningful?343- Are comments high-signal (why/constraints) rather than narration?344- Are abstractions justified by real complexity/reuse?345- Are IO/time/env dependencies isolated enough for testing?346- Are errors specific and context-bearing?347- Is the repo/module shape moving toward cohesive responsibility boundaries?348- For greenfield work: are file count and LOC within the size tripwires?349- Did every new abstraction pass the pressure gate (≥2 call sites, unstable boundary, domain invariant, or ownership need)?350- Does every material claim have proportionate evidence at its owning consumer boundary, with a focused regression where practical?351- Do any tests monkeypatch module globals where an injection seam exists (including seams you just built)?352- Did you run the checks, and does your summary state the result honestly (or UNVERIFIED)?353354If two style goals conflict, choose the option that:3553561. strengthens boundary correctness,3572. keeps execution model explicit,3583. reduces accidental complexity.359360## Review Mode Guidance361362When reviewing code, prioritise findings in this order:3633641. Broken/weak boundaries (contracts, validation, domain typing)3652. Architecture drift (fat entrypoints, mixed responsibilities, leaky surfaces)3663. Testability regressions (hard-coded side effects, missing seams)3674. Error/context quality3685. Readability and naming quality369370Keep feedback concrete and propose specific reshaping steps, not abstract style advice.