
Mining Session Skills
- 149 installs
- 130 repo stars
- Updated June 19, 2026
- sugarforever/01coder-agent-skills
Helps with ai & agent building tasks during AI-assisted development.
About
mining-session-skills is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- mining-session-skills
- AI & Agent Building
- AI-coding skill
Mining Session Skills by the numbers
- 149 all-time installs (skills.sh)
- +16 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #3,352 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/sugarforever/01coder-agent-skills --skill mining-session-skillsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 149 |
|---|---|
| repo stars | ★ 130 |
| Last updated | June 19, 2026 |
| Repository | sugarforever/01coder-agent-skills ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Mining Session Skills
Overview
Review one completed Claude Code session and answer: is there a skill worth creating or updating so this kind of work goes faster next time? A clean "nothing worth making here" is a valid result.
This skill is the judgment layer on top of claude-session-manager (the export/normalization layer). It reads exported markdown, not raw JSONL.
Preconditions
1. Inventory = skills loaded in THIS session. Create-vs-update-vs-reuse is decided against the skills already advertised/loaded in the running session. State this limit in the report ("comparison limited to skills loaded this session"). Run this skill where the relevant skills are loaded. 2. Mining operates on exported markdown (default ~/.claude/session-markdown), produced by claude-session-manager. If the target session is not exported yet, export it first (step 1.5).
Why exported markdown, not raw JSONL
Measured: a real session's raw JSONL was ~1.5M tokens (exceeds the context window); the exported compact body was ~91k tokens (17× smaller) with tool payloads deferred to a sidecar. Raw grep '"type":"user"' over JSONL is a trap (tool results are role:user). Always read/mine the exported markdown. Raw-JSONL byte grep is acceptable ONLY as a location prefilter (step 1).
Pipeline
Copy this checklist and track progress:
- [ ] 1. Locate the session (keyword search; confirm with user)
- [ ] 1.5 Export it if not already exported
- [ ] 2. Read the compact transcript (pull sidecar only as needed)
- [ ] 2.5 Segment into topic arcs
- [ ] 3. Mine friction signals per arc
- [ ] 4. Apply the worth-it gate
- [ ] 5. Decide create / update / reuse
- [ ] 6. Present the proposal
- [ ] 7. On approval, interview + draft1. Locate
Search by the user's description. Prefilter optionally with a raw-JSONL byte grep across ~/.claude/projects (finds which file mentions a keyword without parsing), and/or grep the exported corpus under ~/.claude/session-markdown. Skip <local-command-caveat> / <command-*> wrapper noise — the first-prompt excerpt is often a wrapper, not the real ask. Present a ranked shortlist and let the user confirm.
1.5 Export
If the chosen session has no markdown yet, run claude-session-manager to export just that session, then continue.
2. Read
Read the session .md. Pull tool-details/<id>.tools.md ONLY for the specific <tool_call_NNNNNN> refs that matter. Use scripts/extract_session_signals.py <session>.md to get a clean JSON list of human prompts (with event index, line, timestamp, arc-break hints, and the prompt text) — it encodes the input-robustness rules below.
Input-robustness rules:
- The real exported header format is
### N. user - <ISO>/### N. assistant - <ISO>(not### MM-DD HH:MM:SS User:). - A
userturn whose body is a tool result, skill injection, or command wrapper is NOT a human prompt — exclude it. - Ignore thinking-signature blobs and empty attachment events.
2.5 Segment
Sessions can be multi-day, multi-task kitchen sinks. Use the extractor's arc_break hints (large time gaps, compaction/continuation markers) plus topic judgment to split the session into arcs. Mine each arc independently. Do NOT assume one task per session.
3. Mine
Per arc, extract friction signals. See references/friction-signals.md for the taxonomy and how to cite evidence.
4. Gate
Apply the worth-it filter to every candidate. See references/worth-it-gate.md. If nothing passes, report the clean negative and stop.
5. Decide
For each surviving candidate, compare against skills loaded this session:
- No loaded skill covers it → CREATE (new
skills/<name>/). - Loaded and editable (in this repo's
skills/) → UPDATE that SKILL.md. - Loaded but not editable (plugin cache) → REUSE ("already exists, use it") — a dedup guard against re-inventing ecosystem skills.
6. Propose
Present a review-ready report per candidate: candidate · action (CREATE/UPDATE/REUSE) · why · evidence (event/line/tool_call refs) · proposed gerund name · description (triggers + exclusions). List gate-rejected items briefly. Wait for approval before any file change.
7. Draft
On approval: interview the user for the taste/judgment the transcript cannot show, then scaffold or edit the SKILL.md following references/drafting-quality-bars.md. For a new skill, run scripts/sync-marketplace-skills.sh and bump the version in .claude-plugin/marketplace.json (per the repo CLAUDE.md).
Notes
- Treat transcript data as private (prompts, file contents, secrets). Do not modify original
.jsonlfiles. - The value of this skill is the mining methodology, not the SKILL.md format — Claude knows the format natively.
Drafting quality bars (step 7)
Apply when scaffolding a new SKILL.md or editing an existing one. These are the bars reputable authors (Anthropic docs, Jesse Vincent, Simon Willison) converge on.
Frontmatter
name: gerund form preferred (translating-posts-to-blogs), lowercase + hyphens only, no reserved words (anthropic,claude), ≤ 64 chars.description: third person; state what it does AND when to use it AND exclusions ("Not for X — use Y"). The exclusion line is the single most valuable defense against mis-triggering. ≤ 1024 chars.
Body
- Concise — assume Claude is already smart. Only capture what it would not know: conventions, non-obvious procedures, edge cases, project-specific rules. Cut any sentence that explains a concept a capable reader already knows.
- Body < 500 lines. Split overflow into
references/*.md, linked one level deep from SKILL.md (no nested reference chains). - Match degrees of freedom to task fragility: high-freedom prose for judgment tasks; exact, low-freedom scripts/commands for fragile sequences.
- No all-caps imperatives (
MUST/NEVER) without a reason — they cause over-application. - No happy-path-only docs — include known failure modes.
- No time-sensitive phrasing — use an "old patterns" section for deprecated info.
- Chinese content follows the repo's
personal-chinese-writing-styleskill.
Interview before drafting
The transcript shows mechanics, not the why. Before writing, ask the user for the taste/judgment/rationale the session cannot reveal. Capture that — it is the actual value.
Repo integration (for CREATE)
- New skill dir under
skills/<name>/. - Run
scripts/sync-marketplace-skills.shto register it inmarketplace.json(never hand-editskills[]). - Bump the
versionfield in.claude-plugin/marketplace.json.
Friction signals (step 3)
Read the mined arc and look for these signals. Each is a clue that reusable knowledge changed hands. Always capture the evidence reference (event index / line from extract_session_signals.py, or a <tool_call_NNNNNN> ref) so the proposal is auditable.
Signal taxonomy
1. User corrections / redirections — "no, do X instead", "主语有冲突", "that's not what I meant". The strongest signal: the model did the obvious thing and the user had to steer. Capture what the model assumed vs. what the user wanted. 2. Repeated manual tool sequences — the same ordered set of commands run several times (e.g. fetch → translate → cite → publish). Recurrence = automatable workflow. 3. Dead-ends & backtracking — the model tried an approach, abandoned it, tried another. The successful path is worth encoding; the dead-ends are worth warning against. 4. Domain knowledge the user supplied — conventions, gotchas, project rules the model could not have known ("always quote the original at the top", "check the reply thread for corrections"). This is the highest-value skill content. 5. Recurring asks — the user typed essentially the same prompt more than once across the arc (or you know from context they do it often). Per Simon Willison: repeated prompts → make a skill.
How to record evidence
For each candidate, list 2–4 concrete references: event 6, event 7, or <tool_call_000012> from the sidecar. The proposal must let the user verify the claim without re-reading the whole session. Pull the sidecar (tool-details/<id>.tools.md) only for the specific refs that matter.
The worth-it gate (step 4)
A candidate passes ONLY if it would genuinely make future work faster or better. Apply this checklist to every candidate. If none pass, report a clean negative — that is a valid, valuable result.
The gate (Jesse Vincent's test)
Keep a candidate only if at least one is true:
- [ ] Non-obvious process — the model would not do this correctly by default; it needs the steps spelled out.
- [ ] Human taste / judgment — there is a quality bar, voice, or editorial call that is not derivable from the task alone.
- [ ] Divergent-from-standard — the user does it differently from the common/default way, and that difference matters.
Reject if the honest answer is "Claude already does this well in one shot." Mechanical competence the model already has is worth zero as a skill.
Worked examples (from the verysmallwoods tweet→blog drill)
- PASS — "check the reply thread under the source tweet for factual corrections and surface them at the top." Non-obvious editorial process; the model would not do it unprompted.
- PASS — "when translating a first-person company blog, the author's 'we' conflicts with the translator's framing; adjust the voice." Taste/judgment.
- REJECT — "run
git commitandgit push." The model already does this; no skill needed. - REJECT (as a new skill) — "publish to substack/zsxq/x." Loaded skills already cover it → REUSE/UPDATE, not create.
After the gate
For each surviving candidate, go to the create/update/reuse decision (SKILL.md step 5). Briefly note rejected candidates in the proposal so the negative is auditable.
#!/usr/bin/env python3
"""Extract clean human prompts + arc-boundary hints from an exported Claude session markdown.
Encodes the input-robustness rules from the mining-session-skills spec:
- tolerate the real exported header format `### N. <type> - <ISO>`
- distinguish human prompts from tool results / skill injections / command wrappers
- flag likely topic-arc boundaries (large time gaps, compaction/continuation markers)
Usage:
python3 extract_session_signals.py <exported-session>.md
Outputs JSON to stdout: {session_file, human_prompt_count, prompts: [...]}.
Each prompt: {event_index, line, timestamp, arc_break, arc_break_reason, text}.
"""
import datetime
import json
import re
import sys
HEADER = re.compile(r'^### (\d+)\. ([a-z0-9-]+)(?: - (.+))?\s*$')
ARC_GAP_SECONDS = 2 * 60 * 60 # >2h between human prompts hints a new topic arc
# Body prefixes that mark a `user` turn as NON-human (tool plumbing / skill injection)
NONHUMAN_PREFIXES = (
'- Tool result',
'- Tool error',
'[{',
'{ "',
'{"',
'Base directory for this skill',
)
# Substrings that mark a turn as a command/local wrapper, not a human prompt
WRAPPER_SUBSTR = (
'<local-command-caveat',
'<command-message',
'<command-name',
'<local-command-stdout',
)
# Markers that hint a conversation boundary (compaction / continuation)
ARC_MARKERS = (
'continued from a previous conversation',
'ran out of context',
'Compacted',
)
def parse_ts(s):
if not s:
return None
try:
return datetime.datetime.fromisoformat(s.replace('Z', '+00:00'))
except ValueError:
return None
def is_human(kind, body_text):
if kind != 'user':
return False
t = body_text.strip()
# discard sub-4-char ACK turns ("ok", "y", "好的")
if len(t) <= 3:
return False
if any(t.startswith(p) for p in NONHUMAN_PREFIXES):
return False
if any(w in t for w in WRAPPER_SUBSTR):
return False
return True
def parse_turns(lines):
"""Yield ((event_index, kind, ts_str), start_line, body_lines)."""
cur = None
start = 0
buf = []
for i, ln in enumerate(lines, 1):
m = HEADER.match(ln)
if m:
if cur:
yield cur, start, buf
cur = (int(m.group(1)), m.group(2), m.group(3))
start = i
buf = []
elif cur:
buf.append(ln)
if cur:
yield cur, start, buf
def extract(path):
with open(path, encoding='utf-8') as fh:
lines = fh.read().splitlines()
prompts = []
prev_ts = None
for (idx, kind, ts_s), start, buf in parse_turns(lines):
body = '\n'.join(buf).strip()
if not is_human(kind, body):
continue
ts = parse_ts(ts_s)
reasons = []
if any(mk in body for mk in ARC_MARKERS):
reasons.append('compaction/continuation marker')
if ts and prev_ts and (ts - prev_ts).total_seconds() > ARC_GAP_SECONDS:
reasons.append(f'>{ARC_GAP_SECONDS // 3600}h gap from previous prompt')
prompts.append({
'event_index': idx,
'line': start,
'timestamp': ts_s,
'arc_break': bool(reasons),
'arc_break_reason': '; '.join(reasons),
'text': body,
})
if ts:
prev_ts = ts
return {'session_file': path, 'human_prompt_count': len(prompts), 'prompts': prompts}
def main(argv):
if len(argv) != 2:
print('usage: extract_session_signals.py <exported-session>.md', file=sys.stderr)
return 2
json.dump(extract(argv[1]), sys.stdout, ensure_ascii=False, indent=2)
print()
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv))
#!/usr/bin/env python3
"""Dependency-free assert test for extract_session_signals.py.
Run: python3 test_extract_session_signals.py
Exits 0 on success, non-zero (AssertionError traceback) on failure.
"""
import json
import os
import subprocess
import sys
import tempfile
FIXTURE = '''# Claude Session test
## Timeline
### 1. permission-mode
### 5. user - 2026-04-27T15:04:41.796Z
把 tweet 翻译成博客,开头引用原文
### 6. assistant - 2026-04-27T15:04:48.802Z
好的
### 7. user - 2026-04-27T15:05:00.000Z
- Tool result (`toolu_x`): some output
### 9. user - 2026-04-27T15:05:10.000Z
<local-command-caveat>Caveat...</local-command-caveat>
### 11. user - 2026-04-27T15:05:20.000Z
Base directory for this skill: /x
### 20. user - 2026-04-27T18:30:00.000Z
This session is being continued from a previous conversation that ran out of context.
'''
def run(md_path):
here = os.path.dirname(os.path.abspath(__file__))
script = os.path.join(here, 'extract_session_signals.py')
out = subprocess.check_output([sys.executable, script, md_path])
return json.loads(out)
def main():
with tempfile.NamedTemporaryFile('w', suffix='.md', delete=False, encoding='utf-8') as f:
f.write(FIXTURE)
path = f.name
try:
data = run(path)
finally:
os.unlink(path)
ps = data['prompts']
got = [p['text'][:20] for p in ps]
assert data['human_prompt_count'] == 2, f"expected 2 human prompts, got {data['human_prompt_count']}: {got}"
# event 5 = a real human prompt, no arc break
assert ps[0]['event_index'] == 5, ps[0]
assert ps[0]['text'].startswith('把 tweet'), ps[0]
assert ps[0]['arc_break'] is False, ps[0]
# events 7 (tool result), 9 (caveat wrapper), 11 (skill injection) excluded; assistant 6 excluded
# event 20 = continuation summary: kept but flagged as an arc boundary (marker + >2h gap)
assert ps[1]['event_index'] == 20, ps[1]
assert ps[1]['arc_break'] is True, ps[1]
assert 'gap' in ps[1]['arc_break_reason'], ps[1]
assert 'marker' in ps[1]['arc_break_reason'] or 'continuation' in ps[1]['arc_break_reason'], ps[1]
print('OK: all assertions passed')
if __name__ == '__main__':
main()