4.4 KiB
Process Lessons
Start reporting/read-only scripts without set -e
Debugging set -e failures in scripts that aggregate data from multiple sources (git repos, file stats, etc.) consumed significant time — the script worked in isolated tests but failed silently on real data. Begin without -e and add it only for scripts that perform destructive actions where fail-fast is critical.
Spec-driven testing catches real bugs early
The spec → implement → test workflow caught real bugs during development (grep flag parsing, local keyword misuse, binary detection false positives). Writing tests that exercise dryrun against spec expectations is an effective pattern for this project.
Use cat -A to diagnose invisible character issues
When a file looks correct but tooling rejects it, cat -A reveals non-printing characters (e.g., M-bM-^@M-^T for em dashes that appear identical to regular dashes). Essential for debugging YAML frontmatter, config files, and any context where encoding matters.
Use git diff --numstat for binary detection instead of file
The file command is unreliable for distinguishing binary from text files (marks shell scripts as "executable"). git diff --numstat shows - for binary files and is more reliable since git already has its own binary detection heuristics.
Verify harness capabilities before designing workarounds
Before committing to workarounds for something the harness "doesn't support", verify the assumption. A 30-second check via a guide agent can prevent building multiple unnecessary workarounds. Pattern: if you're about to design around a limitation, confirm it's actually a limitation first.
Check existing references in old scripts before extending
When extending an existing script, verify that its current references actually work in the live environment. Broken references can be masked by never running certain code paths. Tests catch these immediately.
Guard interactive read with [[ -t 0 ]] for testable scripts
For bash scripts that are both interactive and testable, wrap every read call with [[ -t 0 ]] and provide a default value for non-TTY contexts. This allows the same code path to work interactively or in dryrun/test mode without set -e blowups.
File-based result passing keeps driver context lean
When subagents or background processes produce non-trivial results, write them to files and only Read into context when actually needed. This unifying pattern (sentinel files, bg-model-call, container agent outputs) prevents the driver's context from bloating with data it may never use.
Always Read a file with the Read tool before calling Edit
The Edit tool tracks which files have been explicitly read via the Read tool — viewing a file via Bash (cat, etc.) does not count. An Edit attempt on a file seen only through Bash output is rejected. When planning multiple edits, batch parallel Read calls first, then parallel Edit calls.
/context "Memory files" aggregates two distinct systems
The "Memory files" category reported by /context combines project CLAUDE.md instructions and auto-memory MEMORY.md. They have different purposes (project conventions vs cross-session learnings) and live in different places. When auditing context size, check both rather than assuming a single source.
Grep all consumers before removing or keeping a launcher field
Before keeping an interactive prompt or launcher-written env var, grep every consumer across the filesystem (grep -r CLAUDE_TIME_HORIZON ~). Two vars (CLAUDE_TIME_HORIZON, CLAUDE_PROVIDER) accumulated in active-mode.env unused; auditing consumers revealed the dead code and pointed to every downstream file needing a matching edit (skill templates, statusline).
Resolved: claude-profile ↔ CLAUDE.md / statusline integration questions
Open questions from the 2026-04-12 design session are now resolved: (1) CLAUDE.md session-start reads active-mode.env and auto-selects the project from cwd or CLAUDE_PROJECT, skipping the interactive picker; (2) the status-line script is bash at ~/.claude/status/statusline.sh (not in any git repo, changes are live immediately); (3) mode switching became the /switch-mode slash command / switch-mode skill, not a hook-matched literal phrase. Still open: MiniMax M2 agentic-CLI availability and the token-budget comparison for the inverted architecture (tracked in FUTURE.md, not memory).