- 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>
7.0 KiB
7.0 KiB
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>.mdin the repo, not in profile directories -- Rationale: source of truth must be version-controlled; profile dirs are for user state, not script data. Establisheddata/as a new repo top-level convention. - Decision: Driver enforcement is real via
claude --model <full-id>, not advisory via system prompt -- Rationale: confirmed--modelis 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; theclaude-code-guideagent only confirmedsonnet/opusaliases, 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.
--projectflag 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-callwrapper 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 -rpunderset -eexits silently with code 1 when stdin is closed (no TTY), making--dryrununusable 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 inclaude-foundations/scripts/, not as a sibling -- Fix: usecommand -v context-load(it's symlinked into~/sbin), with the sibling location as a fallback for testing isolation. Usedreadlink -f "$0"so the lookup also works when claude-profile is symlinked. - [claude-code] Symptom: Unsure whether
claude --modelwas supported, considered fragile workarounds (per-driver profile dirs, settings.json rewriting) -- Fix: 30-second check via the claude-code-guide agent confirmed--modelis 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 intoPRESET_*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 modeskill: 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.envis written to$CLAUDE_CONFIG_DIR/active-mode.env; survives/clearbecause the path is stable. Read by CLAUDE.md session-start (future) and the status-line script (future).last-modefile at$CLAUDE_CONFIG_DIR/last-moderecords the most recent mode for picker default; falls back toquickif missing or invalid.- Presets at
$CLAUDE_CONFIG_DIR/presets.yaml(per-profile, not global). Example template shipped atdata/claude-profile/presets.yaml.example. - Documented v1 limitation: parallel
claude-profilesessions against the same profile race onactive-mode.env(last writer wins). - Test suite:
tests/test-claude-profile.shexercises 10 test groups, 37 assertions, all dryrun-based so it never launches realclaude.
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,ScheduleWakeuppatterns, and the MiniMax inverted architecture. Whenever a subagent or container produces a non-trivial result, write it to a file and onlyReadit 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-secondclaude-code-guideagent 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 everyread. Allows the same code path to be interactive or scripted withoutset -eblowups.