Every .go file (non-test, non-generated) starts with a contiguous block:
// CLAUDE:SUMMARY One sentence. The single responsibility of this file.
// CLAUDE:DEPENDS pkg/path1, pkg/path2
// CLAUDE:EXPORTS PublicName1, PublicName2- CLAUDE:SUMMARY — exactly one sentence. Starts with a noun or verb. No period at end.
- CLAUDE:DEPENDS — local imports only (not stdlib, not
modernc.org/sqlite). Relative to module root. Empty line = no local deps. - CLAUDE:EXPORTS — public names actually imported by other packages. Not everything exported — what's used. Verify with
grep -rn "PublicName" --include="*.go" ../ | grep -v <current_dir>.
Line 1 of the file, before the package declaration and before any //go:build directives. The block must be contiguous (no blank lines between annotations).
// CLAUDE:WARN Takes mu.Lock — blocks all Search. Mutates: flatVecs, cache, centroid, nextID.
func (idx *Index) Insert(vecs [][]float32, ids [][]byte) error {Add a WARN above a function if it:
- Takes a lock and its scope (what other functions are blocked)
- Mutates state beyond its return values (struct fields, globals, cache)
- Silently returns on error (no log, no error returned)
- Launches a goroutine (lifecycle implications)
- Has call-order constraints (must be called after X, before Y)
- Touches network/filesystem/shared port
- Contains counter-intuitive decisions that a naive developer would "fix"
- Pure getters, simple helpers, no side effects
- Behavior obvious from the function signature
- TODOs, optimization ideas, or godoc content
One line. Structure: <what it does that's dangerous>. Optional: <what it mutates>.
Examples:
// CLAUDE:WARN Takes mu.Lock; mutates localHandlers map.
// CLAUDE:WARN Blocking — must run in goroutine. Silently ignores poll errors.
// CLAUDE:WARN Launches goroutine — must call Close() to drain buffer.
// CLAUDE:WARN Network + filesystem I/O. Sleeps 200ms after Close() — required for QUIC FIN delivery.
// CLAUDE:WARN Strategy "noop" returns (nil, nil) silently — no error, no data. Intentional for feature flags.Each active directory contains a CLAUDE.md file. 40-60 lines max.
# <service-name>
Responsibility: <one sentence>
Module: <go module path>
Depends on: <list>
Depended on by: <list>
## Key files
| File/Pattern | Role |
|...
## Build & Test
<commands>
## Invariants
- <rule 1>
- <rule 2>
## Known traps
- <trap 1>
- <trap 2>
## DO NOT
- <forbidden action 1>
- <forbidden action 2>Line 1 of every local CLAUDE.md:
> **Protocol** — Before any task, read [`../CLAUDE.md`](../CLAUDE.md) §Research protocol.
> Required commands: `Read <dir>/CLAUDE.md` → `Grep "CLAUDE:SUMMARY"` → `Grep "CLAUDE:WARN" <file>`.
> **Forbidden**: Bash(grep/cat/find) instead of Grep/Read. Never read an entire file as first action.The "Forbidden" line is essential — without it, agents acknowledge the protocol but still default to Bash fallbacks requiring permission prompts. For nested directories (e.g., scripts/deploy/), adjust the relative path: ../../CLAUDE.md.
Auto-generated file at the repo root. One line per annotated file:
path/to/file.go | SUMMARY text | EXPORTS list
Generated by scripts/generate-index.sh. Never edit by hand.
Using Claude Code's dedicated tools (auto-approved, zero permission prompts):
# All summaries in a service
Grep "CLAUDE:SUMMARY" service/ --include="*.go"
# All warnings in a file
Grep "CLAUDE:WARN" path/to/file.go
# Files missing annotations
Glob "service/**/*.go" # exclude *_test.go, *.pb.go, *_templ.go
# Compare with Grep "CLAUDE:SUMMARY" results
# Non-standard annotations (cleanup targets)
Grep "CLAUDE:" service/ --include="*.go"
# Filter out CLAUDE:SUMMARY, CLAUDE:DEPENDS, CLAUDE:EXPORTS, CLAUDE:WARN