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:
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