---
name: v1-goldpan
description: Use when panning recent merged PRs and agent session logs (Claude Code, Codex, Cursor) for compound-worthy moments to document, then queueing the gold through /ce-compound. Triggers on "goldpan", "pan for compound candidates", "pan for gems", "what should I /ce-compound", "find solutions to document", "scan sessions for learnings", "what did we learn last week", "compound candidates", "/v1-goldpan".
allowed-tools:
  - Bash
  - Read
  - Write
  - Edit
  - Grep
  - Glob
  - Skill
  - Agent
  - ToolSearch
  - AskUserQuestion
---
# Goldpan

Pan recent merged PRs and agent session logs (Claude Code + Codex + Cursor) for compound-worthy moments worth documenting, present the finds for approval, then drive `/ce-compound` (lightweight mode) sequentially over the approved set. Discovery is automatic; documentation only happens for items the user approves.

This skill composes two existing primitives — `ce-compound` (writes solution docs) and `ce-session-inventory` + `ce-session-extract` (cross-platform session reading) — and adds the panning workflow around them. It does not write to `docs/solutions/` directly; that is `/ce-compound`'s job.

## Quick Start

1. Confirm the time window (default `7d`).
2. **Calibration check** (Phase 0): if no project signals file exists, prompt to calibrate.
3. Launch two scout subagents in parallel — Scout A (merged PRs) and Scout B+C (sessions across all platforms).
4. De-dup candidates against the project's solutions docs.
5. Write `.agents/goldpan/session-notes/compound-candidates-<YYYY-MM-DD>.md` and present the top candidates inline.
6. Ask the user which candidates to queue. For each approved candidate, stage a context bundle and invoke `/ce-compound` in lightweight mode sequentially.

The skill never writes directly into `docs/solutions/` — `/ce-compound` owns that path. The skill only invokes `/ce-compound` after explicit per-candidate approval.

## When to Use

Use when the user wants to look back over recent activity and identify what is worth documenting as a durable solution — typically weekly or after a sprint. Compounding requires fresh material: this skill finds the material, `/ce-compound` writes the doc.

Do not use for:
- Documenting a problem solved in the **current** session — use `/ce-compound` directly.
- Auditing or refreshing existing solution docs — use `/ce-compound-refresh`.
- Reviewing PRs for code quality — use `/v1-code-review`.

## Inputs

Pass the window as the skill's argument when invoking, e.g. `/v1-goldpan 14d`. Accepts `Nd` (days), an explicit `since:YYYY-MM-DD`, or the literal `recalibrate` to force a fresh calibration pass before scouting. Default `7d`.

If the user does not specify a window, ask once: "Default 7-day window — adjust?". Do not loop.

## Configuration

Read these per-project files when present; fall back to defaults otherwise:

| File | Default | Purpose |
|---|---|---|
| `.agents/goldpan-signals.md` | absent | Calibrated, project-specific PR signals (verbatim phrases, anti-signals, subsystem priorities, calibration PR set). Generated by Phase 0 calibration. |
| `docs/solutions/` | this path | Where solution docs live. Symlinks accepted. Override by reading `.agents/goldpan.config.yaml` if present (key: `solutions_path`). |
| Default PR base branch | `main` | Override via `.agents/goldpan.config.yaml` (key: `pr_base_branch`). |

If `.agents/goldpan-signals.md` is absent the skill still works using only the universal-signal keyword set, but scoring will be weaker until calibration runs.

## Workflow

### Phase 0: Calibration check

On every invocation:

1. Check for `.agents/goldpan-signals.md`. If present, skip to Phase 1.
2. If absent, present a blocking question to the user:
   - **Calibrate now (recommended, ~3-5 min)** — run the calibration workflow described in [references/calibration.md](references/calibration.md), which dispatches 4 parallel research agents over the project's recent PRs to characterize PR style, identify verbatim signals, and write `.agents/goldpan-signals.md`. After calibration completes, proceed to Phase 1.
   - **Skip — use universal signals only** — proceed to Phase 1 with weaker scoring. Note in the final report that the project has no calibrated signals.
   - **Cancel** — abort the goldpan run.

If the user passed `recalibrate` as the argument, force-run calibration regardless of whether the signals file exists, overwriting it.

The calibration is one-time. Re-run it after major team or codebase changes (new authors, large refactors, framework migrations) by invoking `/v1-goldpan recalibrate`.

### Phase 1: Resolve window and dispatch scouts

1. Resolve the window into:
   - `since_date` — `YYYY-MM-DD` (today minus N days)
   - `mtime_days` — integer N for `find -mtime -N`
2. Launch the two scouts below **in parallel** as `general-purpose` Agents. Each scout returns a structured text digest (no files written).

The scout prompts must:
- Tell the scout this is for panning `/ce-compound` candidates out of recent activity.
- Pass [references/scoring.md](references/scoring.md) inline (universal rubric).
- If `.agents/goldpan-signals.md` exists, pass it inline too (project-specific evidence).
- Demand the structured candidate format below.
- Cap output (e.g. "up to 12 candidates").

#### Scout A — Merged PRs

Brief: shortlist compound-worthy merged PRs from the window. Score against [references/scoring.md](references/scoring.md) and (if present) the project's `.agents/goldpan-signals.md`. **Do not score on assumed language; only the rubric and the calibrated evidence catalogued in those files.**

Tooling:
```bash
# 1. Pull all merged PRs in window with full bodies + file lists in one call
BASE_BRANCH="main"   # override from .agents/goldpan.config.yaml if present
gh pr list --state merged --base "$BASE_BRANCH" \
  --search "merged:>=<since_date>" \
  --json number,title,mergedAt,author,body,files \
  --limit 200

# 2. Drop anti-signals (per scoring.md and project signals file) before any further reads.
# 3. For survivors, pull commits and read the diff:
gh pr view <number> --json body,commits,files
gh pr diff <number> | head -400          # cap diff reads
```

**Strongest single tell is in the diff, not the body**: any PR that adds an `AIDEV-NOTE:` (or equivalent project-specific marker noted in the signals file) is almost certainly compound-worthy regardless of body quality.

**Calibration**: the project signals file's "Calibration PRs" section, if present, lists ~10 known compound-worthy PRs from a prior window. Use them as a sanity check — if your scout's candidate set diverges wildly from that calibration set, your filter is miscalibrated.

#### Scout B+C — Agent sessions (Claude Code, Codex, Cursor)

Run as **one** scout, not two. The compound-engineering plugin already owns the cross-platform layout knowledge through `ce-session-inventory` and `ce-session-extract`; this skill composes them rather than re-implementing JSONL parsing.

Brief: discover agent sessions touched within the window for this project, rank them by compound-signal density via the keyword filter, then deep-dive only the top-ranked sessions. Cross-reference any session whose `branch`/`gitBranch` matches a merged-PR head branch from Scout A and treat it as supporting evidence for that PR rather than a separate candidate. Standalone candidates from sessions are rarer; promote only when a session resolves a problem that did NOT result in a PR (e.g. an investigation, a runbook gap, or a convention agreed in chat).

**Step 1 — Discover and rank** with the bundled wrapper (see [scripts/discover-sessions.sh](scripts/discover-sessions.sh)):

```bash
bash <skill-path>/scripts/discover-sessions.sh <N>
```

The wrapper invokes `ce-session-inventory`'s `discover-sessions.sh` (Claude + Codex active + Cursor) plus a one-line `find` over `~/.codex/archived_sessions/` to fill an upstream gap, then pipes everything through `ce-session-inventory`'s `extract-metadata.py` with a compound-signal keyword set baked in. Output is JSONL — one session per line with `match_count` and `keyword_matches`, plus a final `_meta` line.

The default keyword set is the universal compound signals: `AIDEV-NOTE`, `Root Cause`, `failure mode`, `that worked`, `it's fixed`, `working now`, `lgtm`, `problem solved`, `ship it`, etc. If the project's signals file lists additional verbatim phrases, the scout should append them via the `COMPOUND_SIGNAL_KEYWORDS` env var.

**Step 2 — Triage**: drop sessions with `match_count: 0`; sort by `match_count`; cap to the top ~20 per platform. For each surviving session, the metadata line gives `branch`, `last_ts`, and `size` — branch matching against Scout A is the cheapest dedup.

**Step 3 — Deep-dive** only the top sessions, using `ce-session-extract` rather than reading raw JSONL:

```bash
CE_SKILLS_DIR="${CE_SKILLS_DIR:-}"
if [ -z "$CE_SKILLS_DIR" ]; then
  for dir in \
    "$HOME/.codex/plugins/cache/compound-engineering-plugin/compound-engineering"/*/skills; do
    [ -d "$dir/ce-session-extract/scripts" ] && CE_SKILLS_DIR="$dir" && break
  done
fi
if [ -z "$CE_SKILLS_DIR" ] && [ -d "$HOME/.claude/plugins" ]; then
  scripts_dir="$(find "$HOME/.claude/plugins" -path '*/compound-engineering/skills/ce-session-extract/scripts' -type d 2>/dev/null | sort | head -1)"
  [ -n "$scripts_dir" ] && CE_SKILLS_DIR="${scripts_dir%/ce-session-extract/scripts}"
fi
if [ -z "$CE_SKILLS_DIR" ]; then
  echo "ERROR: Could not find ce-session-extract" >&2
  exit 1
fi

EXT="$CE_SKILLS_DIR/ce-session-extract"

# Filtered narrative (user/assistant text + collapsed tool calls) — cap to last N lines
cat <session-file> | python3 "$EXT/scripts/extract-skeleton.py" | tail -n 200

# Tool errors only (Claude is_error: true / Codex non-zero exec)
cat <session-file> | python3 "$EXT/scripts/extract-errors.py"
```

Skeleton mode strips thinking blocks and tool-result noise and collapses repeat calls — three orders of magnitude smaller than the raw file. Errors mode surfaces the failed approaches that often anchor a "What didn't work" section.

Anti-signals (drop the session candidate):
- Last user turn is a follow-up question or correction (resolution didn't land)
- Session ends mid-tool-use (interrupted)
- Branch already matches a PR Scout A surfaced — fold into that PR's candidate
- Skeleton ends with assistant message containing a `docs/solutions/...` path — already documented

### Phase 2: Consolidate and de-dup

1. Collect each scout's candidate list.
2. Merge candidates that describe the same underlying problem (a PR plus the session that produced it count as one candidate — keep both source pointers).
3. De-dup against existing solutions: for each candidate, run targeted greps in the project's solutions path:
   ```bash
   SOLUTIONS_PATH="docs/solutions"   # override from goldpan.config.yaml if present
   grep -ril "<keyword>" "$SOLUTIONS_PATH"/ | head -5
   ```
   If a clear existing match is found, mark the candidate as **covered** and demote it (keep in the report under a separate "Already documented" section so the user can decide to refresh).
4. Score each candidate against the rubric in [references/scoring.md](references/scoring.md) — High / Medium / Low.

### Phase 3: Write the report

Write to `.agents/goldpan/session-notes/compound-candidates-<today>.md` using the template in [references/report-template.md](references/report-template.md). Inline in the chat, list only the **High** candidates with a one-line synopsis and a copy-paste `/ce-compound` invocation hint, then move directly into Phase 4.

### Phase 4: Approval & Queue

After printing the inline summary (High candidates only), get explicit approval before invoking `/ce-compound`. Then drive the queue sequentially.

#### 4a. Multi-select approval

Use `AskUserQuestion` with `multiSelect: true` to present the High candidates plus a "None — stop here" option. Offer Medium candidates only if the user asks. The schema for `AskUserQuestion` is deferred — call `ToolSearch` with `select:AskUserQuestion` first to load it.

If `AskUserQuestion` is unavailable (non-Claude-Code harness, or call errors), fall back to a numbered chat prompt: "Reply with the comma-separated numbers to queue, or `none`." Do not silently skip the prompt and do not pre-select any candidates.

#### 4b. Stage one context bundle per approved candidate

For each approved candidate, write `.agents/goldpan/session-notes/compound-queue/<YYYY-MM-DD>-<slug>.md` containing the synthesized evidence. The bundle is the input that `/ce-compound` will treat as "the recently solved problem". Format:

```markdown
# Queued compound candidate: <title>

**Source:** PR #<n> | Claude session `<id>` | Codex session `<id>`
**Track:** bug | knowledge
**Suggested category:** <category>/
**Component:** <service-or-module>

## Problem
<the problem in 2-4 sentences, sourced from PR body / session messages>

## What didn't work
<failed approaches, in bullets — bug track only; omit for knowledge track>

## Solution
<the verified fix, with code snippets pulled directly from the PR diff or session>

## Why this works
<root cause + why this addresses it>

## Evidence
- PR #<n>: <url>
- Claude session: <path>
- Codex session: <path>
- Key commits: <sha-list>
```

The bundle must be self-contained — `/ce-compound` should not need to re-derive anything from session logs. Pull diff snippets, error messages, and the verifying-it-worked statement directly from the source.

If the synthesis is thin (the source material lacks a clear problem/solution narrative), abort that candidate, log "skipped: thin evidence" in chat, and continue to the next one. Do not invent details.

#### 4c. Sequential invocation

For each staged bundle, invoke the compound skill via the `Skill` tool, one at a time:

```
Skill(skill: "compound-engineering:ce-compound", args: "<title> — see .agents/goldpan/session-notes/compound-queue/<file>")
```

Before the call, print the bundle contents into chat as plain markdown so `/ce-compound`'s Phase 0/1 sees the problem in recent conversation. When `/ce-compound` asks Full vs Lightweight, pick **Lightweight** unless the user explicitly chose Full at approval time. When it asks about session-history search, choose **No** — this skill already panned the relevant sessions.

Process one candidate fully before starting the next. After each completes, print a one-line status: `OK docs/solutions/<category>/<file>.md (or updated)`. If `/ce-compound` reports a failure, mark the bundle file with `# STATUS: failed — <reason>` at the top and continue to the next.

#### 4d. Final summary

After the queue drains, print:

```
Queue complete. Documented N of M approved candidates.
- OK <path1>
- OK <path2>
- FAIL <path3>  (skipped: <reason>)

Bundles retained at .agents/goldpan/session-notes/compound-queue/ — delete after review.
```

Do not write to `docs/solutions/` directly. All documentation goes through `/ce-compound`.

## Candidate Schema (what scouts return)

Every candidate must have:

```yaml
title: short imperative phrase                # e.g. "Why CacheManager Redis/S3 reads diverge"
source:                                       # one or more
  - pr: <number>                              # OR session: <id> + platform: claude|codex|cursor
  - session: <session-id>
    platform: claude
date: YYYY-MM-DD
track: bug | knowledge
suggested_category: <category>                # from /ce-compound's schema
synopsis: 3-5 sentence summary
why_compound_worthy: one sentence
keywords: [list, for, dedup]
verified: true | false                        # was the fix actually shipped/verified?
```

## Reference Files

- [references/scoring.md](references/scoring.md) — universal compound-worthiness rubric defined against `/ce-compound`'s schema
- [references/calibration.md](references/calibration.md) — Phase 0 calibration workflow that generates `.agents/goldpan-signals.md`
- [references/pr-signals-template.md](references/pr-signals-template.md) — template the calibration writes to (also a manual-fill option)
- [references/sources.md](references/sources.md) — source catalogue and how scouts compose `ce-session-inventory` + `ce-session-extract`
- [references/report-template.md](references/report-template.md) — output report template
- [scripts/discover-sessions.sh](scripts/discover-sessions.sh) — wraps `ce-session-inventory` with archived-codex gap fill + pre-baked compound-signal keywords

## Upstream Primitives Used

This skill composes (rather than re-implements) primitives from [Every's compound-engineering plugin](https://github.com/EveryInc/compound-engineering-plugin):

- **`ce-compound`** — writes the actual solution doc. Owns `docs/solutions/` and the schema.
- **`ce-session-inventory`** — cross-platform session discovery + metadata + keyword ranking. Owned scripts: `discover-sessions.sh`, `extract-metadata.py`. Wrapped by `scripts/discover-sessions.sh`.
- **`ce-session-extract`** — single-file skeleton (filtered narrative) or errors mode. Owned scripts: `extract-skeleton.py`, `extract-errors.py`. Used directly by Scout B+C deep-dives.

If those primitives are absent (compound-engineering plugin uninstalled), the wrapper exits with a clear error. Install the compound-engineering plugin rather than re-implementing — see [v1tamins README → Recommended companion](../../../../README.md#recommended-companion-compound-engineering) for install commands.

## Anti-Patterns

- **Don't read full session transcripts.** Use `ce-session-extract` skeleton mode; never bulk-load JSONL.
- **Don't fabricate candidates.** If a session has no clear "fix shipped + root cause" signal, skip it.
- **Don't write into `docs/solutions/`.** That's `/ce-compound`'s job — even from Phase 4.
- **Don't queue without explicit approval.** Phase 4a is gated on a blocking question. No silent auto-approve, no defaulting to "all High".
- **Don't queue thin candidates.** If the synthesized bundle would be vague or speculative, drop it before invoking `/ce-compound`.
- **Don't run queued items in parallel.** `/ce-compound` is sequential by design and the conversation context needs to reset between items.
- **Don't include `/ce-compound`-style full prose** in the candidate report. The synopsis is a pointer; the staged bundle is the evidence.
- **Don't skip calibration silently.** If signals file is missing, present the choice; don't just degrade quality without telling the user.
