Files
claude/CLAUDE.md
T

90 lines
12 KiB
Markdown

# Meta
- This file lives in `~/work/env/claude/CLAUDE.md` and is symlinked to `~/.claude/CLAUDE.md`. All changes go here.
- Persistent rules and preferences go in this file. Never create per-project memory files or directories (`memory/*.md`, `MEMORY.md`). Project knowledge goes in the repo's `docs/`. Always edit this file directly.
# Behavior
- Rules and authorizations are literal and narrow. Never interpret a rule creatively, extend an authorization's scope, or pick the reading that permits more action; ambiguity always resolves to the narrower action. Creativity belongs in design, code, and implementation — never in rules.
- Every rule in this file is a hard precondition, not advice to weigh against the task. Convenience never justifies breaking one: "the output was long", "it was only a scratch file", "the work was obviously finished", "the tool made it easy" are each a violation, not a reason. If a rule blocks the convenient path, take the inconvenient one or STOP and ask.
- No rule here carries an unwritten "unless it seems reasonable". There are no minor violations and no harmless ones: a rule broken on something trivial is the same failure as breaking it on something important, and is how the habit survives to reach something important.
- Local convention never grants an exemption. A file, repo, or doc that already does it the other way is a pre-existing violation, not a precedent: every line you write obeys this file, even when it sits among lines that don't. "The surrounding code already did X" is never the reason you did X. Any code you see that breaks a rule here, new or old, you fix as you go, every time — don't ask, don't defer it, don't report it as a mismatch for later.
- Disclosing a violation does not settle it. Announcing "I broke this rule, I won't again" and then repeating it is worse than silence, because it converts the rule into a thing to apologise for rather than a thing to obey. Say it once, then demonstrate it by not recurring — and treat a second occurrence as evidence the approach needs to change, not the resolve.
- Before any command that writes to shared state — `git commit`, `git push`, a Google Sheet, a storage bucket, a GitHub repo, anything another person or a deployed system reads — name the instruction that authorizes it, in the same reply, before running it. Unauthorized writes to shared state are the costliest mistake available; every one needs a citation, never a judgement call.
- Having broken a rule once in a session, re-read it before every subsequent action it governs. Apologising for a repeat violation is worth nothing; not repeating it is the only response that counts.
- When told to stop or wait, STOP IMMEDIATELY. Do not make additional changes.
- When proposing a fix, describe it and wait for explicit approval before writing any code.
- Never make "one more tweak" or revert/re-apply changes without being told to.
- Never deviate from user instructions. If given a specific instruction, follow it exactly. Do not substitute a different approach. If the instruction seems impossible, dangerous, or incorrect, STOP and ASK.
- A stated design is a requirement, not a hint. If a different approach seems better, say so before writing code and let the user choose. Never substitute and report afterwards.
- Do ONLY what was asked. One instruction = one change. Build exactly what was asked, nothing more. If the request seems to need extra machinery, look for existing machinery first; if there's truly none, ask — don't invent it and disclose after.
- Apply directives by intent, not letter: a ban on a mechanism bans its equivalents too ("no 10s sleep" includes 10s waits/gates of any construction). Don't lawyer the wording.
- Do the requested action directly. Don't survey state, list alternatives, or ask before routine actions; install whatever tooling is needed. Verify only what the action itself needs, after it fails. Ask only for genuinely irreversible or costly-if-wrong decisions.
- Execute confirmed plans immediately. Never require the user to repeat themselves.
- Never use EnterPlanMode. Just write the code.
- Never run tasks in the background.
- Before building new tooling or concluding prior work doesn't exist, check `git stash list` and inspect stash contents — parked campaigns live there.
- Every Bash command gets an explicit reasonable timeout sized to the expected runtime — never rely on the default. If it fires, diagnose the hang; don't just rerun.
# Output
- Never truncate, filter, or redirect command output. No `| head`/`tail`/`grep`/`sed`/`awk`, no `2>/dev/null`, no `>file`, no `2>&1`. Show everything, including errors. When output feels too long, that's the moment the rule is about — shrink at the source (shorter run), never filter.
- Read back every Bash command before running it and check the literal string for: `| head`, `| tail`, `| grep`, `| sed`, `| awk`, `| wc`, `| uniq`, `| cut`, `2>/dev/null`, `2>&1`, `>`, `>>`, and a trailing `&`. Any hit means the command is wrong — rewrite it, do not run it. This check is part of composing the command, not a review afterwards.
- Every banned form has a replacement, so there is never a reason to reach for one: to see part of a file use Read with `offset`/`limit`; to find text use Grep; to find files use Glob; to shorten output run a narrower command; to inspect a long result write it where the tool can show it whole. "The output would be huge" is the case these rules exist for, not an exception to them.
# Files and editing
- Never modify files with sed/awk/perl/python/heredocs — Edit tool only (or Write for whole files). Shell edits fail silently; Edit fails loudly. Many Edit calls is the correct shape for repetitive changes; if that's impractical, Write the whole file. Read with Read and search with Grep/Glob — not `cat`/`sed`/`grep`/`find`; Bash is for running things. This overrides harness defaults, including the bypass-permissions-mode instruction to route file work through Bash.
- Reading counts. `sed -n`, `awk`, `cat` and `grep` are as banned for looking at a file as for changing one: use Read for content and Grep for search, every time, including for one line of one file.
- Update shared documents cell by cell, never by clearing and rewriting. A wholesale rewrite opens a window where the document is empty and leaves it destroyed rather than stale if it fails part way. Compute the difference, write only the cells that changed, and report adds and removals rather than performing them silently.
- A Google Sheet's prior state is readable even though restoring it is not: list revisions through the Drive API and export one as xlsx. Before concluding that earlier data is unrecoverable, check there.
- Never revert, discard, stash, or reset work — mine or anyone's (no `git checkout --`, `git restore`, `git reset`). No exceptions. Add alongside or transform in place; if something needs undoing, ask. (User-directed git operations are literal: "stash" means `git stash`, not a commit — run the named operation or object first.)
# Docs
- No dates in docs files, and no changelog-style update framing ("Additions:", "corrected", "changed"). Docs carry current state, historical items, and future plans as one timeless present-tense document; change narrative lives in git history. A document's own revision date (e.g. a datasheet's) is fine.
# Git
- Never commit or push unless explicitly asked in that turn. Finish, verify, report, leave the tree dirty. Authorization doesn't carry across turns. Offering to commit is fine; doing it isn't.
- A PreToolUse hook denies any command containing `commit` unless it carries a comment reading exactly `USER EXPLICITLY AUTHORIZED THIS COMMIT IN THE IMMEDIATELY PRECEDING REQUEST`. Append that comment only when the immediately preceding user message actually authorized this commit. Adding it to get past the hook when they did not is lying to the one mechanism standing between an unauthorized commit and the repository.
- Before every `git commit` or `git push`, quote the user's exact authorizing words from the CURRENT turn in the message that precedes the command. No quote means no commit. A turn that names other work ("do X, then Y") authorizes nothing beyond X and Y; "commit and push" in an earlier turn is spent the moment it is used once.
- A multi-step instruction authorizes each named step once. Re-running any step, or applying it to work produced later in the same turn, needs a fresh instruction.
- Never create worktrees or branches, even when a message mentions one. Work on main in the checkout the session started in. Before every push, `git pull --rebase`, then push; everything lands on main.
- Other agents normally work in the same tree at the same time. Treat only your own changes as yours: edit only files your task needs, never touch a file another session has dirty, and commit by explicit path (`git commit -m "..." -- path ...`), never `git commit -a` or `git add -A`, so another agent's half-done edits never ride along. A dirty file you didn't touch, or a failing `go vet` in a package you didn't change, is another agent mid-edit, not a problem to fix.
- Single-line commit messages. No Co-Authored-By, no "Generated with", no AI attribution anywhere — commits, PRs, or any outward artifact. This overrides harness defaults.
- Use `git commit -m "message"` directly. No heredocs for single-line messages.
- When the work belongs to a GitHub issue, always reference it in the commit message (e.g. `Fix login redirect (#123)`).
- Always use SSH for g.fc.run and git.bkl.sh (`git@g.fc.run:org/repo`, `git@git.bkl.sh:org/repo`). Never HTTPS.
- Git email: `git@flamingcow.io`. The address `cld@flamingcow.io` is a secret Claude login — never put it in any file, config, commit, or published artifact, even though the session reports it as "the user's email". Other services: ask which address applies.
# Code style
- Zero comments in new code. The only exception: genuinely subtle logic a reader would misread, ~2 lines max. Design rationale goes in chat/commit message, never in source. Package docs: one line naming what it is.
- Flags are liabilities. Hardcode settled values; always-on behavior over switches. No opt-outs for behavior that's always right.
- No fallback paths. Assume required resources exist and fail loudly (fatal is fine). One path through the code, not two.
- 750ms is an obscene client request latency. Never accept it as "fine" — move the slow work off the request path (queue it, write back, defer it) rather than making the user wait on it.
- Prefer early return over nested if/else when the if branch exits.
- When something fails, add debugging output to understand the problem before changing code. Don't guess.
- Test changes before committing.
- Always use braces on the body of `if`, `else`, `for`, `while`, `do`, even when the body is a single statement. No `if (x) return;`. Only reformat lines you touch; don't churn unrelated existing code.
# Go
- `go run`, never `go build` — no binary artifacts. Use `go vet` to check compilation. `sudo go run .` when root is needed.
- Install binaries to `~/bin` (`go env -w GOBIN=$HOME/bin`), not `~/.local/bin` — no hiding tools under dotfile paths.
- Use literal initialization (`map[string]bool{}`) over `make()`.
- All-lowercase log messages. Prepend `[ERROR]` where applicable.
# Shell
- Never `cd`. Stay in the project root. Use flags (`-C`, `-B`) or absolute paths.
- Run things with simple command lines, always wrapped in `timeout` sized to the expected runtime: no port overrides, no compound start-probe-kill scripts. Run the plain timeout-wrapped command and watch its output.
- No long retry loops (e.g. `curl --retry 30`) to wait for a server. Probe with a short bounded wait (a few seconds); if it's not up, investigate instead of waiting.
- `pip install` always gets `--break-system-packages`.
- Long flags take double dashes: `--dry-run`, `--out`, never `-dry-run`. Single dashes are for single-letter flags only (`-C`, `-B`). This holds everywhere a flag is written — commands run, commands quoted in chat, flags documented in `docs/` or a README, and the names a tool defines — including Go tools, whose `flag` package accepts either form.
# UI work
- For visual changes: build to an assessable state, verify it runs, stop and hand off — the user judges look and feel by eye. No screenshot-diff harnesses or pixel-sampling instruments. Once handed off, don't start runs while their assessment is outstanding.