Update /log skill to use transcript backups via Sonnet subagent; add switch-mode
- skills/log/SKILL.md: pre-gathers unprocessed transcript metadata (compact JSON via list-transcripts-here.sh) rather than full content; spawns a Sonnet subagent (not Haiku — gotcha detection requires judgment) to read JSONL backups, write a companion -transcripts.md log, and mark backups processed in tracking.json; adds Agent and Bash(bash|pwd|python3) to allowed-tools - skills/switch-mode/SKILL.md: add previously untracked skill to repo Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@ description: >
|
|||||||
End-of-session logging. Captures key decisions, gotchas, open questions, and discussion
|
End-of-session logging. Captures key decisions, gotchas, open questions, and discussion
|
||||||
points into memory/log/ for later reflection. Run before ending a session to preserve
|
points into memory/log/ for later reflection. Run before ending a session to preserve
|
||||||
context. Fast and low-friction -- just run /log.
|
context. Fast and low-friction -- just run /log.
|
||||||
allowed-tools: Read, Write, Glob, Bash(date *), Bash(ls *), Bash(cat *), Bash(find *), Bash(rm *), Bash(mkdir *)
|
allowed-tools: Read, Write, Glob, Agent, Bash(date *), Bash(pwd), Bash(ls *), Bash(cat *), Bash(find *), Bash(rm *), Bash(mkdir *), Bash(python3 *), Bash(bash *)
|
||||||
---
|
---
|
||||||
|
|
||||||
# Session Log Skill
|
# Session Log Skill
|
||||||
@@ -17,6 +17,9 @@ You are capturing key points from the current session into a structured log file
|
|||||||
!`date +%Y-%m-%d`
|
!`date +%Y-%m-%d`
|
||||||
!`date +%Y%m%d-%H%M%S`
|
!`date +%Y%m%d-%H%M%S`
|
||||||
|
|
||||||
|
### Current project directory
|
||||||
|
!`pwd`
|
||||||
|
|
||||||
### Existing log files
|
### Existing log files
|
||||||
!`ls -1 memory/log/ 2>/dev/null || echo "No log directory yet"`
|
!`ls -1 memory/log/ 2>/dev/null || echo "No log directory yet"`
|
||||||
|
|
||||||
@@ -29,16 +32,19 @@ You are capturing key points from the current session into a structured log file
|
|||||||
### Current MEMORY.md index
|
### Current MEMORY.md index
|
||||||
!`cat MEMORY.md 2>/dev/null || echo "No MEMORY.md found"`
|
!`cat MEMORY.md 2>/dev/null || echo "No MEMORY.md found"`
|
||||||
|
|
||||||
|
### Unprocessed transcript backups for this project (metadata only)
|
||||||
|
!`bash ~/.claude/scripts/list-transcripts-here.sh 2>/dev/null || echo "[]"`
|
||||||
|
|
||||||
## Instructions
|
## Instructions
|
||||||
|
|
||||||
Review the **full conversation history** in your context window and extract the key points worth preserving. Not every session needs a log — if the session was trivial (a typo fix, a quick question), say so and skip.
|
Review the **full conversation history** in your context window and extract key points worth preserving. Not every session needs a log — if the session was trivial (a typo fix, a quick question), say so and skip.
|
||||||
|
|
||||||
### Step 1: Create the log directory if needed
|
The "Unprocessed transcript backups" above shows metadata (filenames, timestamps) for any pre-compaction snapshots not yet captured in a log. **Do NOT read the transcript content yourself** — that is handled by a subagent in Step 2 to avoid context overflow.
|
||||||
|
|
||||||
|
### Step 1: Create the log directory and write the in-context log
|
||||||
|
|
||||||
If `memory/log/` does not exist, create it with `mkdir -p memory/log/`.
|
If `memory/log/` does not exist, create it with `mkdir -p memory/log/`.
|
||||||
|
|
||||||
### Step 2: Write the log file
|
|
||||||
|
|
||||||
Generate the filename as `memory/log/YYYY-MM-DD.<HHMMSS>.md` using the pre-gathered date and timestamp values.
|
Generate the filename as `memory/log/YYYY-MM-DD.<HHMMSS>.md` using the pre-gathered date and timestamp values.
|
||||||
|
|
||||||
Write the file using this format:
|
Write the file using this format:
|
||||||
@@ -72,9 +78,82 @@ Write the file using this format:
|
|||||||
|
|
||||||
**Guidelines:**
|
**Guidelines:**
|
||||||
- Omit empty sections entirely rather than leaving them blank
|
- Omit empty sections entirely rather than leaving them blank
|
||||||
- The `[topic]` tag on gotchas should match existing memory topic names where possible (e.g., `[k8s]`, `[cilium]`, `[ansible]`, `[sops]`, `[helm]`). Use new tags for new topics.
|
- The `[topic]` tag on gotchas should match existing memory topic names where possible (e.g., `[k8s]`, `[cilium]`, `[ansible]`, `[sops]`, `[helm]`)
|
||||||
- Keep entries concise — this is raw material for `/reflect-logs`, not a polished document
|
- Keep entries concise — this is raw material for `/reflect-logs`, not a polished document
|
||||||
- Include enough context that each entry makes sense on its own without the full conversation
|
- Include enough context that each entry makes sense without the full conversation
|
||||||
|
|
||||||
|
### Step 2: Dispatch transcript analysis subagent (if unprocessed transcripts exist)
|
||||||
|
|
||||||
|
If the pre-gathered transcript list is non-empty and contains backup files that `exists: true`:
|
||||||
|
|
||||||
|
Spawn a **Sonnet** subagent (model: sonnet) with the following prompt. Sonnet is used (not Haiku) because gotcha detection requires judgment about backtracking, failed attempts, and domain-specific failure modes — Haiku tends to miss these. Fill in the bracketed values from the pre-gathered data:
|
||||||
|
|
||||||
|
---
|
||||||
|
**Subagent prompt template:**
|
||||||
|
|
||||||
|
You are processing pre-compaction transcript backups into a structured session log.
|
||||||
|
|
||||||
|
**Project directory:** [CWD from pre-gathered context]
|
||||||
|
**Log directory:** memory/log/ (relative to project dir — write files there using absolute path)
|
||||||
|
**Log filename:** [SAME HHMMSS timestamp as Step 1, but with suffix -transcripts, e.g. memory/log/YYYY-MM-DD.HHMMSS-transcripts.md]
|
||||||
|
**Transcripts to process:** [paste the JSON array from the pre-gathered list]
|
||||||
|
|
||||||
|
## Your task
|
||||||
|
|
||||||
|
For each backup file listed above (where `exists: true`):
|
||||||
|
|
||||||
|
1. Extract the conversation using:
|
||||||
|
```
|
||||||
|
python3 ~/.claude/scripts/extract-transcripts.py --extract <backup_name>
|
||||||
|
```
|
||||||
|
Run this as a Bash command and read the output.
|
||||||
|
|
||||||
|
2. If the transcript has >40 turns, process it in two passes:
|
||||||
|
- First half of turns in one read
|
||||||
|
- Second half in a second run (re-run --extract and skip to turn N)
|
||||||
|
Note: the --extract command outputs all turns; read the full output but focus analysis on substance.
|
||||||
|
|
||||||
|
3. After reading all transcripts, write a single log file at the absolute path:
|
||||||
|
`[PROJECT_ABS_PATH]/memory/log/YYYY-MM-DD.HHMMSS-transcripts.md`
|
||||||
|
|
||||||
|
Use this format:
|
||||||
|
```markdown
|
||||||
|
# Transcript Log — YYYY-MM-DD (pre-compaction backups)
|
||||||
|
|
||||||
|
## Sources
|
||||||
|
- <backup_name> (session <session_id>, saved <saved_at>)
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
<!-- What was worked on across the captured sessions -->
|
||||||
|
|
||||||
|
## Decisions
|
||||||
|
- Decision: <what> — Rationale: <why>
|
||||||
|
|
||||||
|
## Gotchas Discovered
|
||||||
|
- **[topic]** Symptom: <what happened> — Fix: <what resolved it>
|
||||||
|
|
||||||
|
## Open Questions
|
||||||
|
- <question>
|
||||||
|
|
||||||
|
## Key Context
|
||||||
|
- <fact>
|
||||||
|
|
||||||
|
## Process Notes
|
||||||
|
- <note>
|
||||||
|
```
|
||||||
|
|
||||||
|
4. After writing the log, mark all processed transcripts:
|
||||||
|
```
|
||||||
|
python3 ~/.claude/scripts/extract-transcripts.py --mark-all-processed "[CWD]" --log-file "memory/log/YYYY-MM-DD.HHMMSS-transcripts.md"
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Report: transcript(s) processed, log file written, any issues encountered.
|
||||||
|
|
||||||
|
**Allowed tools for the subagent:** Read, Write, Bash(python3 *), Bash(mkdir *)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Spawn this subagent with `model: sonnet` and wait for it to complete before continuing.
|
||||||
|
|
||||||
### Step 3: Prune old logs
|
### Step 3: Prune old logs
|
||||||
|
|
||||||
@@ -91,6 +170,6 @@ After writing the log file, check for old logs that should be pruned:
|
|||||||
### Step 4: Summary
|
### Step 4: Summary
|
||||||
|
|
||||||
Print a brief summary:
|
Print a brief summary:
|
||||||
- Log file created (with path)
|
- In-context log file created (with path)
|
||||||
- Number of entries by section
|
- Whether a transcript analysis subagent was dispatched (and which backups it processed)
|
||||||
- Any files pruned or warnings issued
|
- Any files pruned or warnings issued
|
||||||
|
|||||||
128
skills/switch-mode/SKILL.md
Normal file
128
skills/switch-mode/SKILL.md
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
---
|
||||||
|
name: switch-mode
|
||||||
|
description: >
|
||||||
|
Change engagement mode mid-session. Updates active-mode.env and last-mode so
|
||||||
|
the next session launches in the new mode. Injects the new mode's workflow
|
||||||
|
stance into the current conversation so it takes effect immediately (driver
|
||||||
|
model cannot change without a relaunch).
|
||||||
|
allowed-tools: Read, Write, Glob, Bash(ls *), Bash(cat *)
|
||||||
|
---
|
||||||
|
|
||||||
|
# Switch Mode Skill
|
||||||
|
|
||||||
|
You are helping the user change their engagement mode.
|
||||||
|
|
||||||
|
## Pre-gathered context
|
||||||
|
|
||||||
|
### Available modes
|
||||||
|
!`ls ~/dev/claude/small-scripts/data/claude-profile/modes/`
|
||||||
|
|
||||||
|
### Current active-mode.env
|
||||||
|
!`cat ~/.claude-oreillyit/active-mode.env`
|
||||||
|
|
||||||
|
### Current last-mode
|
||||||
|
!`cat ~/.claude-oreillyit/last-mode`
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
|
||||||
|
The user wants to switch engagement mode. Follow these steps exactly.
|
||||||
|
|
||||||
|
### Step 1: Build the mode menu
|
||||||
|
|
||||||
|
Read each `.md` file in `/home/paul/dev/claude/small-scripts/data/claude-profile/modes/` using the Read tool.
|
||||||
|
From each file's frontmatter, extract:
|
||||||
|
- `name` — the mode identifier
|
||||||
|
- `tag` — display tag (same as name usually)
|
||||||
|
- `driver` — the driver model
|
||||||
|
- `escalates_to` — escalation model (or "none")
|
||||||
|
|
||||||
|
From the body, read the `## Purpose` section to get a one-line description.
|
||||||
|
|
||||||
|
Present a numbered menu like this (order: quick, deep, hybrid, orch, chat):
|
||||||
|
|
||||||
|
```
|
||||||
|
Available modes:
|
||||||
|
|
||||||
|
1. quick [Sonnet] One small focused job — get in, get out
|
||||||
|
2. deep [Sonnet -> Opus] Hard design/debug, plan-first, spec-driven
|
||||||
|
3. hybrid [Haiku -> Opus] Long sessions, cheap driver, escalate on demand
|
||||||
|
4. orch [Sonnet] Parallel container agents, orchestration focus
|
||||||
|
5. chat [Haiku] No project, just conversation
|
||||||
|
```
|
||||||
|
|
||||||
|
Mark the current mode (from `active-mode.env`'s `CLAUDE_MODE`) with `(current)`.
|
||||||
|
|
||||||
|
If `$ARGUMENTS` is non-empty and matches a mode name, skip the menu and go directly to Step 2 with that mode.
|
||||||
|
|
||||||
|
### Step 2: Confirm selection
|
||||||
|
|
||||||
|
Ask the user which mode number (or name) they want to switch to.
|
||||||
|
Wait for their response. If they already specified a mode in `$ARGUMENTS` or the menu was skipped, confirm it: "Switching to `<name>` mode — confirm? (y/n)"
|
||||||
|
|
||||||
|
### Step 3: Read the target mode file
|
||||||
|
|
||||||
|
Use the Read tool to read the full content of `/home/paul/dev/claude/small-scripts/data/claude-profile/modes/<name>.md`.
|
||||||
|
|
||||||
|
Extract all frontmatter fields:
|
||||||
|
- `name`
|
||||||
|
- `tag`
|
||||||
|
- `driver`
|
||||||
|
- `async_ok`
|
||||||
|
- `autoloop`
|
||||||
|
- `plan_mode_auto`
|
||||||
|
- `spec_driven`
|
||||||
|
- `escalates_to`
|
||||||
|
|
||||||
|
Compute the full mode file path: `/home/paul/dev/claude/small-scripts/data/claude-profile/modes/<name>.md`
|
||||||
|
|
||||||
|
### Step 4: Write active-mode.env
|
||||||
|
|
||||||
|
Write `/home/paul/.claude-oreillyit/active-mode.env` with this exact format (substitute the values from the frontmatter):
|
||||||
|
|
||||||
|
```
|
||||||
|
CLAUDE_MODE=<name>
|
||||||
|
CLAUDE_MODE_TAG=<tag>
|
||||||
|
CLAUDE_DRIVER=<driver>
|
||||||
|
CLAUDE_ESCALATES_TO=<escalates_to>
|
||||||
|
CLAUDE_PROJECT=
|
||||||
|
CLAUDE_TIME_HORIZON=2
|
||||||
|
CLAUDE_ASYNC_OK=<async_ok>
|
||||||
|
CLAUDE_AUTOLOOP=<autoloop>
|
||||||
|
CLAUDE_PLAN_MODE_AUTO=<plan_mode_auto>
|
||||||
|
CLAUDE_SPEC_DRIVEN=<spec_driven>
|
||||||
|
CLAUDE_MODE_FILE=/home/paul/dev/claude/small-scripts/data/claude-profile/modes/<name>.md
|
||||||
|
```
|
||||||
|
|
||||||
|
For `CLAUDE_PROJECT=` — leave the value empty (no project context is carried across a mode switch initiated mid-session; the user will set it at relaunch).
|
||||||
|
|
||||||
|
### Step 5: Write last-mode
|
||||||
|
|
||||||
|
Write `/home/paul/.claude-oreillyit/last-mode` with just the mode name and a trailing newline:
|
||||||
|
|
||||||
|
```
|
||||||
|
<name>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 6: Adopt the new workflow stance
|
||||||
|
|
||||||
|
Read the full body of the new mode's `.md` file (everything after the closing `---` of the frontmatter). This is the mode's instructions to Claude.
|
||||||
|
|
||||||
|
Tell the user:
|
||||||
|
|
||||||
|
> Mode updated to `<name>`. The new mode will be fully active after `/clear` + relaunch (driver model `<current-driver>` cannot change mid-session).
|
||||||
|
>
|
||||||
|
> In this session, the following changes are active immediately:
|
||||||
|
> - **Workflow stance**: [summarise the key stance change in 1-2 sentences based on the mode body]
|
||||||
|
> - **Subagent policy**: [summarise from the Subagent policy section]
|
||||||
|
> - **Async policy**: [enabled / disabled based on async_ok]
|
||||||
|
> - **Plan mode**: [auto / manual / never, from plan_mode_auto]
|
||||||
|
>
|
||||||
|
> Adopting new stance now.
|
||||||
|
|
||||||
|
Then behave according to the new mode's body prose for the remainder of the session. The driver model (`<current-driver>`) is fixed — acknowledge this if the new mode's driver differs.
|
||||||
|
|
||||||
|
### Error handling
|
||||||
|
|
||||||
|
- If `$ARGUMENTS` is set but does not match any mode name: say "Unknown mode: `<arg>`. Available modes: quick, deep, hybrid, orch, chat." and show the menu.
|
||||||
|
- If the user picks their current mode: say "You are already in `<name>` mode. No change made." and stop.
|
||||||
|
- If a file write fails: report the error and tell the user to check permissions on `/home/paul/.claude-oreillyit/`.
|
||||||
Reference in New Issue
Block a user