Work reporting from cross-tool AI session history. Reuses do-history-insights/scripts/ to collect session data from Claude Code, Codex, and Cursor, then dispatches a single @miner subagent to produce standup bullets, billable timesheets, or narrative recaps.
Phases
Every subagent prompt MUST be self-contained — include all prior-phase context explicitly.
Subagent dispatch policy: Each role uses the @miner agent type. Every dispatch prompt MUST include:
- The exact output file path (
.scratch/<session>/<prescribed-filename>.md) - The constraint: "Write your complete output to that path. You may read any repository file. Do NOT edit, create, or delete files outside
.scratch/<session>/. Do NOT run build commands, tests, or destructive shell commands."
Session ID: Generate per SPINE.md Sessions convention. Reuse across all phases.
1. Collect
Parse arguments, run parser scripts, collect git log.
Arguments:
--days N(default 7) — time window--format standup|timesheet|recap(default standup) — output format--project filter(optional) — case-insensitive substring match on project name
Generate session ID. Run parser scripts via Bash:
PYTHON=$(command -v python3 || command -v python)
if [ -z "$PYTHON" ]; then echo "Error: Python 3.9+ required but not found"; exit 1; fi
SINCE=$(date -v-${DAYS:-7}d +%Y-%m-%d)
SCRATCH=".scratch/<session>"
SCRIPTS="$HOME/.agents/skills/do-history-insights/scripts"
mkdir -p "$SCRATCH"
PYTHONPATH="$SCRIPTS" "$PYTHON" "$SCRIPTS/parse_claude.py" --since "$SINCE" --output "$SCRATCH"
PYTHONPATH="$SCRIPTS" "$PYTHON" "$SCRIPTS/parse_codex.py" --since "$SINCE" --output "$SCRATCH"
PYTHONPATH="$SCRIPTS" "$PYTHON" "$SCRIPTS/parse_cursor.py" --since "$SINCE" --output "$SCRATCH"
PYTHONPATH="$SCRIPTS" "$PYTHON" "$SCRIPTS/aggregate.py" --input "$SCRATCH" --output "$SCRATCH/analytics.json"
Verify analytics.json exists and has sessions. If summary.total_sessions == 0, report "No AI sessions found in the last N days. Try increasing --days." and stop.
Git log collection: After parsers run, extract unique project values from *_sessions.json files (e.g., kenoxa/spine, carv/identity-scribe). Resolve each to a filesystem path by checking ~/Projects/{project} and the current working directory. For each resolved path that is a git repository, run git log --since=$SINCE --oneline --no-merges. Write results to .scratch/<session>/git_log.json as {project: [commit_lines]}. Skip projects that can't be resolved, aren't git repos, or have no commits in range. This is best-effort — not all projects will resolve.
2. Dispatch
Single @miner subagent dispatch. Mode: recap.
The miner reads session files directly from disk — do not inline file contents in the dispatch prompt. Pass the scratch directory path so the miner can read *_sessions.json, git_log.json, and analytics.json as needed.
Construct the dispatch prompt by combining:
- Substitute variables into the Shared Preamble from references/recap-prompts.md:
{scratch_dir}→.scratch/<session>{project_filter}→ if--projectis set:Filter to sessions where \project` contains "<value>" (case-insensitive). If no match, list available projects.— if not set:No filter. Include all sessions.`
- Select the format-specific template matching
--format. Substitute:{preamble}→ the fully-substituted Shared Preamble from step 1{date_range}→N days (YYYY-MM-DD to YYYY-MM-DD)using the--daysvalue and computed start/end dates{output_path}→.scratch/<session>/report-{format}.md{analytics_summary}(recap format only) → read thesummaryobject fromanalytics.jsonand format as:Total sessions: N. Date range: YYYY-MM-DD to YYYY-MM-DD. Providers: Claude N, Codex N, Cursor N. Avg duration: N min. Total prompts: N.If--projectfilter is active, append:Sessions matching "<filter>": N.
| Role | Agent type | Input | Output |
|------|-----------|-------|--------|
| report-{format} | @miner | Scratch dir path + format-specific prompt | .scratch/<session>/report-{format}.md |
3. Present
Read .scratch/<session>/report-{format}.md. Display the contents directly in the terminal as markdown. No post-processing — the subagent output IS the final output.
Guidelines
- Data source: The miner reads raw
*_sessions.jsonfiles for per-session detail.analytics.jsonis only for summary stats (total sessions, provider breakdown, date range). - Project filter: Case-insensitive substring match on
session.project. When no sessions match, list available projects. - Format-specific rules: Encoded in the prompt templates — do not override them in the dispatch prompt.
Anti-Patterns
- Reading only
analytics.jsonfor session detail — it loses per-session data; the miner must read raw*_sessions.json - Processing or formatting data in the main thread — dispatch to
@miner - Inventing task descriptions when no data exists — use "unspecified task" with files list
- Dispatching multiple subagents — single
@minerdispatch per invocation - Modifying scripts in
do-history-insights/scripts/
Scan to join WeChat group