Add memory files, reflection state, and update docs

Memory files for decisions, bash gotchas, and process lessons.
Updated MEMORY.md index and README.md with new scripts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Paul O'Reilly
2026-03-17 11:14:44 +13:00
parent 87f7bfb7cd
commit 22db5514f8
10 changed files with 167 additions and 1 deletions

View File

@@ -0,0 +1,29 @@
# Session Log — 2026-03-13
## Summary
Created the `small-scripts` project — a spec-driven utility script collection with dryrun support and automated testing. Implemented the first script `git-status-report` which recursively scans directories for git repos and reports uncommitted changes with character-level diffs and remote sync status.
## Decisions
- Decision: Use OpenSpec format for all script specifications — Rationale: Testing agent-driven development; specs define purpose, usage, behaviour, dryrun behaviour, edge cases, and examples
- Decision: Every script must support `--dryrun` / `-n` — Rationale: Enables testing via dryrun without side effects; tests validate spec compliance through dryrun output
- Decision: Removed `set -e` from git-status-report, kept `set -uo pipefail` — Rationale: `set -e` caused silent failures in complex pipeline/subshell chains; for a reporting tool, explicit error handling is safer than errexit
- Decision: "No remotes" and "detached HEAD" don't count as dirty — Rationale: These are informational states, not divergences; "(no remotes)" only shown when repo already has local changes
- Decision: Project hosted under `skynet` org on Gitea — Rationale: AI-focused project (agent-driven development testbed)
## Gotchas Discovered
- **[bash]** Symptom: `set -euo pipefail` caused silent script termination with no output during complex loops with command substitutions and subshell calls — Fix: Removed `set -e`, kept `set -uo pipefail`. Reporting tools don't need errexit; explicit error handling is more predictable.
- **[bash]** Symptom: `grep -qF "$expected"` interpreted `--dryrun` as a grep flag — Fix: Use `grep -qF -- "$expected"` to prevent option-like strings from being parsed as flags
- **[bash]** Symptom: `local` keyword used outside a function in main loop body caused `local: can only be used in a function` error — Fix: Remove `local` qualifier for variables in the main script body
- **[bash]** Symptom: `set -e` in test script killed execution when capturing output from commands expected to exit non-zero (`output=$(cmd)` where cmd exits 1) — Fix: Use `output=$(cmd) && rc=$? || rc=$?` or `output=$(cmd) || true` pattern
- **[bash]** Symptom: `file` command on shell scripts returns "executable" which matched the binary detection grep `binary\|executable\|image\|archive` — Fix: Changed to `grep -qP "binary|image|archive"` with additional `! grep -q "text"` check to avoid false positives on text executables
## Key Context
- Project structure: `specs/` (OpenSpec), `scripts/` (implementations), `tests/` (test scripts using dryrun)
- Scripts symlinked to `~/sbin` for PATH availability
- Test runner at `tests/run-all.sh` with colour pass/fail output
- First script `git-status-report` has 26 test assertions covering: help, no repos, dryrun, clean/dirty repos, untracked/deleted files, no remotes, ahead of remote, mixed repos, nested repo filtering, permission denied
## Process Notes
- The `set -e` debugging consumed significant time — the script worked in isolated tests but failed silently on real repos. Future scripts should start without `set -e` for reporting/read-only tools.
- Test development caught real bugs (grep flag parsing, local keyword misuse) — the spec-driven approach with comprehensive tests works well.
- The `file` command for binary detection is unreliable for scripts; need a better heuristic (maybe `git diff --numstat` which shows `-` for binary files).

View File

@@ -0,0 +1,25 @@
# Session Log — 2026-03-17
## Summary
Added a "reproduce before fixing" best practice to claude-foundations' debugging topic, committed and pushed all outstanding claude-foundations changes, then built a new `unreflected-logs` script for scanning projects for session logs not yet processed by `/reflect-logs`.
## Decisions
- Decision: Add "reproduce before fixing" to `best-practices/debugging.md` rather than TDD — Rationale: TDD file covers regression tests as artifacts; the debugging file covers the *workflow* of how to approach a bug
- Decision: Bulk commit all outstanding claude-foundations changes in one commit — Rationale: User requested committing everything, not just the single file change
- Decision: `unreflected-logs` script uses python3 for JSON parsing of `.reflection-state.json` — Rationale: Reliable JSON parsing vs fragile bash/jq alternatives; python3 is available on target systems
## Gotchas Discovered
- **[bash]** Symptom: `((PASS++))` when PASS=0 evaluates to falsy (arithmetic result 0), causing `set -e` to exit the script silently — Fix: Use `PASS=$((PASS + 1))` instead, which always succeeds as an assignment
## Key Context
- `unreflected-logs` script follows the small-scripts spec-first workflow: spec in `specs/`, script in `scripts/`, test in `tests/`, symlinked to `~/sbin`
- The script compares `memory/log/*.md` files against `.reflection-state.json` processed keys (format: `log/<filename>`)
- Live scan of `~/dev/claude` found 5 unreflected logs across 5 projects as of this session
## Process Notes
- The `((var++))` bash gotcha with `set -e` is a classic trap — already documented in `memory/gotchas-bash.md` but still bit us in a new test file. Worth noting that it applies to any arithmetic expression that evaluates to 0.

View File

@@ -0,0 +1,15 @@
# Session Log — 2026-03-17
## Summary
Diagnosed why the `/housekeeping` skill (created last session) failed to load — an em dash in the YAML frontmatter description silently broke parsing. Fixed the skill and added a non-ASCII frontmatter check to `validate-skill`.
## Gotchas Discovered
- **[skills]** Symptom: Skill installed correctly (symlink, SKILL.md present) but Claude Code reports "Unknown skill" — Fix: Non-ASCII characters (em dashes `—`, smart quotes, etc.) in YAML frontmatter silently prevent skill loading. Replace with ASCII equivalents. Claude commonly generates em dashes, so this is a recurring risk.
## Key Context
- The fix was replacing `—` (UTF-8 `\xe2\x80\x94`) with `-` in the `description: >` field of `custom-claude-skills/skills/housekeeping/SKILL.md`
- Non-ASCII in the skill body (below frontmatter) is fine — only the YAML-parsed frontmatter is affected
## Process Notes
- `cat -A` was the key diagnostic — showed `M-bM-^@M-^T` bytes revealing the em dash that looked identical to a regular dash in normal display
- Added the check to validate-skill with: script change, spec update, test fixture + 2 assertions — all 45 tests pass

View File

@@ -0,0 +1,22 @@
# Session Log — 2026-03-17
## Summary
Diagnosed why `/housekeeping` skill wasn't loading in the `~/.claude-octopus` profile, fixed the root cause in `install.sh`, and created a new `check-skills` script to detect missing/stale skill symlinks. Integrated check-skills into the `/housekeeping` skill.
## Decisions
- Decision: Use `CLAUDE_CONFIG_DIR` env var to detect the active Claude profile — Rationale: Claude Code sets this automatically; falls back to `~/.claude` when unset
- Decision: Create `check-skills` as a read-only diagnostic script rather than auto-fixing — Rationale: Keeps it safe for `/housekeeping` (information-only), users can run `install.sh` to fix
- Decision: Log to `small-scripts` rather than `custom-claude-skills` — Rationale: The new script and tests live in small-scripts; custom-claude-skills changes were smaller edits
## Gotchas Discovered
- **[claude-code]** Symptom: `/housekeeping` skill not found when using `~/.claude-octopus` profile — Fix: Each Claude profile has its own independent `skills/` directory. Skills must be symlinked into every profile, not just `~/.claude`. The `CLAUDE_CONFIG_DIR` env var identifies the active profile.
- **[claude-code]** Symptom: `install.sh` hardcoded `$HOME/.claude/skills` so new skills only appeared in the default profile — Fix: Changed to `${CLAUDE_CONFIG_DIR:-$HOME/.claude}/skills`
## Key Context
- `CLAUDE_CONFIG_DIR` env var is set by Claude Code to the active profile directory (e.g., `/home/paul/.claude-octopus`)
- Multiple Claude profiles maintain completely independent `skills/` directories — no cross-profile sharing
- The `check-skills` script classifies skills as: LINKED (correct), MISSING (not in profile), STALE (wrong target), ORPHAN (not in source repo)
## Process Notes
- Spec-first workflow for `check-skills` kept implementation focused — spec, script, test, symlink, integrate
- All 17 test cases passed on first run