# 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).