Transcript analysis
A curated collection of Claude Code skills — code-review loop, local chat-history search, session end/resume, Gemini image generation, transcript retrospectives — that run machine-wide with just python and node.
npx -y skills add BryceEWatson/claude-global-skills --skill transcript-analysisAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Analyze Cowork session transcripts for recurring narrative patterns — repeated instructions, planning loops, failure patterns, decision re-litigation, and knowledge re-establishment. Produces a structured report with CLAUDE.md candidates, unresolved loops, and pattern frequency data. Use this skill when the user wants to review what keeps repeating across sessions, extract lessons from past work, audit their collaboration patterns, or identify rules that should be encoded permanently. Triggers on: transcript analysis, session analysis, narrative analysis, what keeps repeating, review our sessions, cowork analysis, pattern analysis, what should go in CLAUDE.md, extract lessons, session retrospective, retro, session patterns.
SKILL.md
28.6 KB, ~6.7k tokens by cl100k_base, as published. Nobody here has run it
Transcript Analysis — Recurring Narrative Pattern Mining
Analyze all Cowork session transcripts for the current project to identify recurring patterns — repeated instructions, planning loops, failure regressions, decision re-litigation, and knowledge that has to be rebuilt each session. Produces a structured report with actionable recommendations.
Why This Skill Exists
After enough sessions, behavioral patterns emerge that are invisible within any single conversation: rules the user keeps re-stating, mistakes that keep recurring, planning discussions that never resolve, and context that has to be rebuilt every time. This skill surfaces those patterns so the important ones can be encoded into CLAUDE.md (or skills) and the rest can be consciously accepted or resolved.
When to Use This Skill
- The user asks "what keeps repeating across our sessions?"
- After a significant milestone (10+ sessions, major feature complete, quarterly review)
- When CLAUDE.md feels stale or incomplete
- When the user suspects the same mistakes keep happening
- Before a major architecture or workflow change (to understand current pain points)
Inputs
- Project folder path — defaults to the current working directory. Used to filter sessions by
userSelectedFoldersin Cowork manifests. - Optional: keyword filter — additional terms to match beyond folder path (e.g., brand names, product terms, tool names). The user can provide these or you can derive them from the project's CLAUDE.md / README.
- Optional: date range — restrict analysis to a specific period (e.g., "last 30 days", "since March 1")
Prerequisites
Cowork Transcripts
Cowork session transcripts live at (Windows):
%AppData%\Claude\local-agent-mode-sessions\ (current name)
%AppData%\Claude\claude-code-sessions\ (legacy name — check both)
The directory structure is:
<base>/<org-id>/<user-id>/
local_<session-uuid>.json ← session manifest (title, processName, timestamps, cliSessionId)
local_<session-uuid>/
audit.jsonl ← session cost, duration, turns
.claude/projects/-sessions-<processName>/
<cliSessionId>.jsonl ← primary transcript
<cliSessionId>/subagents/ ← subagent transcripts (optional)
Claude Code CLI Transcripts
CLI transcripts live at (Windows):
%USERPROFILE%\.claude\projects\<project-slug>\<session-id>.jsonl
Where <project-slug> is the working directory path with path separators replaced by dashes (e.g., c--Users-you-Projects-MyApp). These use the same JSONL schema as Cowork transcripts.
Platform Detection
Use os.path.expandvars() for Windows env vars or os.path.expanduser("~") for Unix-style paths. Check both Cowork and CLI paths; analyze whichever has data.
Workflow
Phase 1: Discover and Inventory Sessions
Step 1.1: Locate Transcript Sources
import os, glob
# Cowork transcripts (try both directory names)
appdata = os.environ.get('APPDATA', os.path.expanduser('~/.config'))
cowork_candidates = [
os.path.join(appdata, 'Claude', 'local-agent-mode-sessions'),
os.path.join(appdata, 'Claude', 'claude-code-sessions'),
]
cowork_base = next((c for c in cowork_candidates if os.path.isdir(c)), None)
# CLI transcripts
home = os.path.expanduser('~')
cli_base = os.path.join(home, '.claude', 'projects')
For Cowork: enumerate <cowork_base>/<org-id>/<user-id>/ to find the user directory (usually one org-id and one user-id).
For CLI: enumerate project slug directories matching the current project path.
Step 1.2: Read All Manifests (Cowork)
For each local_*.json file in the user directory, extract:
sessionId— unique session identifierprocessName— the VM process name (human-readable slug)cliSessionId— the CLI session UUID (needed to find the transcript JSONL)title— session title (most useful for filtering)createdAt— timestamp in millisecondsuserSelectedFolders— array of workspace paths the session had access toinitialMessage— the first user message (useful for filtering)
Step 1.3: Filter to Project-Relevant Sessions
Match sessions where ANY of these are true:
userSelectedFolderscontains the project folder path (case-insensitive)titlecontains any of the project keyword filtersinitialMessagecontains any of the project keyword filters
Keyword selection matters. Use project-specific terms: product names, brand names, platform names, tool names, workflow names. Cast a wide net — it's better to include marginal sessions than miss relevant ones.
Deriving keywords: If the user doesn't provide keywords, scan the project's CLAUDE.md, README.md, and package.json/pyproject.toml for project names, tool names, and domain terms. Use these as the keyword filter.
Step 1.4: Enrich with Audit Data
For each matching Cowork session, read <session-dir>/audit.jsonl. Each line is a JSON object. Look for the line with type: "result" or containing total_cost_usd — it has:
total_cost_usd— session costduration_ms— wall-clock durationnum_turns— conversation turns
CLI sessions don't have audit data — skip this step for CLI transcripts.
Step 1.5: Locate Transcripts
For Cowork sessions with a cliSessionId, find the transcript at:
<session-dir>/.claude/projects/-sessions-<processName>/<cliSessionId>.jsonl
Sessions without a cliSessionId are failed/aborted — skip them.
For CLI sessions, the transcript IS the JSONL file in the projects directory.
Step 1.6: Print Inventory Table
Output a table sorted by date descending:
Date Title Cost Mins Turns Source
──────────────────────────────────────────────────────────────────────────────────────────────────
2026-03-17 09:42 Experiment review mar17 $0.60 0.9 2 Cowork
2026-03-16 14:30 Fix auth bug n/a n/a 12 CLI
...
Include summary stats: total sessions, sessions with transcripts, total cost (Cowork only), total hours.
Phase 2: Extract Conversation Content
For each transcript JSONL file:
Step 2.1: Parse Lines
Each line is a JSON object with a type field. Process based on type:
type | Include? | Content location |
|---|---|---|
user | Yes | message.content (array of blocks or string) |
assistant | Yes | message.content (array of blocks) |
system | Situational | Usually skip — contains CLAUDE.md/system prompts |
queue-operation | No | Internal plumbing |
Exclude lines where:
isApiErrorMessageistrue(API errors, not conversation)isSidechainistrue(background operations)
Step 2.2: Extract Text
For content that is an array of blocks:
def extract_text(content):
if isinstance(content, str):
return content
if isinstance(content, list):
return '\n'.join(
block.get('text', '')
for block in content
if isinstance(block, dict) and block.get('type') == 'text'
)
return ''
Step 2.3: Clean and Truncate
- Strip
<scheduled-task>...</scheduled-task>blocks (boilerplate) - Strip
<system-reminder>...</system-reminder>blocks (system noise) - Strip
<ide_selection>...</ide_selection>blocks (editor context) - Strip
<file_contents>...</file_contents>blocks (file dumps) - Truncate individual messages to ~1500 chars (preserve signal, reduce volume)
- Skip messages shorter than 10 chars (empty confirmations)
Step 2.4: Handle Subagents (Optional)
If <cliSessionId>/subagents/ exists, parse each agent-*.jsonl using the same schema. Subagent transcripts are usually short but may contain delegated decision-making. Include them in the analysis tagged as subagent content.
Phase 3: Pattern Extraction
Analyze ALL extracted conversations across ALL sessions looking for six categories of recurring patterns. Use keyword matching as a first pass, then review matches for thematic clustering.
Category A: Repeated Instructions & Rules
Things the user keeps telling Claude that should be in CLAUDE.md or skills:
| Signal pattern | What it indicates |
|---|---|
| "make sure", "always", "never", "remember to" | Instruction the user has given before |
| "don't forget", "please don't", "stop doing" | Correction of a repeated mistake |
| "I told you", "I said", "we discussed" | Re-establishment of a prior instruction |
| "update the state", "update session" | Process step being forgotten |
| "use the skill", "read the skill first" | Skill bypass |
| Repeated file path or format corrections | Convention not encoded |
Cluster by topic — group related corrections together (e.g., all path-related corrections, all state-update reminders).
Category B: Planning Loops
Topics where the project keeps re-planning without resolving:
| Signal pattern | What it indicates |
|---|---|
| "what should we do next", "priority", "what's next" | Re-prioritization loop |
| "let's plan", "create a prompt for next session" | Session handoff without execution |
| Session titles containing "plan", "next steps", "priorities" | Dedicated planning sessions |
| Same topic appearing in nextSteps across 3+ sessions | Unresolved planning item |
Frequency threshold: A topic becomes a "loop" when it appears in 3+ sessions without a resolution artifact (committed code, published output, completed task).
Category C: Failure & Recovery Patterns
Mistakes or system failures that repeat:
| Signal pattern | What it indicates |
|---|---|
| "I thought we solved/fixed this" | Regression |
| "this keeps happening", "same issue", "again" | Recurring failure |
| "crashed", "doesn't work", "never responds" | Tool/system failure |
| "wrong browser", "wrong account" | Environment setup error |
| Context continuation messages | Context overflow (session was too long) |
Track regression vs. new failure — regressions (things that were fixed but broke again) are higher priority than new failures.
Category D: Decision Narratives
Key decisions and rationale that keep being re-explained:
| Signal pattern | What it indicates |
|---|---|
| "we chose X because", "the reason is" | Decision rationale being restated |
| "pricing", "strategy", "experiment" | Strategic decision under discussion |
| "API", "integration", "platform" | Technical decision being revisited |
| Same decision topic in 3+ sessions | Decision not yet landed |
Category E: Knowledge Re-establishment
Context that has to be rebuilt each session:
| Signal pattern | What it indicates |
|---|---|
| "what's our status", "where are we" | State unknown at session start |
| "where is the file", "which config" | File location unknown |
| "how does X work", "remind me" | System knowledge lost |
| Context continuation summaries | Full context rebuild |
Count continuation messages — each "This session is being continued from a previous conversation that ran out of context" represents a context rebuild event.
Category F: Emotional & Momentum Patterns
Tone shifts that recur:
| Signal pattern | What it indicates |
|---|---|
| "looks great", "perfect", "nice" | Positive momentum |
| "frustrating", "annoying", "why does" | Frustration trigger |
| "let's just", "forget it", "move on" | Giving up on current approach |
| Session ending with task completion confirmation | Productive session |
| Session ending with "what's next?" | Momentum tapering |
Phase 4: Compile Report
Write the report to a research/studies/ directory (create if needed) in the project workspace as {YYYY-MM-DD}_narrative-analysis.md. If no research/studies/ directory exists, write to the project root.
Include these sections:
Section 1: Session Inventory
The table from Phase 1, plus summary stats (total sessions, cost, hours, date range).
Section 2: Top 10 Recurring Narratives
Ranked by frequency (number of unique sessions where the pattern appears):
- Pattern name — short descriptive label
- Category — A through F
- Session count — how many unique sessions exhibit this pattern
- Representative quotes — 1-2 short verbatim excerpts from user messages, each tagged with a provenance pointer
<cliSessionId>/<lineIndex>(see Evidence Discipline) - Recommendation — one of:
- "CLAUDE.md candidate" — encode as a permanent rule
- "Skill candidate" — encode as a procedural skill or slash command
- "Decision needed" — requires a one-time decision to stop the loop
- "Structural" — caused by platform limitations, can only be mitigated
- "Acceptable" — natural pattern, no action needed
Section 3: CLAUDE.md Candidates
Specific rules extracted from Category A, formatted as ready-to-paste CLAUDE.md entries. Each should include:
- The rule text
- Why it matters (what goes wrong without it)
- How many sessions it appeared in
Section 4: Skill Candidates
Patterns that are too procedural for CLAUDE.md and should be skills instead. For each:
- What the skill would do
- Which existing skill it could extend (if any)
- Why a CLAUDE.md rule is insufficient
Section 5: Unresolved Loops
From Category B, decisions or plans that keep cycling. For each:
- The topic
- How many sessions it's appeared in
- What would resolve it (a decision, an experiment, acceptance)
Section 6: Raw Pattern Log
Every pattern identified with:
- Pattern name
- Category
- Session count
- Key signal phrases
Evidence Discipline — Provenance, Privacy & Dedup
This skill lifts verbatim transcript excerpts into durable artifacts — the
report under research/studies/ and the findings ledger — that often live in a
committed (sometimes deployed) repo. The discipline below adapts story-miner's
mining mechanics to this prompt-only skill; where it diverges from story-miner
(which does the work in a preprocessor), that is called out. It applies whenever a
quote or finding leaves the raw transcript (Phases 3-4).
1. Provenance-grounded quoting. Tag every surfaced quote with a pointer to its
source line so the quote is checkable: <cliSessionId>/<lineIndex> — cliSessionId
because that is what names the transcript file (<cliSessionId>.jsonl; for a CLI
session the session id IS the file name), and <lineIndex> the 0-based line number
in that JSONL. Capture the line index while parsing in Phase 2.1 — you are
already iterating the lines. story-miner additionally suffixes #<contentHash16>
(the first 16 hex of a SHA-256 over the first ~400 chars of that line's extracted (redacted, truncated) text, computed by
its preprocessor); replicate that suffix only if you compute the hash
programmatically, otherwise the <cliSessionId>/<lineIndex> pair is the floor. The
pointer turns the Anti-Pattern Checklist's "actual user messages, not paraphrases"
from an aspiration into something verifiable. Caveat: Phase 2 joins/strips blocks
and truncates to ~1500 chars, so a quote is verbatim against the extracted text
of that line, not necessarily a byte-substring of the raw line. Record the pointer
next to the quote in both the report and the ledger; a quote you cannot point to
does not go in the report.
2. Redact before surfacing. story-miner gates every output through a
deterministic secret/PII scanner; replicate the posture, not its exact regexes.
Before writing ANY verbatim excerpt, strip at least: provider tokens/keys (sk-…,
ghp_…, github_pat_…, glpat-…, AKIA…, AIza…, xox[baprs]-…), JWTs, PEM
private-key blocks, Authorization:/Cookie: headers, DB connection strings, and
long hex/base64 runs; and neutralize home-directory paths (C:\Users\<name>\…,
/home/<name>/…, /Users/<name>/…) so a username never leaks. Redaction is
best-effort — a floor, not a guarantee.
3. Scan the output before finalizing. After drafting the report + ledger, scan
the written files for the patterns above (a Grep pass suffices). On any hit,
redact and re-scan until clean. Never finalize an unscanned report — this is the
prompt-only analogue of story-miner's gated --scan-dir step (which exits non-zero
until clean).
4. Never quote model-internal or system text. Surface quotes only from
user/assistant text blocks — the qualifier is on the block, not the line
(one user line can carry hundreds of tool_result blocks). From story-miner:
never quote thinking/reasoning content, and cross-check the guard — a quote's
provenance must resolve to a text block, not a thinking block. Reinforcing this
skill's own Phase 2.3 stripping: never quote <system-reminder>,
<scheduled-task>, <ide_selection>, <file_contents>, or tool output either.
5. Deterministic dedup before counting. A pattern's session count is
load-bearing — it drives ranking and the 2+/3+ thresholds — so don't let one
friction, surfaced under two labels, count twice. Before counting, merge
near-identical findings deterministically: extract each finding's rare key-terms
(file paths, function names, error-class names, minus a common-word stoplist) and
treat two findings as the same pattern when they share >= 3 rare terms
(story-miner's default minRareTermOverlap; drop to 2 for short, term-sparse
findings). This complements the LLM thematic clustering in Phase 3 with a
deterministic merge.
Scaling Notes
Large Session Counts (100+ sessions)
Transcripts can be large. Process in batches if context limits are hit:
- Extract and save condensed data to a temporary
transcript-extracts.jsonfile first - Then analyze the condensed data for patterns
- User messages are the highest-signal content — prioritize those over assistant messages for pattern detection
Incremental Analysis
If a previous narrative analysis report exists in the project, read it first and focus on sessions that postdate it. The new report should note which sessions are new since the last analysis and highlight any patterns that have changed (new, resolved, or intensified).
Intermediate Data Files
The analysis pipeline may produce intermediate files for inspection:
| File | Purpose | Cleanup? |
|---|---|---|
data/session-inventory.json | All matching sessions with metadata and paths | Delete after report or keep for incremental runs |
data/transcript-extracts.json | Condensed conversation text from all sessions | Delete after report — can be large |
data/user-messages.json | User messages only (highest signal) | Delete after report |
Ask the user if they want these cleaned up after the report is generated.
Findings Ledger — Tracking State Across Runs
The core mechanism for avoiding repeated work is the findings ledger: a JSON file that persists in the project and tracks each finding's lifecycle across analysis runs.
Ledger Location
.claude/transcript-analysis/findings-ledger.json
This lives in the project's .claude/ directory (not the user's ~/.claude/) because findings are project-specific. The .claude/ directory is the standard project-level config location for Claude Code.
Ledger Schema
{
"version": 1,
"project": "MyProject",
"runs": [
{
"date": "2026-03-17",
"sessions_analyzed": 211,
"session_date_range": ["2026-02-11", "2026-03-17"],
"report_path": "research/studies/2026-03-17_narrative-analysis.md"
}
],
"findings": [
{
"id": "A_windows_file_path",
"category": "A",
"title": "Windows host path for file uploads",
"status": "actioned",
"first_seen": "2026-03-17",
"last_seen": "2026-03-17",
"session_count": 3,
"action_taken": "Added rule to CLAUDE.md; propagated to related skills",
"action_date": "2026-03-18",
"notes": "Recurrence should drop to zero — monitor in next run",
"quotes": [
{"ref": "<cliSessionId>/<lineIndex>", "text": "Make sure you use the local windows file path, not your VM file path"}
]
}
],
"last_session_date": "2026-03-17T09:42:00Z"
}
Finding Statuses
| Status | Meaning | Next run behavior |
|---|---|---|
new | Just discovered this run | Present in report as new finding |
acknowledged | User has seen it but hasn't acted yet | Present as "still open" with session count delta |
actioned | User encoded it in CLAUDE.md, a skill, or made a decision | Check if pattern still recurs in new sessions. If yes → persistent. If no → resolved |
resolved | Was actioned AND no longer appears in new sessions | Skip entirely — only mention in summary stats |
persistent | Was actioned but pattern still recurs in new sessions | Flag prominently — the fix didn't work |
accepted | User decided this is fine and doesn't want to see it again | Skip entirely |
deferred | User wants to revisit later | Present only in summary, not in main findings |
Phase 0: Load Ledger (NEW — runs before Phase 1)
Before discovering sessions, check for an existing ledger:
import os, json
ledger_path = os.path.join('.claude', 'transcript-analysis', 'findings-ledger.json')
if os.path.exists(ledger_path):
with open(ledger_path) as f:
ledger = json.load(f)
last_run_date = ledger['runs'][-1]['date'] if ledger['runs'] else None
last_session_date = ledger.get('last_session_date')
known_findings = {f['id']: f for f in ledger['findings']}
print(f"Previous run: {last_run_date}, {len(known_findings)} known findings")
else:
ledger = {"version": 1, "project": os.path.basename(os.getcwd()), "runs": [], "findings": [], "last_session_date": None}
last_run_date = None
last_session_date = None
known_findings = {}
If a ledger exists with last_session_date:
- In Phase 1, still discover ALL sessions (for accurate counts), but mark which are "new since last run"
- In Phase 3, analyze only new sessions for pattern detection, then merge with existing findings
- In Phase 4, generate a differential report (see below)
Phase 3 Changes: Incremental Pattern Extraction
When a ledger exists, pattern extraction works differently:
- Run pattern detection on ALL sessions (not just new ones) to get updated session counts
- For each detected pattern, check the ledger:
- If
idmatches a known finding → updatelast_seenandsession_count - If the known finding is
actionedand pattern still appears in sessions afteraction_date→ set status topersistent - If the known finding is
actionedand pattern does NOT appear in sessions afteraction_date→ set status toresolved - If no match → add as a new finding with status
new
- If
- For each ledger finding NOT detected this run:
- If status was
neworacknowledged→ it may have been naturally resolved; set status toresolvedwith a note - If status was
actioned→ set status toresolved(the fix worked) - Leave
acceptedanddeferredas-is
- If status was
Phase 4 Changes: Differential Report
When generating the report with an existing ledger, the report format changes:
# Transcript Analysis — {date} (Incremental)
**Previous run:** {last_run_date} | **New sessions since:** {new_session_count}
**Total:** {total_sessions} sessions ({total_cost}) | **Known findings:** {known_count}
## What Changed Since Last Run
### New Findings ({count})
{findings with status "new" — full detail as before}
### Persistent Findings ({count}) — Action Taken But Pattern Continues
{findings with status "persistent" — these need attention, the fix didn't work}
### Still Open ({count})
{findings with status "acknowledged" — show session count delta}
### Resolved ({count})
{one-line summary of each resolved finding — just the title and what fixed it}
### Deferred ({count})
{one-line summary of deferred findings}
## Updated CLAUDE.md Candidates
{only NEW candidates not already in the ledger}
## Full Pattern Log
{complete pattern table as before, but with status column from ledger}
Phase 5: Update Ledger (NEW)
After generating the report, update the ledger:
# Add this run to the runs array
ledger['runs'].append({
'date': today,
'sessions_analyzed': total_sessions,
'session_date_range': [earliest_date, latest_date],
'report_path': report_path
})
ledger['last_session_date'] = latest_session_timestamp
# Write updated ledger
os.makedirs(os.path.dirname(ledger_path), exist_ok=True)
with open(ledger_path, 'w') as f:
json.dump(ledger, f, indent=2)
User Triage Workflow
After each run, present the user with new and persistent findings for triage:
New findings to triage:
1. [A] Input validation rule (3 sessions) → action / acknowledge / accept / defer
2. [C] QA skill timeout on large packs (2 sessions) → action / acknowledge / accept / defer
Persistent findings (action didn't resolve):
3. [A] Hero image cropping — actioned 2026-03-18, still appears in 2 new sessions
→ re-investigate / accept / defer
The user's triage choices update the ledger immediately. This is the mechanism that prevents the same findings from being presented as "new" on every run.
Seeding the Ledger from an Existing Report
If there's already a narrative analysis report but no ledger (as is sometimes the case), Phase 0 should detect this:
- Look for
research/studies/*_narrative-analysis.mdfiles - If found but no ledger exists, offer to seed the ledger from the report
- Parse the report's pattern log (Section 6) to extract finding IDs, categories, session counts, and quotes
- Create ledger entries with status
acknowledged(since the user has seen them but hasn't triaged) - Set
last_session_datefrom the report's date range - Present the seeded findings for triage before proceeding with new analysis
This bootstrapping step only happens once — after that, the ledger is authoritative.
Output Contract
After running this skill, the following artifacts exist:
.claude/transcript-analysis/findings-ledger.json— persistent finding state (the primary artifact)research/studies/{date}_narrative-analysis.md— human-readable report for this run
The ledger is the source of truth. The report is a snapshot view derived from it.
What This Skill Does NOT Do
- No transcript summarization — this finds patterns ACROSS sessions, not summaries OF sessions
- No code analysis — this analyzes conversation dynamics, not codebase changes
- No prescriptive refactoring — it identifies what repeats, not how to fix it (though it recommends CLAUDE.md vs skill vs decision)
- No real-time monitoring — this is a batch retrospective, not a live session watcher
Anti-Pattern Checklist
Before finalizing the report, verify:
- Patterns are cross-session (appear in 2+ sessions), not one-off observations
- Representative quotes are actual user messages, not paraphrases
- Session counts reflect unique sessions, not total message occurrences
- CLAUDE.md candidates are rules the user stated, not inferences about what they might want
- Unresolved loops are genuinely unresolved (check for resolution artifacts in later sessions)
- The report distinguishes between "user keeps saying this" (Category A) and "this keeps failing" (Category C)
- Every surfaced quote has a provenance pointer (
<cliSessionId>/<lineIndex>) that resolves to a verbatimuser/assistanttext block — never thinking, system, or tool content - The report and ledger were redacted and scanned for secrets/PII and home-directory paths before finalizing
- Near-identical findings were deduped by shared rare terms (>= 3) before counting, so no single friction is double-counted across labels
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.