Add claude-profile engagement mode picker with statusline and session-start integration
- claude-profile: phase 1-3 picker (profile, mode, launch) with preset support, dryrun, WezTerm theming, and --append-system-prompt mode body injection - 5 mode files (chat/quick/deep/hybrid/orch) with YAML frontmatter + prose body; new escalates_to field drives statusline →Opus arrow for deep and hybrid - statusline.sh reads CLAUDE_CONFIG_DIR/active-mode.env to show [Sonnet→Opus] deep · topic format when launched via claude-profile - Root CLAUDE.md session-start: auto-selects project from cwd or CLAUDE_PROJECT in active-mode.env, skipping the interactive picker when context is clear - Spec, tests (37 assertions, 9 test files, all passing), context docs, and preset example included Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,25 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,15 +0,0 @@
|
||||
# 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
|
||||
@@ -1,22 +0,0 @@
|
||||
# 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
|
||||
42
memory/log/2026-04-12.002212.md
Normal file
42
memory/log/2026-04-12.002212.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Session Log -- 2026-04-12
|
||||
|
||||
## Summary
|
||||
Designed and implemented engagement modes for `claude-profile`: 5 modes (chat / quick / deep / hybrid / orch) bundling driver model, subagent policy, async tolerance, and workflow stance. Wrote a full OpenSpec, replaced the 104-line script with a ~280-line three-phase picker, added a 37-assertion test suite (all passing), and seeded FUTURE.md with five follow-ups including a MiniMax-driven inverted architecture.
|
||||
|
||||
## Decisions
|
||||
- Decision: Mode files live in `data/claude-profile/modes/<name>.md` in the repo, not in profile directories -- Rationale: source of truth must be version-controlled; profile dirs are for user state, not script data. Established `data/` as a new repo top-level convention.
|
||||
- Decision: Driver enforcement is real via `claude --model <full-id>`, not advisory via system prompt -- Rationale: confirmed `--model` is supported and session-scoped via the claude-code-guide agent. Removes the contradiction of "you are Sonnet" being injected into an Opus session.
|
||||
- Decision: Use full model IDs (`claude-sonnet-4-6`, `claude-haiku-4-5-20251001`) not aliases -- Rationale: removes ambiguity about which version is selected; the `claude-code-guide` agent only confirmed `sonnet`/`opus` aliases, haiku alias is unverified.
|
||||
- Decision: v1 of claude-profile does NOT ask for a project interactively -- Rationale: would duplicate the existing CLAUDE.md project picker. `--project` flag still works for non-interactive use; CLAUDE.md integration is in FUTURE.md.
|
||||
- Decision: Mode 3 (Deep Work) drives with Sonnet, not Opus -- Rationale: Sonnet is the workhorse; Opus is the consultant. Opus only enters via named workflows (plan review, spec review, dual-model second opinion, gnarly-bug consult, architecture review). Default reasoning is "think hard", not ultrathink.
|
||||
- Decision: Frontmatter and presets.yaml parsed by pure awk, no yq dependency -- Rationale: small-scripts targets a clean Linux env; adding yq just for one launcher is overkill. Parsing is simple key:value with one-level nesting.
|
||||
- Decision: `bg-model-call` wrapper deferred to FUTURE.md, not built this session -- Rationale: Out of scope for the launcher; the modes reference it as a pattern but don't require it to ship.
|
||||
|
||||
## Gotchas Discovered
|
||||
- **[bash]** Symptom: `read -rp` under `set -e` exits silently with code 1 when stdin is closed (no TTY), making `--dryrun` unusable from scripts -- Fix: guard every interactive read with `[[ -t 0 ]]`; fall back to default value when not on a terminal. Affected the profile picker, mode picker, and time-horizon question.
|
||||
- **[claude-profile]** Symptom: Original script's `CONTEXT_LOADER="${SCRIPT_DIR}/context-load"` failed because context-load lives in `claude-foundations/scripts/`, not as a sibling -- Fix: use `command -v context-load` (it's symlinked into `~/sbin`), with the sibling location as a fallback for testing isolation. Used `readlink -f "$0"` so the lookup also works when claude-profile is symlinked.
|
||||
- **[claude-code]** Symptom: Unsure whether `claude --model` was supported, considered fragile workarounds (per-driver profile dirs, settings.json rewriting) -- Fix: 30-second check via the claude-code-guide agent confirmed `--model` is session-scoped and accepts both aliases and full IDs. Saved building 3 workarounds.
|
||||
- **[shell]** Symptom: `eval "$preset_data"` would have been a code-injection footgun if presets.yaml contained shell metacharacters -- Fix: parse preset blocks into `PRESET_*` variables via awk, then map them to known field names with a case statement. Never eval untrusted content.
|
||||
|
||||
## Open Questions
|
||||
- Does CLAUDE.md (the top-level session-start instructions in `~/dev/claude/CLAUDE.md`) have a clean place to read shell env files at startup? Needed for the project-picker integration follow-up.
|
||||
- Where exactly does the status-line script live in claude-foundations, and is it bash or another language? Needed before scoping the mode-tag rendering follow-up.
|
||||
- Does MiniMax M2 ship a usable agentic CLI/harness in 2026, or would building one be a precondition for the inverted-architecture follow-up?
|
||||
- Token-budget sketch under both architectures (claude-profile hybrid vs. minimax-profile) -- the inverted architecture needs >30% projected savings to be worth pursuing, or it's a research project not a productivity win.
|
||||
- For the `switch mode` skill: literal phrase ("switch mode") matched by a UserPromptSubmit hook, or a slash command `/switch-mode`? Mode files all assume the literal phrase.
|
||||
|
||||
## Key Context
|
||||
- New `data/` directory in small-scripts is a new top-level convention; documented in CLAUDE.md and README.md.
|
||||
- Driver mapping table in spec and script: `haiku → claude-haiku-4-5-20251001`, `sonnet → claude-sonnet-4-6`, `opus → claude-opus-4-6`, `opus-1m → claude-opus-4-6[1m]`.
|
||||
- `active-mode.env` is written to `$CLAUDE_CONFIG_DIR/active-mode.env`; survives `/clear` because the path is stable. Read by CLAUDE.md session-start (future) and the status-line script (future).
|
||||
- `last-mode` file at `$CLAUDE_CONFIG_DIR/last-mode` records the most recent mode for picker default; falls back to `quick` if missing or invalid.
|
||||
- Presets at `$CLAUDE_CONFIG_DIR/presets.yaml` (per-profile, not global). Example template shipped at `data/claude-profile/presets.yaml.example`.
|
||||
- Documented v1 limitation: parallel `claude-profile` sessions against the same profile race on `active-mode.env` (last writer wins).
|
||||
- Test suite: `tests/test-claude-profile.sh` exercises 10 test groups, 37 assertions, all dryrun-based so it never launches real `claude`.
|
||||
|
||||
## Process Notes
|
||||
- File-based result passing (background bash + sentinel files) emerged as the unifying design principle across this session: it ties together `bg-model-call`, `ScheduleWakeup` patterns, and the MiniMax inverted architecture. Whenever a subagent or container produces a non-trivial result, write it to a file and only `Read` it into context if you actually need to. This keeps the driver's context lean even when subagents do heavy work.
|
||||
- Always verify harness capabilities (like `claude --model`) before designing around them. A 30-second `claude-code-guide` agent check prevented committing to fragile workarounds. The pattern: if you're about to design a workaround for something the harness "doesn't support", verify the assumption first.
|
||||
- Spec-first paid off when the driver-enforcement question turned out to have a clean answer. The spec was already structured to accept the change cleanly (one Edit on Phase 3, one new "Driver mapping" subsection); had implementation gone first, it would have been a more invasive rewrite.
|
||||
- When extending an old script, check whether its existing references actually work in the current environment. The original `CONTEXT_LOADER="${SCRIPT_DIR}/context-load"` was broken in the live environment but had been masked by never running the script in dryrun mode. Tests would have caught this immediately if they'd existed.
|
||||
- For interactive bash scripts that also need to be testable: `[[ -t 0 ]]` guard around every `read`. Allows the same code path to be interactive or scripted without `set -e` blowups.
|
||||
Reference in New Issue
Block a user