feat(diagnosing-superpowers): structure test and verified harness session references

Claude-Session: https://claude.ai/code/session_01DyaGKhTXvHNs2JgPhDktz7
This commit is contained in:
Jesse Vincent
2026-08-28 10:15:15 -07:00
parent b000813ddc
commit 83269b3086
4 changed files with 335 additions and 0 deletions
@@ -0,0 +1,100 @@
# Claude Code session store
Verified against: Claude Code 2.1.247 (transcript `version` field), macOS.
When a field below is missing from the file in front of you, trust the file
and say so in coverage notes.
## Where
- Main transcript: `~/.claude/projects/<cwd-slug>/<sessionId>.jsonl`, where
`<cwd-slug>` is the working directory with every `/` replaced by `-`
(e.g. `/tmp/work``-tmp-work`).
- Subagent transcripts: `~/.claude/projects/<cwd-slug>/<sessionId>/subagents/agent-<agentId>.jsonl`,
each with a sibling `agent-<agentId>.meta.json`
(`agentType`, `description`, `toolUseId`, `spawnDepth`, optional `model`).
- Plugin registry: `~/.claude/plugins/installed_plugins.json` — per plugin:
`installPath`, `version`, `installedAt`, `lastUpdated`, `gitCommitSha`.
- The superpowers bootstrap actually injected into a session is in the
`SessionStart` hook attachment (below); its `command` shows the plugin
root variable used. A dev checkout loaded with `--plugin-dir` will not be
in the registry, so report both the registry entry and the hook evidence.
## Which file is the current session
The most recently modified `.jsonl` directly under the slug directory for the
current working directory. Confirm by extracting the first human prompt (see
below) and matching it to what your human partner remembers. If two files
are close in mtime, show both first prompts and ask.
## Line types
Every line is one JSON object. `type` values seen: `user`, `assistant`,
`attachment`, `system`, plus session-level records (`permission-mode`,
`mode`, `bridge-session`, `last-prompt`, `ai-title`, `atis-latch`,
`pr-link`, `queue-operation`, `relocated`, `worktree-state`).
Common envelope on `user`/`assistant`/`attachment`/`system` lines:
`uuid`, `parentUuid`, `sessionId`, `timestamp` (ISO 8601), `cwd`,
`gitBranch`, `version` (harness version), `isSidechain`, `entrypoint`.
| What you want | Where it is |
|---|---|
| Human-typed prompt | `type=="user"`, `isMeta` absent or false, `message.content` is a string or a list whose first block is `type:"text"`. Lines whose first block is `tool_result` are tool results, not prompts. `<system-reminder>` text inside a prompt is injected, not typed. |
| Assistant text / tool calls | `type=="assistant"`, `message.content[]` blocks of `type:"text"` or `type:"tool_use"` (`id`, `name`, `input`). |
| Tool result | `type=="user"`, `message.content[0].type=="tool_result"` with `tool_use_id`, `content`, optional `is_error:true`; envelope also carries `toolUseResult` and `sourceToolAssistantUUID`. |
| Model | `message.model` on assistant lines. |
| Tokens | `message.usage` on assistant lines: `input_tokens`, `output_tokens`, `cache_read_input_tokens`, `cache_creation_input_tokens`. |
| Skill invocation | `tool_use` block with `name:"Skill"` and `input.skill` (e.g. `superpowers:brainstorming`); the tool result line has `toolUseResult.commandName`. |
| Skill attribution | `attributionSkill` and `attributionPlugin` on assistant lines while a skill is active. |
| Subagent dispatch | `tool_use` with `name:"Agent"` (`input.description`, `input.subagent_type`, `input.prompt`); the subagent's own file is matched by `toolUseId` in its `.meta.json`. Subagent lines have `isSidechain:true` and `agentId`. |
| Hook output | `type=="attachment"`, `attachment.type` `hook_success`/`hook_failure`, `attachment.hookName` (e.g. `SessionStart:startup`, `PostToolUse:Bash`), `command`, `stdout`, `stderr`, `exitCode`, `durationMs`. |
| Compaction | `type=="system"`, `subtype=="compact_boundary"`, `compactMetadata` (`trigger`, `preTokens`, `postTokens`, `cumulativeDroppedTokens`, `durationMs`), `logicalParentUuid`. |
| Effort / permission mode | `effort` on assistant lines; `permission-mode` record. |
## Safe extraction
Lines can exceed a megabyte. Never print a whole line. Check size first:
```bash
F=~/.claude/projects/<slug>/<id>.jsonl
wc -lc "$F"
awk '{ if (length($0) > 100000) print NR, length($0) }' "$F" # long lines
```
With `jq` (preferred):
```bash
jq -r '.type' "$F" | sort | uniq -c # line-type census
jq -r 'select(.type=="user" and .isMeta!=true and ((.message.content|type)=="string" or .message.content[0].type=="text"))
| "\(input_line_number)\t\(.timestamp)\t\((.message.content|if type=="string" then . else .[0].text end)[0:160])"' "$F" # human prompts
jq -c 'select(.type=="assistant") | .message.content[]? | select(.type=="tool_use")
| {name, id, input: (.input|tostring|.[0:120])}' "$F" # tool calls
jq -r 'select(.type=="assistant") | .message.content[]? | select(.type=="tool_use" and .name=="Skill") | .input.skill' "$F" # skill invocations
jq -c 'select(.type=="assistant") | {ts:.timestamp, model:.message.model, skill:.attributionSkill,
u:(.message.usage|{input_tokens,output_tokens,cache_read_input_tokens,cache_creation_input_tokens})}' "$F" # per-message usage
jq -c 'select(.subtype=="compact_boundary") | {line:input_line_number, ts:.timestamp,
m:(.compactMetadata|{trigger,preTokens,postTokens,cumulativeDroppedTokens,durationMs})}' "$F" # compactions (full compactMetadata also has UUID lists; keep this trimmed)
jq -c 'select(.type=="attachment" and (.attachment.type|startswith("hook"))) | {line:input_line_number, hook:.attachment.hookName, exit:.attachment.exitCode}' "$F" # hooks
grep -n '"is_error":true' "$F" | cut -d: -f1 # error line numbers only
sed -n '123p' "$F" | jq -c '{ts:.timestamp, first:((.message.content // "") as $c
| ($c | if type=="array" then ($c[0] // "") else $c end) | tostring | .[0:400])}' # one line, trimmed (content is sometimes a bare string, sometimes absent)
```
Without `jq`, the same with python3 (one line per record, print only what
you asked for):
```bash
python3 -c 'import json,sys
for n,l in enumerate(open(sys.argv[1]),1):
o=json.loads(l)
if o.get("type")=="assistant":
for b in o["message"].get("content",[]):
if b.get("type")=="tool_use": print(n, b["name"], str(b.get("input"))[:120])' "$F"
```
## Subagents
List `~/.claude/projects/<slug>/<id>/subagents/`. For each `agent-*.meta.json`
print `agentType`, `description`, `model`; the matching `.jsonl` is that
subagent's transcript and follows the same line format. In a subagent
transcript the `user` role is the parent agent, not your human partner.
@@ -0,0 +1,77 @@
# Codex session store
Verified against: Codex CLI 0.146.0 and 0.147.0 rollouts (`cli_version` in
`session_meta`), macOS. When a field below is missing from the file in front
of you, trust the file and say so in coverage notes.
## Where
`~/.codex/sessions/YYYY/MM/DD/rollout-<ISO-timestamp>-<thread-id>.jsonl`.
Subagent threads are separate rollout files whose `session_meta.payload`
has `thread_source: "subagent"` and `source.subagent.thread_spawn.parent_thread_id`
pointing at the parent thread id. Root sessions have `thread_source: "user"`.
## Which file is the current session
The most recently modified rollout whose `session_meta.payload.cwd` is the
current working directory and whose `thread_source` is `user`. Confirm by
matching the first `user_message` event to what your human partner
remembers.
## Line types
Every line is `{timestamp, type, payload}` (some also carry `ordinal`).
`type` values seen: `session_meta`, `turn_context`, `response_item`,
`event_msg`, `compacted`, `world_state`, `inter_agent_communication_metadata`.
| What you want | Where it is |
|---|---|
| Session identity | `session_meta.payload`: `id`, `session_id`, `cwd`, `originator` (e.g. `Codex Desktop`), `cli_version`, `model_provider`, `thread_source`, `source`, `git` (`commit_hash`, `branch`, `repository_url`), `base_instructions.text`. |
| Model per turn | `turn_context.payload`: `turn_id`, `model`, `effort`, `cwd`, `approval_policy`, `sandbox_policy`, `multi_agent_version`. Also `event_msg` `thread_settings_applied`. |
| Human-typed prompt | `event_msg` with `payload.type=="user_message"`: `payload.message`. (`response_item` messages with `role:"developer"` are injected, not typed; see Subagents below for rollouts that carry no `user_message` event at all.) |
| Assistant text | `event_msg` `agent_message` (`payload.message`, `payload.phase`) or `response_item` `message` with `role:"assistant"`. |
| Tool calls | `response_item` with `payload.type` `function_call` (`name`, `arguments`, `call_id`) or `custom_tool_call` (`name`, `input`, `call_id`); outputs are `function_call_output` / `custom_tool_call_output` matched by `call_id`. Also `event_msg` `patch_apply_end` (`success`, `changes`), `web_search_end`, `mcp_tool_call_end` (`invocation.server`, `invocation.tool`). |
| Turn timing | `event_msg` `task_started` (`turn_id`, `started_at`, `model_context_window`) and `task_complete` (`duration_ms`, `time_to_first_token_ms`, `last_agent_message`); `turn_aborted` (`reason`, `duration_ms`). |
| Tokens | `event_msg` `token_count`: `payload.info.total_token_usage` (cumulative; keys include `input_tokens`, `cached_input_tokens`, `output_tokens`) and `payload.rate_limits`. |
| Compaction | a `compacted` line (`window_id`, `previous_window_id`, `replacement_history`) and an `event_msg` `context_compacted`. |
| Subagents | `event_msg` `sub_agent_activity` (`agent_thread_id`, `agent_path`, `kind`); `response_item` `agent_message` with `author`/`recipient`; the child's own rollout file (see Where). |
| Skill use | No attribution field. Look for `SKILL.md` in `function_call.arguments` / `custom_tool_call.input` and in `world_state`/`session_meta` instruction text. |
| Reasoning | `response_item` `reasoning` (`summary[].text`; `encrypted_content` is opaque). |
## Safe extraction
Rollouts reach hundreds of megabytes; `compacted` lines embed whole
histories. Never print a whole line. Check size first:
```bash
F=~/.codex/sessions/YYYY/MM/DD/rollout-....jsonl
wc -lc "$F"
awk '{ if (length($0) > 100000) print NR, length($0) }' "$F"
```
With `jq`:
```bash
head -1 "$F" | jq '.payload | {id, cwd, originator, cli_version, model_provider, thread_source, git}' # identity
jq -r '.type + "/" + (.payload.type // "")' "$F" | sort | uniq -c # census
jq -r 'select(.type=="event_msg" and .payload.type=="user_message") | "\(input_line_number)\t\(.timestamp)\t\(.payload.message[0:160])"' "$F" # human prompts
jq -r 'select(.type=="turn_context") | "\(.timestamp)\t\(.payload.model)\t\(.payload.effort)"' "$F" # model per turn
jq -c 'select(.type=="response_item" and (.payload.type=="function_call" or .payload.type=="custom_tool_call"))
| {line:input_line_number, name:.payload.name, args:((.payload.arguments // .payload.input)|tostring|.[0:120])}' "$F" # tool calls
jq -c 'select(.payload.type=="task_complete" or .payload.type=="turn_aborted") | {ts:.timestamp, type:.payload.type, ms:.payload.duration_ms}' "$F" # turn timing
jq -c 'select(.payload.type=="token_count") | {ts:.timestamp, t:.payload.info.total_token_usage}' "$F" # tokens (cumulative)
grep -n '"type":"compacted"\|"context_compacted"' "$F" | cut -d: -f1 # compaction line numbers
grep -n 'SKILL\.md' "$F" | cut -d: -f1 # skill-read line numbers
sed -n '123p' "$F" | jq -c '{ts:.timestamp, type, p:(.payload|tostring|.[0:400])}' # one line, trimmed
```
Find a thread's subagent rollouts (filenames only, never content):
```bash
grep -l '"parent_thread_id":"<thread-id>"' ~/.codex/sessions/*/*/*/rollout-*.jsonl
```
A subagent rollout can carry no `event_msg` `user_message` at all — the
parent agent's dispatch prompt instead shows up as a `response_item`
`message` with `role:"user"`. If a `user_message` event is present, it is
from the parent agent, not your human partner.
@@ -0,0 +1,30 @@
# Other harnesses: discover, then report what you found
This file is for any harness without a verified reference in this
directory. You know your own harness better than this file does. Use that
knowledge, and write down exactly what you found so the report reader can
judge it.
## Procedure
1. **Ask the harness.** Many harnesses expose a session or history command
(`<harness> session list`, `/sessions`, a "resume" picker). Use it to get
the session id and, if shown, the file path.
2. **Look under the harness's config directory** (`~/.<harness>/`,
`~/.config/<harness>/`, `~/.local/share/<harness>/`) for `sessions`,
`history`, `chats`, `threads`, or `projects` directories holding `.jsonl`
or `.json` files.
3. **Confirm a candidate** by extracting its first human message with a
size-safe command (`head -c 2000`, or `jq` on the first record) and
matching it to what your human partner remembers. Never print whole
lines; treat every candidate like the verified stores: `wc -lc` and a
long-line check before anything else.
4. **Map the fields you need** by reading a handful of records with `jq -c
'keys'` or `head -c`: human prompt, assistant text, tool call and result,
model, harness version, timestamps, subagent linkage, compaction.
5. **Record in the case file and the report's coverage notes**: the store
path, the layout you inferred, which of the fields above you could and
could not find, and your confidence. Field-level claims in the report
are marked "inferred from the file, not a documented format".
6. **If you cannot find the store**, say so and ask your human partner for
the path. Do not guess a layout from another harness.
+128
View File
@@ -0,0 +1,128 @@
#!/usr/bin/env bash
# Structural checks for skills/diagnosing-superpowers. Behavior is tested by
# the scenarios in CREATION-LOG.md; this script only checks the things a
# shell can check: frontmatter, referenced files exist, no local paths or
# names leaked into shipped files, SKILL.md word budget.
set -u
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
SKILL_DIR="$REPO_ROOT/skills/diagnosing-superpowers"
SKILL_MD="$SKILL_DIR/SKILL.md"
WORD_BUDGET=900
PASSES=0
FAILURES=0
pass() { echo " [PASS] $1"; PASSES=$((PASSES + 1)); }
fail() { echo " [FAIL] $1"; FAILURES=$((FAILURES + 1)); }
echo "diagnosing-superpowers structure"
# --- SKILL.md frontmatter -------------------------------------------------
if [ -f "$SKILL_MD" ]; then
pass "SKILL.md exists"
frontmatter="$(awk 'NR==1 && $0!="---"{exit} NR>1 && $0=="---"{exit} NR>1{print}' "$SKILL_MD")"
if printf '%s\n' "$frontmatter" | grep -q '^name: diagnosing-superpowers$'; then
pass "frontmatter name is diagnosing-superpowers"
else
fail "frontmatter name is diagnosing-superpowers"
fi
description="$(printf '%s\n' "$frontmatter" | awk '/^description:/{sub(/^description:[ ]*/,""); print; found=1; next} found && /^[ ]/{print} found && !/^[ ]/{exit}' | tr '\n' ' ')"
if printf '%s' "$description" | grep -q '^Use when'; then
pass "description starts with 'Use when'"
else
fail "description starts with 'Use when' (got: ${description:0:60})"
fi
if [ "${#description}" -le 1024 ]; then
pass "description under 1024 characters"
else
fail "description under 1024 characters (${#description})"
fi
for banned in "dispatch" "then" "step"; do
if printf '%s' "$description" | grep -qiw "$banned"; then
fail "description contains workflow word '$banned'"
else
pass "description avoids workflow word '$banned'"
fi
done
# --- word budget --------------------------------------------------------
body_words="$(awk 'BEGIN{fm=0} NR==1 && $0=="---"{fm=1; next} fm==1 && $0=="---"{fm=2; next} fm==2{print}' "$SKILL_MD" | wc -w | tr -d ' ')"
if [ "$body_words" -le "$WORD_BUDGET" ]; then
pass "SKILL.md body within $WORD_BUDGET words ($body_words)"
else
fail "SKILL.md body within $WORD_BUDGET words ($body_words)"
fi
# --- required sections --------------------------------------------------
for heading in "## Hard rules" "## Red Flags"; do
if grep -q "^$heading" "$SKILL_MD"; then
pass "SKILL.md has section '$heading'"
else
fail "SKILL.md has section '$heading'"
fi
done
# --- every referenced skill file exists --------------------------------
while IFS= read -r ref; do
if [ -f "$SKILL_DIR/$ref" ]; then
pass "referenced file exists: $ref"
else
fail "referenced file exists: $ref"
fi
done < <(grep -o '\(references\|prompts\|templates\)/[A-Za-z0-9._-]*\.md' "$SKILL_MD" | sort -u)
else
fail "SKILL.md exists"
fi
# --- expected files -------------------------------------------------------
expected_files=(
references/claude-code-sessions.md
references/codex-sessions.md
references/other-harnesses.md
prompts/skill-timeline.md
prompts/plan-adherence.md
prompts/repeated-work.md
prompts/stumbles.md
prompts/quality-evidence.md
prompts/request-conflicts.md
prompts/cost-and-time.md
prompts/scrub.md
prompts/scrub-audit.md
prompts/similar-session.md
templates/case.md
templates/report.md
templates/bundle-README.md
templates/issue.md
CREATION-LOG.md
)
for rel in "${expected_files[@]}"; do
if [ -f "$SKILL_DIR/$rel" ]; then
pass "expected file present: $rel"
else
fail "expected file present: $rel"
fi
done
# --- no local paths or names in shipped files ----------------------------
leaks="$(grep -rn -E '/Users/|/home/|jesse' "$SKILL_DIR" 2>/dev/null || true)"
if [ -z "$leaks" ]; then
pass "no machine-specific paths or names in shipped files"
else
fail "no machine-specific paths or names in shipped files"
printf '%s\n' "$leaks" | head -10 | sed 's/^/ /'
fi
# --- "the user" never appears in skill prose -----------------------------
user_hits="$(grep -rn -i 'the user' "$SKILL_DIR" --include='*.md' 2>/dev/null | grep -v CREATION-LOG.md || true)"
if [ -z "$user_hits" ]; then
pass "skill files say 'your human partner', not 'the user'"
else
fail "skill files say 'your human partner', not 'the user'"
printf '%s\n' "$user_hits" | head -10 | sed 's/^/ /'
fi
echo
echo "Passed: $PASSES Failed: $FAILURES"
[ "$FAILURES" -eq 0 ]