Code Quality Standards
Code standards, testing requirements, error handling patterns, security practices, build verification, and living documents maintenance.
Tags
README
code-quality
Code standards, testing requirements, error handling patterns, security practices, build verification, and living documents maintenance.
What It Does
This module installs a rules file that instructs Claude to:
- Choose the simplest implementation that fully meets the current requirements, rather than building for requirements that do not exist yet
- Climb the dependency ladder deliberately: built-in first, then an established library, and hand-rolled code only when neither fits
- Delete backward-compatibility shims and migrate callers instead of keeping old shapes alive
- Follow consistent code standards (environment variables, database migrations, dependencies, component patterns, path aliases)
- Write tests for new features, edge cases, bug fixes, and complex logic
- Apply structured error handling patterns for both frontend and backend
- Enforce security practices (input sanitization, upload validation, secrets management, RLS)
- Run full build verification before pushing code
- Maintain living documents (README, project story) after PR merges
Manual Installation
Copy rules/code-quality.md into your Claude configuration:
# Global (all projects)
mkdir -p ~/.claude/rules
cp rules/code-quality.md ~/.claude/rules/code-quality.md
cp rules/change-philosophy.md ~/.claude/rules/change-philosophy.md
cp rules/latent-vs-deterministic.md ~/.claude/rules/latent-vs-deterministic.md
cp rules/completeness.md ~/.claude/rules/completeness.md
cp rules/receiving-code-review.md ~/.claude/rules/receiving-code-review.md
cp rules/in-the-circuits.md ~/.claude/rules/in-the-circuits.md
cp rules/spec-is-the-artifact.md ~/.claude/rules/spec-is-the-artifact.md
cp rules/menu-gen-test.md ~/.claude/rules/menu-gen-test.md
# Project-level
mkdir -p .claude/rules
cp rules/code-quality.md .claude/rules/code-quality.md
cp rules/change-philosophy.md .claude/rules/change-philosophy.md
cp rules/latent-vs-deterministic.md .claude/rules/latent-vs-deterministic.md
cp rules/completeness.md .claude/rules/completeness.md
cp rules/receiving-code-review.md .claude/rules/receiving-code-review.md
cp rules/in-the-circuits.md .claude/rules/in-the-circuits.md
cp rules/spec-is-the-artifact.md .claude/rules/spec-is-the-artifact.md
cp rules/menu-gen-test.md .claude/rules/menu-gen-test.md
Files
| File | Description |
|---|---|
rules/code-quality.md |
Rule file covering the simplest-implementation principle, the dependency ladder (built-in > established library > custom implementation), code standards, testing, error handling, security, build verification, and living documents |
rules/change-philosophy.md |
Rule file on elegant integration: redesign existing systems rather than bolting on, and delete backward-compatibility shims rather than preserving old shapes |
rules/latent-vs-deterministic.md |
Rule file on classifying work as latent (judgment) vs deterministic (scripts) and pushing deterministic steps into code |
rules/completeness.md |
Rule file on the Boil-the-Lake completeness principle and scoring rubric |
rules/receiving-code-review.md |
Rule file on receiving code review feedback: verify before implementing, push back with evidence, no sycophantic agreement |
rules/in-the-circuits.md |
Rule file on classifying tasks as in-circuit (dense RL training, trust output) vs out-of-circuit (no verifier, slow down) before proceeding |
rules/spec-is-the-artifact.md |
Rule file on treating the spec as the durable artifact and code as regenerable output; write and review the spec before the code runs |
rules/menu-gen-test.md |
Rule file on the Menu-Gen Test: before building an app/script/feature, ask whether a single prompt or multimodal call could replace it |
Will install
| Path | Action | Target | Type |
|---|---|---|---|
rules/code-quality.md | → | rules/code-quality.md | rule |
rules/change-philosophy.md | → | rules/change-philosophy.md | rule |
rules/latent-vs-deterministic.md | → | rules/latent-vs-deterministic.md | rule |
rules/completeness.md | → | rules/completeness.md | rule |
rules/receiving-code-review.md | → | rules/receiving-code-review.md | rule |
rules/in-the-circuits.md | → | rules/in-the-circuits.md | rule |
rules/spec-is-the-artifact.md | → | rules/spec-is-the-artifact.md | rule |
rules/menu-gen-test.md | → | rules/menu-gen-test.md | rule |
Dependencies
No dependencies.
Required by
Included in presets
Install this module
Agent prompt
Recommended for agent users -- hands the whole install off to your assistant.
Fetch https://cd23a9be.ccgm-site.pages.dev/modules/code-quality.md and install this module into my Claude Code setup.
Native plugin marketplace
One command via the native plugin marketplace -- additive, does not merge settings.json.
claude plugin install code-quality@ccgm
The marketplace path is additive, not a replacement: it installs commands, agents, and skills as native plugin components, but it does not perform the bash installer's deep settings.json merge, and it does not write the always-loaded global CLAUDE.md context. Rules are only injected via an opt-in SessionStart hook rather than being auto-loaded. Use the bash installer when those pieces matter to you.
Files
rule (8)
rules/code-quality.md
# Code Quality Standards
## Simplest Implementation That Fully Meets the Requirements
Choose the simplest implementation that fully meets the current requirements. Both halves carry weight:
- **Simplest** - no abstraction with one implementation, no config option nobody sets, no plugin system for a single plugin, no generic helper called from one place.
- **Fully meets the current requirements** - simple is not the same as partial. Every stated requirement is handled, edge cases and error paths included. See `completeness.md`.
The requirements that count are the ones that exist now. A requirement someone might have next quarter is a guess, and code shaped around a guess has to be unwound when the guess turns out wrong. Build the second case when the second case arrives - by then its actual shape is known.
Signs the implementation outran the requirements:
- An interface with exactly one implementer
- A config option that is never set to anything but its default
- A layer whose only job is forwarding calls to the next layer
- Generic type parameters instantiated with the same concrete type everywhere
- "We'll need this when we add X" where X is on no roadmap
## Minimize Dependencies and Complexity
Prefer the simplest layer that fully solves the problem. If a built-in language feature, standard library, or platform capability achieves an equal or better outcome, use it instead of adding a dependency.
This applies to everything: CLI tools, npm packages, frameworks, shell utilities, and any external tooling.
**The ladder: built-in > established library > custom implementation > framework.**
- **Before adding a dependency**, check whether the language or platform already provides what you need
- **When the built-in does not cover it, prefer an established, well-maintained library over a custom implementation** - see below
- **Fewer dependencies = fewer failure modes** - every dependency is a maintenance burden, a security surface, and a breaking-change risk
- **Equal outcome = no dependency** - if the result is the same or better without the tool, don't use the tool
Built-in wins:
- Pure bash with ANSI escapes instead of a TUI library for simple menus
- `fetch()` instead of axios for HTTP requests
- CSS variables instead of a theming library
- Shell built-ins (`read`, `printf`) instead of external CLI tools
### Established Library Over Custom Implementation
"Minimize dependencies" is not "write it yourself." A hand-rolled implementation is still a dependency - one with no maintainer, no security advisories, no other users finding its bugs, and no exit. When the built-in genuinely does not cover the problem, take the established library.
Library wins:
- A maintained date library instead of hand-written timezone and DST arithmetic
- The platform crypto API or a vetted library instead of a hand-written primitive
- A real parser for a real grammar (CSV, YAML, semver, HTML) instead of regex
- A schema validator instead of hand-written per-field checks across every entry point
"Established, well-maintained" means: released within the last year or explicitly finished, an issue tracker someone answers, a license that permits the use, and adoption wide enough that its bugs surface in public rather than in this codebase. A package failing those tests is not a safer choice than writing the code - it is the same risk with less control.
The dividing line is scope, not preference. Twenty lines of obvious logic is not a library's job. Anything with a specification behind it - dates, encodings, crypto, grammars, protocols - is.
## Code Standards
### Environment Variables
- When adding new env vars, update the corresponding `.env.example` file
- Never commit actual secrets or API keys
### Database Changes
- New migrations require regenerating TypeScript types
- Document schema changes in the migration file comments
- After merging a PR with migrations, run them immediately. Do not defer migration execution to manual follow-up issues.
#### Migration Validation (REQUIRED)
**Before committing any migration file**, validate it will run without errors:
1. **Quote reserved keywords** - These PostgreSQL reserved words must be double-quoted when used as identifiers:
- `position`, `order`, `user`, `offset`, `limit`, `key`, `value`, `type`, `name`, `check`, `default`, `time`, `index`, `comment`
- Example: `"position" integer` not `position integer`
2. **Use idempotent patterns**:
- Functions: `CREATE OR REPLACE FUNCTION`
- Triggers: `DROP TRIGGER IF EXISTS ... ; CREATE TRIGGER ...`
- Indexes: `CREATE INDEX IF NOT EXISTS`
- Tables: `CREATE TABLE IF NOT EXISTS` (when appropriate)
- Columns: `ALTER TABLE ... ADD COLUMN IF NOT EXISTS`
- Policies: `DROP POLICY IF EXISTS ... ; CREATE POLICY ...`
3. **Test locally before committing** (prefer non-destructive methods):
```bash
# Preferred: Apply only pending migrations (preserves local data)
supabase migration up
# Alternative: Full reset (wipes all local data)
supabase db reset
```
Use `migration up` for iterative development. Use `db reset` only when you need a clean slate or are debugging migration order issues.
4. **Common gotchas**:
- `ON CONFLICT` requires a unique constraint on the conflict columns
- `SECURITY DEFINER` functions run as the owner, not the caller
- RLS policies need `USING` (for SELECT/UPDATE/DELETE) and/or `WITH CHECK` (for INSERT/UPDATE)
### Dependencies
- **Question every new dependency** - can the standard library or a built-in do this?
- Justify new npm packages in PR description (why is this needed over a simpler approach?)
- **A custom implementation is also a dependency.** Justify hand-rolling in the PR description the same way - why this over an established library?
- Prefer well-maintained packages with good TypeScript support when a dependency is genuinely warranted
### Component Patterns (React/TypeScript)
```typescript
// Always use functional components with TypeScript
interface ComponentProps {
// Define props with explicit types
}
export function Component({ prop1, prop2 }: ComponentProps) {
return <div className="container">...</div>;
}
```
### Path Aliases
Use path aliases for clean imports:
- `@/` -> `src/`
- `@components/` -> `src/components/`
- `@hooks/` -> `src/hooks/`
- `@services/` -> `src/services/`
- `@types/` -> `src/types/`
---
## Testing
Write tests for:
- **New features** - cover the happy path and key functionality
- **Edge cases** - empty states, boundary conditions, invalid inputs
- **Bug fixes** - add a test that reproduces the bug before fixing
- **Complex logic** - utilities, hooks, business logic
---
## Error Handling
### Frontend (React)
- Use error boundaries to wrap major sections
- Show toast notifications for user feedback
- Validate forms before submit with inline errors
- Handle loading and error states in data fetching
### Backend
- Centralized error middleware for consistent responses
- Never leak internal details - generic messages to client, detailed logs server-side
### General Principles
- Fail fast in development (throw, don't swallow)
- Graceful degradation in production
- Always give users actionable feedback
- Log errors for debugging
---
## Security
- Sanitize user input before rendering (DOMPurify for HTML)
- Validate image uploads (MIME type, size limits)
- Never commit .env files or secrets
- Use Row Level Security (RLS) for database access control
- Review all user-facing inputs for injection risks (SQL, XSS)
---
## Build Verification
**Do NOT run lint, type-check, tests, or build after every code change.** Only run the full verification suite **immediately before pushing** (pre-push). Running builds mid-development wastes time and tokens.
- **Never** leave failing tests, type errors, or lint errors in pushed code
- **Update** documentation if requirements or architecture change
### Pre-Push Verification (CRITICAL)
**Before pushing code, run ALL the same checks that CI runs.** This is the ONLY time to run the full verification suite. Do not run it earlier.
#### Check for Pre-Push Hook
Many projects have a `.husky/pre-push` hook that runs automatically. If present, it will block the push if checks fail.
#### If No Pre-Push Hook Exists
Manually run the full verification suite before pushing:
```bash
# Typical checks (adjust commands per project):
npm run lint # All workspaces
npm run type-check # TypeScript projects
npm run test:run # All test suites
npm run build # Ensure build succeeds
```
#### Why This Matters
- CI minutes cost money (GitHub Actions, etc.)
- Failed CI = wasted time waiting for feedback
- Local checks are faster than round-trip to CI
- Catches issues before they're visible to the team
#### Adding Pre-Push Hooks to Projects
If a project doesn't have a pre-push hook, consider adding one:
```bash
# .husky/pre-push (make executable with chmod +x)
#!/bin/sh
npm run lint && npm run type-check && npm run test:run && npm run build
```
---
## Living Documents
Some projects maintain living documents (`README.md`, `docs/project-story.md`) that stay current with the codebase. After merging a PR, check whether living documents need updating.
### Post-PR-Merge Check
After every PR merge, before moving to the next task:
1. Check if the repo has a `README.md` and/or `docs/project-story.md`
2. If they exist, evaluate whether the merged PR warrants an update (see criteria below)
3. If yes, update the relevant file(s) in 5-10 minutes - not a rewrite, just targeted additions
4. Commit the updates as part of the current branch or as a fast-follow
### When to Update README.md
Update when the PR:
- Adds or removes a package
- Changes extension capabilities or permissions
- Changes dev commands, build system, or verification steps
- Changes external APIs, services, or required permissions
- Changes pricing, payment flow, or deployment configuration
- Adds significant new test coverage
**How**: Find the affected section. Add/modify the relevant table row, code block, or bullet. Keep it factual and terse.
### When to Update docs/project-story.md
Update when the PR:
- Represents a notable architectural decision or reversal
- Fixes a non-obvious bug with an interesting root cause
- Introduces or eliminates a pattern across the codebase
- Represents a methodology change (tooling, workflow, agent coordination)
- Is part of a new epic or phase
- Has an interesting human decision behind it
**How**: Find the section closest to the PR's topic. Add 2-5 sentences in narrative voice. If no section fits, add a new subsection.
### When NOT to Update
- Typo fixes, dependency bumps, or documentation-only changes
- Changes already well-described by the PR title
- The living document already covers the topic and the PR doesn't change the answer
### Scope Discipline
Living doc updates should take 5-10 minutes, not 30. If an update requires re-reading the entire codebase, add a new subsection and move on.
rules/change-philosophy.md
# Change Philosophy: Elegant Integration
When making changes to an existing system, do not patch, bolt on, or work around. Instead:
**For each change, examine the existing system and redesign it into the most elegant solution that would have emerged if the change had been a foundational assumption from the start.**
## What This Means in Practice
- Before adding a feature, understand the full system it touches
- Ask: "If we had known about this requirement from day one, how would the system look?"
- Refactor toward that ideal rather than adding layers of special cases
- The result should look like it was always designed this way
## Do Not Preserve Backward Compatibility
Compatibility shims are how "bolted on" happens. The shim *is* the special case: a second code path, kept alive so an old shape can coexist with the new one. Keep enough of them and the system stops having a design and starts having a history.
When a change makes an old shape wrong, delete the old shape. Update every caller in the same change.
Delete rather than preserve:
- Deprecated aliases, wrappers, and re-exports kept "just in case"
- Readers for a format nothing writes any more
- Version flags with exactly one live value
- Adapters for callers that no longer exist
- `if (legacy)` branches nothing sets `legacy` for
- Dead options left in a signature so an old call site would still type-check
Migrate the callers instead. Compatibility is not free: it doubles the paths under test, hides which one is real, and defers a rename that costs minutes now and an archaeology session later.
### Where Compatibility Is a Real Requirement
Compatibility is a requirement when something outside this change depends on the old shape and cannot be updated with it:
- Published APIs, packages, or CLIs with consumers you do not control
- On-disk data, databases, or persisted state that already exists in the field
- Wire protocols between independently deployed peers
- Anything under a stated support or versioning commitment
Where compatibility is genuinely required, treat it as a requirement, not a reflex: name it in the spec, write the migration, and version the break deliberately. What this rule forbids is preserving the old shape out of caution when nothing depends on it.
### The Grep Test
Before keeping any compatibility path, find its callers:
```bash
grep -rn "old_function_name" src/ tests/ scripts/
```
If the only hits are the definition and the shim, delete both. **If you cannot name the caller, there is no caller.** "Something might use it" is a guess; the grep is the answer.
For a published surface, the callers are outside the repo - which is exactly why that case is a requirement instead of a reflex. Everywhere else, the repo is the whole world.
### Rationalizations
| You are about to say... | The reality is... |
|-------------------------|-------------------|
| "Something might still call the old one" | Grep. If nothing calls it, nothing calls it. Keeping it costs a permanent second code path to avoid a search that takes seconds. |
| "I'll deprecate it now and remove it later" | Later does not come. The deprecation comment becomes the documentation, and the shim outlives everyone who understood it. |
| "Removing it is a breaking change" | Internal code has no consumers to break. A change is only breaking if someone outside this change depends on it - name them or delete it. |
| "Keeping the old path is the safe option" | Two live paths is the unsafe option. Tests cover one, production takes the other, and nobody knows which. |
| "It's only a small alias" | Small aliases are what codebases fill up with. Each one is individually free and collectively the reason nothing can be renamed. |
| "Updating every caller is out of scope" | Updating callers is the change. Half a rename leaves the codebase worse than before it started. |
| "I'll leave the old param so existing calls still compile" | A parameter nothing reads is a lie the signature tells the next reader. Remove it and fix the call sites. |
## When to Apply
- Adding new features to existing code
- Fixing bugs that reveal a design flaw
- Integrating a new dependency or service
- Extending a data model
- Renaming or reshaping anything with callers inside the repo
## When NOT to Apply
- Trivial one-line fixes where the existing design is fine
- Time-critical hotfixes (patch now, redesign later)
- Changes to code you don't own or understand fully yet
- When the "elegant" solution would require rewriting half the codebase for a minor feature
- Surfaces with consumers outside this change (see "Where Compatibility Is a Real Requirement")
## Examples
**Bad** (bolted on):
```typescript
// Added special case for premium users
if (user.isPremium) {
// duplicate 40 lines of logic with slight variations
}
```
**Good** (redesigned as if foundational):
```typescript
// Tier-aware from the start
const config = getTierConfig(user.tier)
return processWithConfig(data, config)
```
The goal is not perfection - it's coherence. Every change should make the system feel more intentional, not more accidental.
## Red Flags
Stop and redesign if you catch yourself:
- Adding a branch, flag, or wrapper whose only job is keeping an older shape working
- Writing "deprecated" in a comment instead of deleting the thing
- Leaving a parameter, field, or export in place so old call sites still compile
- Duplicating logic with slight variations rather than making the difference a parameter
- Keeping a code path because "something might use it" without running the grep
- Calling a half-finished rename done because the alias makes it build
rules/latent-vs-deterministic.md
# Latent vs Deterministic Work Agent bugs often come from doing **deterministic work in latent space** — the model reasoning about something a script could compute exactly. Before acting on any step, classify it: - **Latent** — judgment, synthesis, open-ended choice. Needs the model. No single right answer. - **Deterministic** — same input always gives the same output. A short script can produce it exactly, faster, cheaper, and without risk of fabrication. Mixing the two is the bug. A script that tries to weigh tradeoffs is over-engineered; a model that adds timestamps in its head is wrong on the first DST boundary. ## Examples | Work | Class | Belongs in | |------|-------|-----------| | Is this PR ready to merge? | Latent | Model | | Summarizing an error log | Latent | Model | | Picking which test suite to run | Latent | Model | | Computing `now - event_time` in minutes | Deterministic | Script | | Converting UTC to local time | Deterministic | Script | | Grepping for a keyword across files | Deterministic | Script | | Counting lines, files, matches | Deterministic | Script | | Parsing a URL, a date, a path | Deterministic | Script | | Reading the contents of a known file | Deterministic | Tool (Read) | ## Red Flags That Deterministic Work Is Sneaking Into Latent Space Stop and reach for a script (or an existing tool) if you catch yourself: - Doing arithmetic in your head when the numbers came from data - Converting timezones, durations, or units manually - "Eyeballing" whether a regex matches without running it - Inferring file existence from naming patterns instead of checking - Counting items in a list without `wc -l` or equivalent - Remembering a value from earlier in the session instead of reading it fresh - Computing a hash, a diff, or a checksum mentally - Parsing structured output (JSON, CSV, TSV) by scanning the text Each of these is a deterministic computation. If it gets the wrong answer once, it will get the wrong answer again. Push it into code where the test can pin it. ## Why This Rule Exists Two classes of failure disappear when deterministic work moves to scripts: 1. **Hallucinated math and parsing.** The model is confident and wrong. Users trust the answer and act on it. 2. **Non-reproducible bugs.** Nothing is pinned, so the same task produces different output on different runs and no test can catch the drift. Pushing deterministic steps into code flips both: the answer is exact, and a unit test makes the skill's behavior regressable. ## The Loop When authoring a new skill, hook, or command: 1. List the steps the agent will perform. 2. Mark each step latent or deterministic. 3. For every deterministic step, write (or find) a script that produces the answer. 4. Have the skill invoke the script instead of describing the computation in prose. 5. Write a test that pins the script's behavior on a representative input. The script constrains the model. The test constrains the script. The skill is the contract between them. ## When to Leave Work in Latent Space Not every deterministic-looking task is worth extracting. Skip the extraction when: - The computation runs once in a whole session (cost of writing the script exceeds the win) - The inputs are themselves latent (e.g., "summarize, then count the key points" — the summary is the real work) - The script would be longer than the prose and no clearer The rule is: if the model is doing the same deterministic computation more than twice across sessions, that computation belongs in a script.
rules/completeness.md
# Completeness Principle: Boil the Lake When the cost of doing it fully is minutes and the cost of doing it partially is a follow-up PR, do it fully. Default to the complete implementation, not the 90% shortcut. **For each solution, ask: is there a meaningful delta between "the whole job" and "what I was about to ship?" If the delta is small, close it now.** ## Why This Matters Agent-assisted development compresses the cost of completeness. Work that used to take a team hours or days now takes minutes of agent time. The old tradeoffs - "ship the happy path, backlog the edges" - were rational when completeness was expensive. They are not rational when it is not. The result of the old tradeoffs is a codebase full of TODO comments, skipped tests, unhandled edge cases, and "we'll fix it in a follow-up" debt. A codebase that feels accidental. The alternative is shipping the whole thing the first time. ## Effort Compression Table | Task | Traditional team | Agent-assisted | |------|-----------------|----------------| | Write the happy path | hours | minutes | | Cover edge cases | hours-days | minutes | | Add tests for new code | hours | minutes | | Update related docs | hours | minutes | | Add input validation | hours | minutes | | Handle error states in UI | hours | minutes | When the agent-assisted column shows minutes, "defer to a follow-up" is no longer a reasonable default. It is procrastination with a name tag on. ## Completeness Rubric When presenting options or evaluating your own work, score completeness on a 1-10 scale: | Score | Meaning | |-------|---------| | **10** | All edge cases handled, tests cover new behavior, docs updated, error paths explicit. Nothing left for a follow-up. | | **8-9** | Happy path + known edge cases + tests. Minor polish deferred with explicit notes. | | **7** | Happy path works, tests exist, obvious edges handled. Non-obvious edges may slip. | | **5-6** | Happy path works. Tests partial or missing. Edge cases deferred. Follow-up PR required. | | **3-4** | Works for the demo case. Significant work deferred to one or more follow-ups. | | **1-2** | Sketch or proof of concept. Most work still ahead. | ### How to Use It - **Before reporting a task as done**: rate your work. If the score is below 8, either finish the job or explicitly flag what is deferred and why. - **When presenting options to the user**: include the completeness score so the tradeoff is explicit. "Option A: Completeness 10/10" vs "Option B: Completeness 7/10, ships in half the time" is a real choice the user can make. "Which option do you prefer?" without scores is a judgment call dressed as a question. - **On PRs**: if reviewing your own diff and noticing a 6, push the score up before asking for review. Do not outsource completeness to the reviewer. ## Anti-Patterns These are the rationalizations that precede shipping incomplete work. Recognize and reject them. | You are about to say... | The reality is... | |-------------------------|-------------------| | "I'll add tests in a follow-up PR" | The follow-up PR rarely happens. Write the tests now. | | "The happy path is done, edge cases can wait" | The edge cases are the bugs your users will report. Finish them now. | | "This is good enough for v1" | V1 ships to production. "Good enough" becomes "how it works." | | "The follow-up issue captures the rest" | Issues in the backlog are wishes, not commitments. Finish what is in front of you. | | "I don't want to scope-creep this PR" | Completing the feature you are already building is not scope creep. It is the scope. | | "Let me just ship the shortcut, it's done" | "Done" means complete. If it is a shortcut, it is not done. | | "The edge case is unlikely" | Unlikely edge cases in code you wrote today are certain bugs in production next month. | ## Boundaries Completeness is not gold-plating. Do not: - Add speculative features the task did not call for - Handle hypothetical edge cases that cannot actually occur - Refactor unrelated code while you are in there - Over-engineer for requirements that do not exist yet The rule is: **finish the job you are on**, not "expand the job to touch every file you can reach." If the task is "add input validation to the login form," finish it to 10/10 (all inputs, all error paths, tests, a11y). Do not also rewrite the auth middleware because it looked rough. Completeness governs the *depth* of the job, not the *breadth* of the design. It says handle every case the current requirements imply; it never says build for requirements that do not exist yet. The two run together: **the simplest implementation that fully meets the current requirements, finished completely, is a 10/10.** An extra abstraction layer nothing uses does not raise the score - it is unfinished work in a different direction. See `code-quality.md` > "Simplest Implementation That Fully Meets the Requirements." ## The Test Before claiming a task is complete, ask: 1. Are there edge cases I know about but did not handle? 2. Is there a test I know I should write but decided to skip? 3. Is there a doc or comment I know is now stale? 4. Did I leave a TODO in the code or a "will do later" in the PR body? If any answer is yes, the work is not complete. Either finish it now or state explicitly what is deferred and why. Completeness compounds. Every PR that ships at 10/10 makes the codebase feel more intentional. Every PR that ships at 6/10 adds a paper cut the next agent has to step around.
rules/receiving-code-review.md
# Receiving Code Review When a reviewer (human or agent) leaves feedback on your work, the goal is correct code - not social smoothness. Agreement without verification is a failure mode, not politeness. **Core mandate: verify before implementing, ask before assuming, technical correctness over social comfort.** ## Forbidden Responses Never open a reply with performative agreement. These phrases signal reflexive compliance, not thought: - "You're absolutely right!" - "Great point!" - "Good catch!" - "Thanks for catching that!" - "Of course, let me fix that right away." These are sycophancy. They substitute a social gesture for the work of evaluating whether the feedback is correct. The reviewer cannot tell from your agreement whether you verified the claim or just rolled over. ## Required Responses When feedback arrives, pick one of three responses. Nothing else is acceptable. ### (a) Technical acknowledgment State the fact of the change in technical terms. The diff is the thanks. > "Fixed. `getUserById` now returns `null` for missing rows instead of throwing." Not: "You're right, great catch! I fixed it." ### (b) Just fix and show in diff For unambiguous, correct feedback (typo, obvious bug, clear style violation), change the code and let the diff speak. No commentary required. ### (c) Reasoned pushback with evidence When the feedback is wrong, incomplete, or based on a misread of the code, push back. Cite specific lines, tests, or prior decisions. Respect the reviewer's authority without surrendering the technical argument. > "The caller at `src/api/users.ts:84` already wraps this in a `try/catch` that expects the throw. Changing the return shape would break that path. Proposing we keep the throw here and add the null-return variant as `getUserByIdOrNull` if needed." Reasoned pushback is not defensiveness. It is the work. ## Verify Before Implementing Before changing any code in response to feedback: 1. **Read the feedback completely.** Do not start editing after reading the first sentence. 2. **Restate the requirement** in your own words. If you cannot, you did not understand it. 3. **Verify the claim against the codebase.** Open the file. Read the lines the reviewer cited. Confirm the problem exists as described. 4. **Evaluate technical soundness.** Does the proposed fix work? Does it break other callers? Does it conflict with an earlier architectural decision? 5. **Respond** with one of the three required responses above. 6. **Implement one item at a time**, with tests. A reviewer can be wrong. A reviewer can be right about the symptom but wrong about the cause. A reviewer can be correct but missing context that changes the right fix. Verification is how you find out. ## YAGNI Check Before implementing a suggestion to add a feature, endpoint, handler, option, or abstraction: ``` grep -r "suggested_feature_name" src/ tests/ ``` If nothing calls it, push back. "Implementing this properly" on a never-used code path violates YAGNI. The right response is often: > "Grepped for callers of `X` - none exist in the current codebase. Holding off until a real consumer appears. Happy to revisit if you have a use case in mind." Speculative completeness is not completeness. It is scope creep disguised as thoroughness. ## Unclear Items Protocol Partial understanding breeds wrong implementation. If the review has multiple items and you understand some but not all, stop. Do not implement the items you understood while planning to "ask about the rest later." The items you did not understand may change how the understood items should be done. State explicitly what is clear and what is not: > "I understand items 1, 2, and 4. For item 3, I need clarification: are you asking to remove the retry entirely, or switch it from exponential backoff to fixed delay? For item 5, which of the two interpretations in the thread applies here?" Then wait. Do not guess. ## Respect Reviewer Authority, Push Back on Inaccurate Reads Reviewer authority is real. The reviewer may have context you lack, design decisions you were not part of, or downstream concerns you cannot see. Default to charitable interpretation: assume the feedback is correct until verification proves otherwise. But authority does not make every claim accurate. When you have verified the feedback is wrong, say so with evidence. Silently implementing a broken change because a reviewer suggested it is worse than pushing back. It wastes the reviewer's time on a merge that will be reverted, and it teaches the reviewer that their suggestions do not need to be correct. Push back is appropriate when the feedback: - Misreads what the code does - Would break an existing test or caller - Violates YAGNI or adds unused surface area - Conflicts with a documented architectural decision - Is based on a pattern that does not apply to this codebase Accept gracefully when the reviewer counter-argues and is correct. The goal is the right code, not winning. ## Anti-Patterns | You are about to say... | The reality is... | |-------------------------|-------------------| | "You're absolutely right!" | You have not yet verified the claim. Verify first, then respond in technical terms. | | "Great point, let me fix that right away." | Speed of agreement is not a virtue. Slow down and read the cited lines. | | "I'll just apply the suggested diff." | Applying a diff you did not evaluate is the reviewer writing the code, not you reviewing it. | | "I understand most of the feedback, I'll start on what I got." | Partial understanding of a review is worse than no start. The items you skipped may reframe the items you did. | | "I don't want to argue with the reviewer." | Pushing back with evidence is not arguing. Silently shipping wrong code is. | | "They probably know something I don't." | Maybe. Ask. Do not implement on the assumption. | | "It's a small suggestion, not worth the friction." | Small suggestions are where codebase drift accumulates. If it is wrong, say so. | ## Red Flags Stop and reconsider if you catch yourself: - Opening a reply with "You're absolutely right" before reading the cited code - Applying a suggested diff without running the affected tests - Adding a new endpoint, handler, or abstraction the reviewer suggested without grepping for callers - Implementing 3 of 5 review items while planning to "ask about the other 2 later" - Agreeing with a suggestion that contradicts a decision from a prior PR - Feeling relief that the review was short enough to "just fix quickly" - Reaching for "Thanks for catching that!" instead of the diff ## The Test Before posting a reply to a code review, ask: 1. Did I read every cited file and line? 2. Can I restate the feedback in my own words? 3. Did I verify the claim is accurate in this codebase? 4. If I am agreeing, did I verify - or am I just agreeing? 5. If I am pushing back, did I cite specific evidence? 6. If I am unclear on any item, did I ask before implementing anything? If any answer is no, the reply is not ready. Fix the gap before posting. Code demonstrates you listened. The diff is the thanks.
rules/in-the-circuits.md
# In-the-Circuits: Verifiable-Domain Self-Classification Before starting any task, name the circuit you are in. One sentence. This sets confidence mode, review cadence, and escalation threshold for everything that follows. > "If you're in the circuits that were part of the RL, you fly. And if you're in the circuits that are out of the data distribution, you're going to struggle and you have to figure out which circuits you're in in your application." > — Andrej Karpathy, Sequoia Capital, 2026-04-29 ## The Classification | Circuit | What it means | How to proceed | |---------|--------------|----------------| | **In-circuit** | The task sits in a domain where frontier models have dense RL training: code, math, refactoring, testing, structured data transformation. Output quality is high and verifiable. | Ride the wave. Trust output. Move at full speed. Standard verification applies. | | **Out-of-circuit** | The task touches taste, UX copy, novel architecture, brand voice, domain-specific reasoning the labs did not RL on, or any domain where there is no ground-truth verifier. Output may be fluent but unreliable. | Slow down. Human-in-loop. Expect to fine-tune or escalate. Flag explicitly before proceeding. | If the circuit is unclear, treat it as **out-of-circuit**. The cost of unnecessary caution on an in-circuit task is low. The cost of overconfidence on an out-of-circuit task is high. ## The Protocol At task start, write one sentence: ``` Circuit: in-circuit — refactoring the auth middleware to extract token validation. ``` or ``` Circuit: out-of-circuit — writing onboarding copy for a healthcare app. Flagging for human review. ``` That is the entire protocol. No elaborate analysis. If you cannot name the circuit in one sentence, it is out-of-circuit. ## Examples | Task | Circuit | Reason | |------|---------|--------| | Implement a CSV parser | In-circuit | Code; dense RL training; output is mechanically verifiable | | Refactor this function for clarity | In-circuit | Code; RL'd on refactoring patterns; output is diff-reviewable | | Write a failing test for this bug | In-circuit | Testing; pass/fail is a verifier | | Convert this schema to TypeScript types | In-circuit | Structured transformation; types are checkable | | Fix this SQL query | In-circuit | Code; query result is verifiable | | Name this product | Out-of-circuit | Taste; no verifier; labs not RL'd on brand naming | | Decide whether to use Postgres or DynamoDB | Out-of-circuit | Novel architecture choice; context-dependent; no ground-truth verifier | | Write empathetic onboarding copy for a healthcare app | Out-of-circuit | UX copy + healthcare domain knowledge; taste-dependent; high stakes if wrong | | Choose the right color palette for this brand | Out-of-circuit | Aesthetic taste; subjective; no verifier | | Summarize this legal contract | Out-of-circuit | Domain-specific (legal); hallucination risk is high-stakes | ## When to Apply Apply this classification at the start of every non-trivial task. "Non-trivial" means anything that will take more than one tool call or produce output the user will act on. ## When NOT to Apply Do not apply it to: - Single-line changes with obvious correct form (no judgment involved) - Tasks where the circuit is obvious and the classification would be noise (e.g., every `git status` call does not need a circuit announcement) ## Relationship to Neighboring Rules **`confusion-protocol.md`** — A mid-task escape hatch when you hit an architectural fork and cannot proceed without a decision. In-the-circuits is a pre-task classification, not a mid-task interrupt. They are complementary: classify first, then if you hit a fork while executing, invoke the confusion protocol. **`verification.md`** — Evidence is required either way. Being in-circuit does not exempt output from verification. It only tells you the output is likely trustworthy enough to verify rather than discard. Out-of-circuit output should be verified AND reviewed by a human before acting on it. **`latent-vs-deterministic.md`** — Different axis. The latent/deterministic split asks: *who should compute the answer* (model vs. script)? The in-circuit split asks: *has the model been RL'd on this domain*? A task can be latent (needs the model) and out-of-circuit (model is unreliable here) at the same time. Example: "choose a product name" is latent (no script can do it) and out-of-circuit (model is unreliable at naming). Both rules apply independently. ## Anti-Patterns | You are about to say... | The reality is... | |-------------------------|-------------------| | "The model is generally smart, it will figure this out" | General intelligence does not equal domain RL. Fluency is not reliability. | | "The copy looks good, ship it" | Out-of-circuit output looks fluent. Fluency is not accuracy or appropriateness. | | "I'll classify mid-task if something feels off" | By then you have already committed to an approach. Classify before you start. | | "This is mostly code, so it's probably fine" | "Mostly code" that also involves novel architecture or domain-specific logic is mixed-circuit. Name it. | | "The user can review it later" | That transfers the classification burden to the user without warning them it exists. Name the circuit; let them decide how much to trust. | ## Red Flags Stop and reclassify if you catch yourself: - Outputting architectural recommendations with the same confidence as a function refactor - Writing UX copy without flagging that taste-based output needs human sign-off - Treating "it compiles" as evidence that out-of-circuit reasoning was correct - Making a domain-specific judgment (legal, medical, financial, brand) without noting the circuit - Presenting options in an out-of-circuit domain without flagging that none of them may be correct
rules/spec-is-the-artifact.md
# Spec Is the Artifact The spec is the durable artifact. Code is regenerable output. > "I actually don't even like the plan mode... You have to work with your agent to design a spec that is very detailed and maybe basically the docs and then get the agents to write them and you're in charge of the oversight." > — Andrej Karpathy, Sequoia Capital, 2026-04-29 When agents can write code from a spec in minutes, the spec becomes more valuable than the code. The code can be deleted, regenerated, or rewritten. A good spec cannot — it encodes decisions, constraints, and intent that took time to discover. ## The Principle Write the spec before the code. Review the spec before the code runs. When behavior diverges from spec, fix the spec first, then bring the code into alignment. The spec is the source of truth. Code without a spec is behavior without intent. Behavior without intent drifts. ## Sizing Guidance Not every task needs an xplan. Use judgment: | Work | Spec overhead | What fits | |------|--------------|-----------| | Typo fix, one-line config change | None needed | Comment in commit message is enough | | Single-PR feature, small refactor | One-page spec | Problem, deliverables, constraints, done-when | | Multi-PR feature, architectural change | Full spec | Problem, deliverables, constraints, done-when, non-goals, open questions | | New project, major system redesign | xplan | Full research + plan + reviews + execution phases | The one-page spec for a single PR is not bureaucracy. It is the document you would write to explain the work in a PR description — written before the code, not after. ### One-Page Spec Structure A spec does not need to be formal. It needs four things: 1. **Problem** — What is broken or missing? Why does it matter? 2. **Deliverables** — What will exist when this is done that did not exist before? 3. **Constraints** — What must not change? What approaches are off the table? 4. **Done-when** — How will we verify the work is complete? That is the minimum. The rest is optional. ## Drift Protocol When a deployed behavior diverges from its spec: 1. Update the spec to reflect the correct intended behavior 2. Then bring the code into alignment with the updated spec Never silently update behavior without updating the spec. The spec is the record of why things work the way they do. A codebase whose behavior has drifted past its spec is a codebase that no future agent can reason about safely. ## When to Apply - Starting a new feature, however small - Starting a refactor that touches more than one file - Starting any change where "done" is not self-evident from the task description ## When NOT to Apply - Obvious one-line fixes (typo, missing semicolon, wrong constant value) - Changes that are fully described by the failing test or error message - Exploratory spikes the user explicitly plans to throw away If in doubt, write the spec. A ten-line spec takes two minutes. Reworking a feature because the intent was unclear takes hours. ## Anti-Patterns | You are about to say... | The reality is... | |-------------------------|-------------------| | "I'll write the spec after I see what the code looks like" | A spec written to match code that already exists is a description, not a design. It cannot catch mistakes because the mistakes are already in the code it is describing. | | "The PR description captures this" | PR descriptions are tied to the diff, not the behavior. They disappear into git history. A spec lives where the code lives and stays current. | | "I'll just put this in a comment" | Comments describe what the code does at the line it appears on. They do not describe the problem, the constraints, or why the design tradeoffs were made. | | "The agent will figure out the spec as it writes the code" | The agent writing both the spec and the code in one pass with no human review of the spec in between is vibe coding with extra steps. The spec review is the gate. Skip it and you have skipped the oversight Karpathy is describing. | | "This is a small task, a spec is overkill" | A one-page spec for a single PR takes two minutes. The alternative is a follow-up PR explaining why the first one did the wrong thing. | ## Relationship to Neighboring Rules **`xplan`** is the heavyweight variant of this principle. xplan runs research, planning, multi-agent review, and structured execution. Use xplan when the scope warrants it. Use a one-page spec for everything else. The principle is the same at every scale: spec first, code second, human reviews the spec before the code runs. **`completeness.md`** defines a 10/10 rubric for done work. The 10/10 rubric assumes there is a target to be complete against. The spec is that target. Without a spec, "done" is undefined and the rubric cannot be applied.
rules/menu-gen-test.md
# Menu-Gen Test: Apps That Shouldn't Exist Before committing to build anything — a new app, a script, a feature, a workflow — ask one question first: > **Could this be a single prompt + multimodal call instead of an app/script/feature? If yes, why are we building anything?** If you cannot answer "why," stop. The build might be unnecessary. ## The Karpathy Confession Andrej Karpathy built Menu Gen: an OCR webapp on Vercel that takes a photo of a restaurant menu, calls an image generator for each item, and re-renders the menu with pictures. Then he saw the Software 3.0 version: hand the photo to Gemini, say "use Nano Banana to overlay the items," and receive the annotated image directly — one multimodal call, no app. > *"All of my menu gen is spurious. It's working in the old paradigm — that app shouldn't exist."* > — Andrej Karpathy, Sequoia Capital, 2026-04-29 The app was not wrong or poorly built. It was answering the right question in the wrong paradigm. The new question is: does the build need to exist at all? ## The Forcing Question At intake — before research, before planning, before any implementation — answer this in one paragraph: > Could this be accomplished with a single prompt and a multimodal/agentic call? If yes, what is the specific reason an app, script, or persistent system is still needed? Valid reasons an app still needs to exist: - Runtime injection into another system (e.g., a Chrome extension that modifies page DOM) - Persistent server state shared across users or sessions (e.g., a multi-tenant SaaS with a database) - Recurring background automation that cannot be triggered manually each time - Distribution to non-technical users who cannot operate a prompt Not valid reasons: - "The prompt would be long" — long prompts are fine - "We need a UI" — many things that feel like they need UI are just a prompt with output rendering - "The logic is complex" — complex logic can live in an agent, not an app ## Dissolvability Score If the answer is not obvious, score it: | Score | Meaning | |-------|---------| | **0** | Clearly needs to exist. Has runtime injection, persistent multi-user state, or distribution requirements. | | **2-3** | Mostly needs to exist, but some parts could be dissolved into prompts. Consider which parts. | | **5** | Could be a single multimodal or agentic call right now. Strong case for not building. | | **4** | Borderline. The app adds enough structure or UX that it is worth building — but name the specific reason explicitly. | A score of 4 or 5 is not a hard stop. It is a flag. Name the reason you are building anyway. If you cannot name it, the build is not justified. ## Examples **Should not exist (score: 5)** Menu Gen — OCR + image gen webapp. One Gemini + Nano Banana call does the same thing. A script that fetches a URL, runs it through a prompt, and emails the summary on a schedule — if it runs manually each time and the user already has access to a model, this is a prompt, not a script. **Needs to exist (score: 0)** A Chrome extension that injects a dark-mode CSS overlay into every page the user visits. It runs inside the browser at runtime, on arbitrary pages the user navigates to. No prompt can do this. A multi-tenant habit-tracking SaaS with user accounts, persistent streaks, and push notifications. It requires a database, a server, and distribution to users who interact via a native UI. ## When to Apply Apply this check at every project intake: `/xplan`, `/research`, `/ideate`, or any other scoping exercise before research and planning begins. Do not apply it to: - Work already in progress (this is an intake check, not a retroactive audit) - Incremental features on an existing system where the system's existence is already justified - Purely exploratory research with no build decision yet ## Relationship to Build Decisions This check does not reject ideas. It forces explicit justification before committing resources. The answer "this needs to exist because users cannot operate a raw prompt" is a complete and sufficient answer. The problem is building without asking the question at all.