End-of-session: statusline + session-start integration, docs update

- context: claude-profile-modes updated to reflect current state (statusline
  and session-start auto-select done; next step is real launch test)
- FUTURE.md: remove two completed items (status-line, CLAUDE.md picker)
- README: add missing scripts (check-skills, gen-secret, mp3-to-mp4,
  split-wezterm, sync-repos) to scripts table
- session log 2026-04-12.003747.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Paul O'Reilly
2026-04-12 00:40:17 +12:00
parent 143b32597e
commit 340c40392a
5 changed files with 62 additions and 93 deletions

View File

@@ -2,4 +2,4 @@
<!-- Thin index — one-line entries linking to context/ detail files --> <!-- Thin index — one-line entries linking to context/ detail files -->
- [claude-profile engagement modes](context/claude-profile-modes.md) — Built and dryrun-tested; needs symlink install + first real `claude` launch + 5 sequenced follow-ups in FUTURE.md - [claude-profile engagement modes](context/claude-profile-modes.md) — Core done (picker, statusline integration, session-start auto-select); needs symlink install + first real `claude` launch test before v1 is declared complete

View File

@@ -18,20 +18,6 @@
The initial engagement mode picker (chat / quick / deep / hybrid / orch) ships with `claude-profile` and writes `active-mode.env` into the active profile directory. Several integration pieces are deferred to future work — none block v1 but each unlocks the design fully: The initial engagement mode picker (chat / quick / deep / hybrid / orch) ships with `claude-profile` and writes `active-mode.env` into the active profile directory. Several integration pieces are deferred to future work — none block v1 but each unlocks the design fully:
### CLAUDE.md project picker integration
- **Problem:** `claude-profile --project <name>` writes `CLAUDE_PROJECT` into `active-mode.env`, but the existing CLAUDE.md session-start project picker still runs and ignores it. The user has to pick the same project twice when launching with a preset.
- **Idea:** Update `~/dev/claude/CLAUDE.md` (the top-level session-start instructions) to read `$CLAUDE_CONFIG_DIR/active-mode.env` first; if `CLAUDE_PROJECT` is set, skip the interactive project menu and `cd` straight into that project. Same hook can announce the active mode to satisfy the "first message after `/clear`" templates in each mode file.
- **Open questions:** Does the CLAUDE.md flow have a clean place to read shell env files, or does `claude-profile` need to inject the project name into the appended system prompt directly? The latter is simpler but couples the picker to claude-profile.
- **Depends on:** Nothing blocking — can be done any time.
### Status-line script: render the mode tag
- **Problem:** The mode tag (`chat / quick / deep / hybrid / orch`) is recorded in `active-mode.env` but the status line at `~/.claude/status/statusline.sh` does not currently read it. Humans cannot see the active mode at a glance, which is the whole point of the persistent indicator.
- **Idea:** Update the status-line script to read `$CLAUDE_CONFIG_DIR/active-mode.env`, extract `CLAUDE_MODE_TAG` and `CLAUDE_DRIVER`, and prepend them to the existing topic in the format `[Driver] mode-tag · topic | N% ctx`. Modes with named subagent escalation (`deep`, `hybrid`) should render an arrow: `[Sonnet→Opus] deep · topic`. Orchestrator should append a queue-depth segment: `[Sonnet] orch · project · queue:N`.
- **Open questions:** Where does the status-line script live in the repo (it's outside small-scripts)? Should the queue-depth read be cached to avoid hammering `.agent-tasks.json` on every status-line render?
- **Depends on:** The status-line script is in claude-foundations, not small-scripts — this work happens in that repo.
### `bg-model-call` wrapper ### `bg-model-call` wrapper
- **Problem:** The `deep` and `hybrid` modes both reference `bg-model-call` as the standardised way to fire a third-party model (MiniMax, etc.) in the background and have the result land in a sentinel file. The wrapper does not exist yet — modes currently just describe the pattern. - **Problem:** The `deep` and `hybrid` modes both reference `bg-model-call` as the standardised way to fire a third-party model (MiniMax, etc.) in the background and have the result land in a sentinel file. The wrapper does not exist yet — modes currently just describe the pattern.

View File

@@ -14,9 +14,14 @@ This project uses **spec-driven development** (OpenSpec) as a testbed for agent-
| Script | Purpose | Status | | Script | Purpose | Status |
|--------|---------|--------| |--------|---------|--------|
| `check-skills` | Verify Claude Code skill symlinks match source repo | Done |
| `claude-profile` | Claude Code profile + engagement-mode launcher | Done |
| `gen-secret` | Generate bash/YAML/JSON-safe random strings | Done |
| `git-status-report` | Recursive git repo status with diff stats | Done | | `git-status-report` | Recursive git repo status with diff stats | Done |
| `md-to-docx` | Markdown to DOCX conversion | Done | | `md-to-docx` | Markdown to DOCX conversion | Done |
| `claude-profile` | Claude Code profile + engagement-mode launcher | Done | | `mp3-to-mp4` | Convert MP3 to MP4 with a static title card | Done |
| `split-wezterm` | Split WezTerm pane into a rows × cols grid | Done |
| `sync-repos` | Mirror git repos across remotes | Done |
| `unreflected-logs` | Scan projects for unreflected session logs | Done | | `unreflected-logs` | Scan projects for unreflected session logs | Done |
| `validate-skill` | Validate SKILL.md files against known Claude Code restrictions | Done | | `validate-skill` | Validate SKILL.md files against known Claude Code restrictions | Done |

View File

@@ -2,90 +2,42 @@
## Status ## Status
**Built and tested via dryrun. NOT yet exercised in a real `claude` launch.** **Core features shipped and pushed (commit 143b325). NOT yet exercised in a real `claude` launch.**
The feature ships as part of `scripts/claude-profile` (rewritten this session from 104 to ~280 lines). Spec is at `specs/claude-profile.spec.md`. All 37 dryrun assertions pass via `tests/test-claude-profile.sh`. Full test suite (`tests/run-all.sh`) is green: 8 of 8 test files passing. ## What's done
## What was built | Component | State |
| Component | Path |
|---|---| |---|---|
| Spec | `specs/claude-profile.spec.md` | | Profile + mode picker (phases 1-3) | Done, 37 dryrun assertions passing |
| Picker bash | `scripts/claude-profile` | | 5 mode files with `escalates_to` frontmatter | Done |
| 5 mode files | `data/claude-profile/modes/{chat,quick,deep,hybrid,orch}.md` | | `active-mode.env` written on every launch | Done (includes `CLAUDE_ESCALATES_TO`) |
| Preset example | `data/claude-profile/presets.yaml.example` | | statusline.sh — `[Sonnet→Opus] deep · topic` format | Done (reads `CLAUDE_CONFIG_DIR/active-mode.env`) |
| Test script | `tests/test-claude-profile.sh` | | Root CLAUDE.md — auto-select project from cwd or `CLAUDE_PROJECT` | Done |
| Preset support (`presets.yaml`) | Done (example at `data/claude-profile/presets.yaml.example`) |
The five modes:
| Mode | Driver model | Async | For |
|---|---|---|---|
| `chat` | Haiku (`claude-haiku-4-5-20251001`) | no | No project, conversation only |
| `quick` | Sonnet (`claude-sonnet-4-6`) | no | Single small focused job |
| `deep` | Sonnet | yes | Hard design/debugging, plan + spec enforced, Opus via named workflows |
| `hybrid` | Haiku | yes | Cheap driver, escalates to Opus/Sonnet subagents on demand |
| `orch` | Sonnet | yes | Decompose work, dispatch container agents, auto-fires `/loop 2m /orchestrate` |
## What is NOT done
1. **Not symlinked into `~/sbin`.** The new script lives at `~/dev/claude/small-scripts/scripts/claude-profile` but is not yet on PATH. To install:
```bash
ln -sf "$HOME/dev/claude/small-scripts/scripts/claude-profile" "$HOME/sbin/claude-profile"
```
2. **Not exercised against real `claude`.** Dryrun confirms the resolved values; an actual launch (e.g. `claude-profile oreillyit --mode quick` or `--mode chat`) is the first thing the next session should try.
3. **Presets file not installed.** Example template is at `data/claude-profile/presets.yaml.example`. To use presets, copy to `~/.claude-oreillyit/presets.yaml` and edit.
4. **CLAUDE.md does not yet read `active-mode.env`.** When a real launch happens with `--project <name>`, the existing CLAUDE.md project picker will still appear and the user has to confirm the same project. This is the first follow-up listed below.
## How the runtime contract works
1. `claude-profile` resolves the profile, mode, and (for some modes) follow-up answers.
2. Writes `$CLAUDE_CONFIG_DIR/active-mode.env` with all resolved values (machine-readable, key=value).
3. Writes `$CLAUDE_CONFIG_DIR/last-mode` with the mode name (used as picker default next time).
4. Reads the mode file's body (everything after the YAML frontmatter), appends it to the context-load output, and passes the combined string via `--append-system-prompt`.
5. Resolves the mode's `driver` field through a hardcoded mapping table to a full Claude model ID.
6. Executes `claude --model "<full-model-id>" --append-system-prompt "<combined>" "${pass-through-args[@]}"`.
The mode file's prose body is what tells the driver model how to behave (escalation rules, plan-mode triggers, async policy, status-line format, on-`/clear` behaviour). The frontmatter is parsed by bash for the launcher's own decision-making.
## Driver mapping (lives in the script as a constant)
| Frontmatter `driver` | `--model` argument |
|---|---|
| `haiku` | `claude-haiku-4-5-20251001` |
| `sonnet` | `claude-sonnet-4-6` |
| `opus` | `claude-opus-4-6` |
| `opus-1m` | `claude-opus-4-6[1m]` |
When new model versions ship, update the `DRIVER_MAP` associative array near the top of `scripts/claude-profile`.
## Next session — recommended order ## Next session — recommended order
1. **Install the symlink:** `ln -sf "$HOME/dev/claude/small-scripts/scripts/claude-profile" "$HOME/sbin/claude-profile"` 1. **Install the symlink** (if not already done):
2. **Real-launch test:** `claude-profile oreillyit --mode chat` first (lowest blast radius — Haiku driver, no project, no async). Verify the mode body actually appears in the system prompt and the model behaves per the chat mode rules. ```bash
3. **Then `--mode quick`** with a real project to verify the Sonnet driver and the no-async constraints. ln -sf "$HOME/dev/claude/small-scripts/scripts/claude-profile" "$HOME/sbin/claude-profile"
4. **Then `--mode deep`** to verify plan-mode auto-engagement and the named-workflow escalation table. ```
5. **If anything feels off,** `tests/test-claude-profile.sh` is the fast feedback loop — run it after any picker-bash changes. 2. **Real-launch test:** `claude-profile oreillyit --mode chat` first (lowest blast radius — Haiku driver, no project, no async). Verify:
6. **Once happy with v1,** start picking up follow-ups from `FUTURE.md` (see "Follow-ups" below). - Mode body appears in system prompt (CLAUDE.md announces the mode)
- Status bar shows `[Haiku] chat` format
- `~/.claude-oreillyit/active-mode.env` is written with correct values
3. **Auto-select test:** launch from inside a project dir (`cd ~/dev/claude/small-scripts && claude-profile oreillyit --mode quick`) — should skip the project picker and announce "Auto-selected project small-scripts"
4. **Then `--mode deep`** to verify plan-mode auto-engagement and the `[Sonnet→Opus] deep · topic` status bar format
5. **If anything's off**, `tests/test-claude-profile.sh` is the fast feedback loop
## Follow-ups (sequenced) ## Remaining follow-ups (from FUTURE.md)
All in `FUTURE.md`. Suggested order: 1. **`bg-model-call` wrapper** — `deep` and `hybrid` modes reference it but it doesn't exist yet. Own spec + script entry.
2. **`switch mode` skill** — mid-session re-pick writes new `active-mode.env` for the next `/clear`. Lower priority.
3. **MiniMax inverted architecture** — long research project; requires token-budget sketch first.
1. **CLAUDE.md project picker integration** — read `CLAUDE_PROJECT` from `active-mode.env`, skip the duplicate picker. Quick win. ## Key gotchas
2. **Status-line script: render the mode tag** — the user explicitly asked for this; humans need to see the active mode at a glance. Lives in the claude-foundations repo, not small-scripts.
3. **`bg-model-call` wrapper** — referenced by the `deep` and `hybrid` modes but not yet built. Own small-scripts entry with its own spec and tests.
4. **`switch mode` skill** — mid-session re-pick. Lower priority; depends on whether mode switching turns out to be common in practice.
5. **MiniMax-driven inverted architecture** — biggest item, real research project. Token-budget sketch is the precondition before any code; if savings <30% it's not worth pursuing.
## Files touched this session - **statusline.sh is not in any git repo** — lives at `~/.claude/status/statusline.sh`. Changes are live immediately; no commit needed.
- **Root `~/dev/claude/CLAUDE.md` is also not git-tracked** — changes there are also immediately live.
- Created: `specs/claude-profile.spec.md`, `data/claude-profile/modes/{chat,quick,deep,hybrid,orch}.md`, `data/claude-profile/presets.yaml.example`, `tests/test-claude-profile.sh`, `context/claude-profile-modes.md` (this file) - **`CLAUDE_CONFIG_DIR` must be exported** by claude-profile before `exec claude`. The statusline hook inherits it from the claude process environment.
- Modified: `scripts/claude-profile` (rewritten), `README.md`, `CLAUDE.md`, `FUTURE.md` - **`read -rp` under `set -e` exits silently if stdin is not a TTY.** The picker guards all interactive reads with `[[ -t 0 ]]`. See `memory/gotchas-bash.md`.
- Pruned: 4 reflected session logs from March (`memory/log/2026-03-17.*.md` and `2026-03-23.123551.md`)
## Key gotchas to remember
- **`read -rp` under `set -e` exits silently if stdin is not a TTY.** Always guard interactive reads with `[[ -t 0 ]]` and provide a default. Without this, `--dryrun` hangs or silently exits when run from scripts. See `memory/gotchas-bash.md` for the broader pattern.
- **`context-load` is on PATH via `~/sbin`, not a sibling of `claude-profile`.** The script uses `command -v context-load` first, with sibling fallback for testing isolation.
- **Use full model IDs, not aliases.** The `claude-code-guide` agent only confirmed `sonnet`/`opus` aliases work; `haiku` is unverified. The mapping table uses full IDs throughout for safety and unambiguous version selection.
- **`claude --model` is session-scoped.** Switching driver mid-session is impossible — it requires a relaunch. The `switch mode` follow-up works around this by writing a new `active-mode.env` for the next `/clear` to pick up.

View File

@@ -0,0 +1,26 @@
# Session Log — 2026-04-12
## Summary
Completed two claude-profile integration pieces: (1) statusline.sh now reads `CLAUDE_CONFIG_DIR/active-mode.env` to show `[Sonnet→Opus] deep · topic` format when launched via claude-profile; (2) root CLAUDE.md session-start now auto-selects project from cwd or `CLAUDE_PROJECT` in active-mode.env, skipping the interactive picker. Added `escalates_to` frontmatter field to all 5 mode files, committed and pushed (commit 143b325).
## Decisions
- Decision: Added `escalates_to` field to mode file frontmatter rather than hardcoding which modes get the →Opus arrow in statusline.sh — Rationale: keeps the statusline.sh generic; any future mode can declare its own escalation target without touching the statusline
- Decision: statusline.sh reads CLAUDE_DRIVER (short name) from active-mode.env rather than using model.display_name from session JSON — Rationale: session JSON shows full name ("Claude Sonnet 4.6"), driver is the concise name ("Sonnet") the status format requires; also future-proofs against model renames
- Decision: Used `grep | cut` rather than `source` to read active-mode.env in statusline.sh — Rationale: safer than sourcing untrusted files, and `set -euo pipefail` means a sourced file with any errors would abort the status line
## Gotchas Discovered
- **[bash]** Symptom: Edit tool refuses to edit a file — Fix: Read tool must be called first even if you've already seen file contents via Bash. The Edit tool tracks which files have been explicitly Read (not just seen in bash output). Use parallel Read calls before parallel Edit calls.
## Key Context
- statusline.sh lives at `~/.claude/status/statusline.sh` — not in a git repo, changes are live immediately with no commit
- The root `~/dev/claude/CLAUDE.md` session-start instructions were updated but that file is also not in any git repo (it's just a file in the filesystem); changes are live immediately
- Next step before considering claude-profile "done": install symlink (`ln -sf "$HOME/dev/claude/small-scripts/scripts/claude-profile" "$HOME/sbin/claude-profile"`) and do a real launch test
## Process Notes
- Sonnet 4.6 has a 200k context window, no extended context option. `opus-1m` refers to Opus with 1M window.
- The "Memory files" category in `/context` includes both CLAUDE.md project instructions (6k) and auto-memory MEMORY.md (1.4k) — two different systems with different purposes