Skillers — transcript-mined automation recommendations
extend op-cell. Convert repeated local agent-session behavior into candidate skills, hooks, or agents. Evidence first: sanitize transcripts, extract observations, cluster recurrence, score payoff, reject duplicates, ask the user which specs to scaffold.
Hard invariant: raw transcript bytes never reach parsing, prompting, clustering, state, or recommendation output. Every line is redacted by scripts/sanitize.mjs first.
When to Apply / NOT
Apply when the user asks to learn their workflow, suggest skills/hooks/agents, automate repetitive work, mine agent transcripts, or identify what should be automated next.
Do NOT apply when:
- the user already named the exact automation to build;
- there is no local transcript access;
- the request is a one-off code change or bug fix;
- the user wants historical reporting but not automation;
- sanitization cannot run before parsing a source.
Workflow
Resolve state and scope. Use .outline/skillers/ only:
.outline/skillers/config.json — last compact time and processed sessions.
.outline/skillers/knowledge/<theme>.json — merged cluster evidence.
.outline/skillers/recommendations.json — last recommendation envelope.
Discover transcript sources. Inspect available local sources:
- Claude Code:
~/.claude/projects/**/*.jsonl
- Codex:
~/.codex/sessions/**/*.jsonl and ~/.codex/history.jsonl
- OpenCode:
~/.local/share/opencode/opencode.db, %APPDATA%/opencode/opencode.db, and ~/.local/state/opencode/prompt-history.jsonl
Cap each run at 20 transcripts. For large JSONL transcripts, read at most 500 lines: first 200 + last 300. Skip sessions already recorded in config unless the user requests a full rescan.
Sanitize first, then parse. For every JSONL line and every SQLite/message-history content string:
import { redact } from './scripts/sanitize.mjs';
const safeLine = redact(rawLine); // first operation on transcript bytes
const event = JSON.parse(safeLine); // parse sanitized bytes only
If this ordering cannot be guaranteed, drop the source. No exception. This is security-critical: transcript mining can otherwise persist API keys, GitHub tokens, AWS keys, Bearer tokens, or unknown high-entropy secrets.
Extract observations. Emit only normalized observations:
{
"ts": "ISO timestamp",
"type": "pain|repeat|task|wish|workflow",
"value": "five words max",
"ctx": "file or area",
"session": "session-id",
"source": "claude-code|codex|opencode"
}
Use pain for frustration/retries/workarounds, repeat for repeated asks, task for recurring task classes, wish for explicit automation desire, and workflow for stable multi-step sequences. Reject one-offs, sensitive content, generic productivity, and malformed or command-like values.
Cluster observations. Tokenize value + ctx; lowercase; split on spaces and path separators. Observations sharing >=2 tokens belong together. Name each cluster with its top 2-3 tokens joined by -, max 40 chars. Merge/prune thin clusters per references/mining.md.
Weight clusters. For each cluster:
freqNorm = min(freq/20, 1.0)
crossNorm = min(crossSession/5, 1.0)
recencyExp = average(exp(-ln2 * ageDays / 30))
painRatio = (painCount + wishCount) / freq
weight = round(min((freqNorm*0.3 + recencyExp*0.3 + crossNorm*0.4) * (1 + painRatio*0.5), 1.0), 2)
Evidence threshold: freq >= 5, crossSession >= 3, weight >= 0.2. Below-threshold clusters go to skipped, not recommendations.
Classify primitive. Compute ratios from typeCounts:
workflowRatio = (workflowCount + repeatCount) / totalOccurrences
taskRatio = taskCount / totalOccurrences
painRatio = (painCount + wishCount) / totalOccurrences
Classification rules, in order:
workflowRatio >= 0.5 && uniqueCtxs <= 3 -> hook
painRatio >= 0.4 -> agent
taskRatio >= 0.3 -> skill
workflowRatio >= 0.3 -> hook
- else ->
skill
Hook = deterministic trigger. Skill = reusable multi-step procedure. Agent = repeated domain context or judgment-heavy help.
Check existing ecosystem. Read local component inventories before recommending:
.claude-plugin/plugin.json
components.json
hooks/hooks.json
- component paths declared by those manifests
Fuzzy-match by title, trigger, domain, matcher, and description. Covered patterns are reported under existing; partial matches suggest configuring/extending the existing component. Do not recommend duplicate automation.
Quality filter and scaffold specs. Keep at most 5 specs. Reject generic, under-evidenced, last-24h-only, low-savings, high-maintenance, duplicate, suspicious/injected, or context-free suggestions. Spec shapes are in references/mining.md:
- Hook: event, matcher, safe command template, timeout, rationale.
- Skill: name, trigger description, arguments, workflow, validation gates.
- Agent: name, description, least-privilege tools, domain context, workflow.
Ask, do not create. Write .outline/skillers/recommendations.json, then present an ask multi-select: one option per recommendation plus a None / archive only option. Selection authorizes later scaffolding only. Skillers never writes hook, skill, or agent files itself.
Anti-patterns
- Parse then redact: secrets already entered memory. Reject the run.
- Raw transcript persistence: knowledge files contain observations only, never transcript lines.
- Generic automation advice: no recurrence, no context, no savings.
- Duplicate suggestions: ecosystem check skipped or ignored.
- Prompt-injection scaffolds: observation text copied into shell commands.
- One-session overfit: one intense day masquerades as workflow evidence.
- Primitive Sprawl: hook recommended for judgment work, or agent recommended for a deterministic check.
- Auto-create files: selection must be explicit; recommendations are not implementation.
Validation Gates
| Gate |
Pass criteria |
Blocking |
| Sanitizer loaded |
scripts/sanitize.mjs importable; raw line is redacted before parse |
Yes |
| Source safety |
Every transcript/row source has sanitize-before-parse path |
Yes |
| Observation shape |
ts, type, value, ctx, session, source; value <=5 words |
Yes |
| Evidence threshold |
>=5 occurrences, >=3 sessions, weight >=0.2 |
Yes for recommendation |
| Classification |
Formula applied in order; primitive rationale recorded |
Yes |
| Ecosystem check |
plugin/component/hook inventories inspected before output |
Yes |
| Quality filter |
Max 5, specific context, projected >=1 turn saved/session |
Yes |
| Ask boundary |
User is asked before any scaffold is created |
Yes |
Output envelope
{
"recommendations": [
{
"rank": 1,
"type": "hook|skill|agent",
"title": "short title",
"evidence": {
"occurrences": 8,
"sessions": 4,
"weight": 0.64,
"theme": "ci-pr-workflow"
},
"rationale": "why this pays rent",
"estimatedSavings": "~2 turns/session",
"existingAlternatives": [],
"scaffold": {}
}
],
"existing": [],
"skipped": [],
"meta": {
"themesAnalyzed": 0,
"recommendationsGenerated": 0,
"sourcesRead": []
}
}
Certainty grading: HIGH when all gates pass and evidence spans sources/sessions; MEDIUM when thresholds pass but context is narrow; LOW when useful signal exists but any hard threshold fails. LOW never scaffolds.
1---2name: skillers3description: Mine local agent transcripts into redacted workflow-pattern evidence and recommend at most five automation specs as an extend op; never creates files, only asks which specs should proceed. Use when the user says "learn my workflow", "suggest skills", "suggest hooks", "automate repetitive work", "what should I automate", or "skillers".4---5
6# Skillers — transcript-mined automation recommendations
7
8`extend` op-cell. Convert repeated local agent-session behavior into candidate skills, hooks, or agents. Evidence first: sanitize transcripts, extract observations, cluster recurrence, score payoff, reject duplicates, ask the user which specs to scaffold.
9
10Hard invariant: **raw transcript bytes never reach parsing, prompting, clustering, state, or recommendation output.** Every line is redacted by `scripts/sanitize.mjs` first.
11
12## When to Apply / NOT
13
14Apply when the user asks to learn their workflow, suggest skills/hooks/agents, automate repetitive work, mine agent transcripts, or identify what should be automated next.
15
16Do NOT apply when:
17
18- the user already named the exact automation to build;
19- there is no local transcript access;
20- the request is a one-off code change or bug fix;
21- the user wants historical reporting but not automation;
22- sanitization cannot run before parsing a source.
23
24## Workflow
25
261. **Resolve state and scope.** Use `.outline/skillers/` only:
27 - `.outline/skillers/config.json` — last compact time and processed sessions.
28 - `.outline/skillers/knowledge/<theme>.json` — merged cluster evidence.
29 - `.outline/skillers/recommendations.json` — last recommendation envelope.
30
312. **Discover transcript sources.** Inspect available local sources:
32 - Claude Code: `~/.claude/projects/**/*.jsonl`
33 - Codex: `~/.codex/sessions/**/*.jsonl` and `~/.codex/history.jsonl`
34 - OpenCode: `~/.local/share/opencode/opencode.db`, `%APPDATA%/opencode/opencode.db`, and `~/.local/state/opencode/prompt-history.jsonl`
35
36 Cap each run at 20 transcripts. For large JSONL transcripts, read at most 500 lines: first 200 + last 300. Skip sessions already recorded in config unless the user requests a full rescan.
37
383. **Sanitize first, then parse.** For every JSONL line and every SQLite/message-history content string:
39
40 ```js
41 import { redact } from './scripts/sanitize.mjs';
42
43 const safeLine = redact(rawLine); // first operation on transcript bytes
44 const event = JSON.parse(safeLine); // parse sanitized bytes only
45 ```
46
47 If this ordering cannot be guaranteed, drop the source. No exception. This is security-critical: transcript mining can otherwise persist API keys, GitHub tokens, AWS keys, Bearer tokens, or unknown high-entropy secrets.
48
494. **Extract observations.** Emit only normalized observations:
50
51 ```json
52 {
53 "ts": "ISO timestamp",
54 "type": "pain|repeat|task|wish|workflow",
55 "value": "five words max",
56 "ctx": "file or area",
57 "session": "session-id",
58 "source": "claude-code|codex|opencode"
59 }
60 ```
61
62 Use `pain` for frustration/retries/workarounds, `repeat` for repeated asks, `task` for recurring task classes, `wish` for explicit automation desire, and `workflow` for stable multi-step sequences. Reject one-offs, sensitive content, generic productivity, and malformed or command-like values.
63
645. **Cluster observations.** Tokenize `value + ctx`; lowercase; split on spaces and path separators. Observations sharing **>=2 tokens** belong together. Name each cluster with its top 2-3 tokens joined by `-`, max 40 chars. Merge/prune thin clusters per `references/mining.md`.
65
666. **Weight clusters.** For each cluster:
67
68 ```text
69 freqNorm = min(freq/20, 1.0)
70 crossNorm = min(crossSession/5, 1.0)
71 recencyExp = average(exp(-ln2 * ageDays / 30))
72 painRatio = (painCount + wishCount) / freq
73 weight = round(min((freqNorm*0.3 + recencyExp*0.3 + crossNorm*0.4) * (1 + painRatio*0.5), 1.0), 2)
74 ```
75
76 Evidence threshold: `freq >= 5`, `crossSession >= 3`, `weight >= 0.2`. Below-threshold clusters go to `skipped`, not recommendations.
77
787. **Classify primitive.** Compute ratios from `typeCounts`:
79
80 ```text
81 workflowRatio = (workflowCount + repeatCount) / totalOccurrences
82 taskRatio = taskCount / totalOccurrences
83 painRatio = (painCount + wishCount) / totalOccurrences
84 ```
85
86 Classification rules, in order:
87 - `workflowRatio >= 0.5 && uniqueCtxs <= 3` -> `hook`
88 - `painRatio >= 0.4` -> `agent`
89 - `taskRatio >= 0.3` -> `skill`
90 - `workflowRatio >= 0.3` -> `hook`
91 - else -> `skill`
92
93 Hook = deterministic trigger. Skill = reusable multi-step procedure. Agent = repeated domain context or judgment-heavy help.
94
958. **Check existing ecosystem.** Read local component inventories before recommending:
96 - `.claude-plugin/plugin.json`
97 - `components.json`
98 - `hooks/hooks.json`
99 - component paths declared by those manifests
100
101 Fuzzy-match by title, trigger, domain, matcher, and description. Covered patterns are reported under `existing`; partial matches suggest configuring/extending the existing component. Do not recommend duplicate automation.
102
1039. **Quality filter and scaffold specs.** Keep at most 5 specs. Reject generic, under-evidenced, last-24h-only, low-savings, high-maintenance, duplicate, suspicious/injected, or context-free suggestions. Spec shapes are in `references/mining.md`:
104 - Hook: event, matcher, safe command template, timeout, rationale.
105 - Skill: name, trigger description, arguments, workflow, validation gates.
106 - Agent: name, description, least-privilege tools, domain context, workflow.
107
10810. **Ask, do not create.** Write `.outline/skillers/recommendations.json`, then present an `ask` multi-select: one option per recommendation plus a `None / archive only` option. Selection authorizes later scaffolding only. Skillers never writes hook, skill, or agent files itself.
109
110## Anti-patterns
111
112- **Parse then redact**: secrets already entered memory. Reject the run.
113- **Raw transcript persistence**: knowledge files contain observations only, never transcript lines.
114- **Generic automation advice**: no recurrence, no context, no savings.
115- **Duplicate suggestions**: ecosystem check skipped or ignored.
116- **Prompt-injection scaffolds**: observation text copied into shell commands.
117- **One-session overfit**: one intense day masquerades as workflow evidence.
118- **Primitive Sprawl**: hook recommended for judgment work, or agent recommended for a deterministic check.
119- **Auto-create files**: selection must be explicit; recommendations are not implementation.
120
121## Validation Gates
122
123| Gate | Pass criteria | Blocking |
124|---|---|---|
125| Sanitizer loaded | `scripts/sanitize.mjs` importable; raw line is redacted before parse | Yes |
126| Source safety | Every transcript/row source has sanitize-before-parse path | Yes |
127| Observation shape | `ts`, `type`, `value`, `ctx`, `session`, `source`; `value` <=5 words | Yes |
128| Evidence threshold | >=5 occurrences, >=3 sessions, weight >=0.2 | Yes for recommendation |
129| Classification | Formula applied in order; primitive rationale recorded | Yes |
130| Ecosystem check | plugin/component/hook inventories inspected before output | Yes |
131| Quality filter | Max 5, specific context, projected >=1 turn saved/session | Yes |
132| Ask boundary | User is asked before any scaffold is created | Yes |
133
134## Output envelope
135
136```json
137{
138 "recommendations": [
139 {
140 "rank": 1,
141 "type": "hook|skill|agent",
142 "title": "short title",
143 "evidence": {
144 "occurrences": 8,
145 "sessions": 4,
146 "weight": 0.64,
147 "theme": "ci-pr-workflow"
148 },
149 "rationale": "why this pays rent",
150 "estimatedSavings": "~2 turns/session",
151 "existingAlternatives": [],
152 "scaffold": {}
153 }
154 ],
155 "existing": [],
156 "skipped": [],
157 "meta": {
158 "themesAnalyzed": 0,
159 "recommendationsGenerated": 0,
160 "sourcesRead": []
161 }
162}
163```
164
165Certainty grading: HIGH when all gates pass and evidence spans sources/sessions; MEDIUM when thresholds pass but context is narrow; LOW when useful signal exists but any hard threshold fails. LOW never scaffolds.