
Sublimate: Three Tiers for Distilling Workflows From Your Own Sessions
Anthropic shipped Dynamic Workflows in Claude Code this week. The harder question is which of your hand-rolled patterns belongs as a Workflow, which belongs as a Skill, and which belongs as a Subagent.
View companion repoThe rubric, before the runtime
Anthropic shipped Dynamic Workflows in Claude Code on 2026-05-28 (announcement: claude.com/blog/introducing-dynamic-workflows-in-claude-code; API reference: code.claude.com/docs/en/workflows.md). You declare phases in a literal meta block, then call phase(), agent(), parallel(), pipeline(). The runtime executes in the background. Your session stays responsive. v2.1.154, 16 concurrent agents, 1,000 per run, structured output schema-validated, /deep-research as the bundled example.
Workflows are not the only primitive. The docs say so under "When to use a workflow" (workflows.md, 2026-05-28). The interesting question is no longer "can I orchestrate." It is "what already lives in my session history, and which of three primitives should it become."
Three things you can lift a repeated pattern into:
- Subagent. One isolated investigation. Claude spawns it, gets a focused report, integrates the result. "Find every file that imports X." "Look up what error this returns." One-off. Lightweight. (post-15, claude-code-skills-factory.)
- Skill. A reusable procedure Claude orchestrates turn by turn, intermediate state in Claude's context. lint-then-format-then-commit. fetch-issue-then-implement-then-test. Three to six agents, runs inline. (Per
~/.claude/skills/registry.) - Workflow. A script the runtime executes. Holds the loop, branching, and intermediate state itself, so Claude's context only sees the final answer. Reach for it when you need dozens of agents, parallel concurrency, or resume across context interrupts. Codebase-wide bug sweep. 500-file migration. Parallel-finders feeding a serial synthesizer. (workflows.md, "When to use a workflow," 2026-05-28.)
The same procedure can be all three at different scales. Generating one blog cover is a Skill. Generating twenty in parallel with retry-on-fail is a Workflow. Looking up which Stitch prompt your last cover used is a Subagent.
Most posts about Workflows are pitching Workflows. This one is about choosing among three.
What sublimate does
Sublimate is a Claude Code plugin that walks your session corpus, clusters by tool-call similarity, classifies each cluster by the rubric above, dispatches a per-cluster prompt-distiller subagent, and emits polished .workflow.js / SKILL.md / AGENT.md candidates. Repo: github.com/krzemienski/sublimate. Hyper-landing: workflows.withagents.dev. Apex catalog: withagents.dev/products/sublimate.
The name is the move. Sublimation is the solid-to-gas phase transition that skips liquid. The miner does the same. Noisy session traces sublime into ordered candidates with no whiteboard step between. The pattern was already there. The miner crystallizes it.
Mechanism, four parts:
- Walk. Every JSONL under
~/.claude/projects/<corpus>/. Extract per-turn(role, tool_name, tool_input_hash)tuples. (cli.py:39, sublimate repo.) - Shingle and cluster. Each session becomes a set of k=3 tool-name n-grams. Cluster sessions pairwise via Jaccard at threshold 0.35. (cluster.py + shingle.py, sublimate repo.)
- PrefixSpan. Mine each cluster for frequent subsequences at min-support 0.4. Shape emerges here. (prefixspan.py, sublimate repo.)
- Distill. A
prompt-distilleragent reads two or three sample sessions per cluster and writes coherentagent()prompts. The Python is upstream of the LLM, not a replacement for it. (agents/prompt-distiller.md, sublimate repo.)
End-to-end on the blog-series corpus (500 sessions sampled from 2,067): the Python miner runs in 1.36 seconds. The full skill chain — mine, curate, fan out per-cluster distillers, lint, report — runs in about ten and a half minutes. The Python is deterministic. The LLM steps cost wall-clock and tokens but produce real prompts. (plans/260528-2330-sublimate-v0.2-pivot/.audit/k3-distill-complete.txt, 2026-05-28.)
Install and invoke:
claude plugin marketplace add krzemienski/sublimate
claude plugin install sublimate@sublimate-marketplace
# from any project root:
/sublimate:distill
The slash command is the user surface. The Python is the engine. Skills, commands, and specialist agents (cluster-curator, prompt-distiller) sit between. (docs/ARCHITECTURE.md, sublimate repo.) The two-layer split is deliberate. The Python is fast and stays out of the LLM budget, so it can sweep every JSONL in the corpus. The LLM runs only after clustering reduces the input to a handful of sample sessions per cluster. Coarse work cheap, fine work expensive.
Four specimens, distilled from a real dogfood run
Honesty interlude. The v0.1 of this post (git history at commit 15ff750) cited three example workflows I wrote by hand. They were guesses dressed as evidence. I deleted them. Then I ran the plugin against my own blog-series corpus — /sublimate:distill in a fresh tmux session as a third-party user, full skill chain, no shortcuts. The transcript is captured at plans/260528-2330-sublimate-v0.2-pivot/.audit/k-transcript.jsonl (554KB). Every specimen below traces to that transcript and to an emitted artifact at .audit/k-emitted/.
The Phase K dogfood produced this Stage 7 report (verbatim from the tmux pane, 2026-05-28):
Cluster Size Tier Verdict File
------- ---- ---- ------- ----
1 361 SKILL KEEP /tmp/sublimate-run/cluster-1/SKILL.md
3 6 SKILL KEEP /tmp/sublimate-run/cluster-3/SKILL.md
8 12 SUBAGENT KEEP /tmp/sublimate-run/cluster-8/AGENT.md
9 6 WORKFLOW KEEP /tmp/sublimate-run/cluster-9.workflow.js
11 6 SKILL KEEP /tmp/sublimate-run/cluster-11/SKILL.md
12 5 SKILL KEEP /tmp/sublimate-run/cluster-12/SKILL.md
13 5 SKILL KEEP /tmp/sublimate-run/cluster-13/SKILL.md
14 5 SKILL KEEP /tmp/sublimate-run/cluster-14/SKILL.md
(other 9 clusters: 5 SKIP, 4 NEEDS_MORE_SIGNAL)
Emitted: 6 SKILL + 1 SUBAGENT + 1 WORKFLOW = 8 candidates.
Four picks worth walking through.
dream-memory-consolidation — SKILL, 361 sessions
Origin: blog-series cluster 1. The curator sample-cited 018eeda4-fbb2-4f94-a1f1-7240da424dcf.jsonl. (curation.json, k-emitted.)
The pattern: a Bash + Read + Grep + Write loop, repeating across 361 sessions, that reads MEMORY.md, scans logs/YYYY/MM/, drift-checks code state, then updates topic files and re-indexes. This is what /dream does — memory consolidation. The Python miner saw the procedure-shape without knowing what /dream was. The cluster-curator agent classified it SKILL because it is a coherent multi-phase procedure that Claude orchestrates turn-by-turn (not background-script work).
The distilled meta.description from the prompt-distiller agent:
"Reflective pass over project memory directory — orient on existing memories, gather new signal from logs/transcripts, consolidate into topic files, prune the MEMORY.md index."
That description was not written by me. It was written by the distiller agent after reading two real /dream sessions. (.audit/k-emitted/cluster-1/SKILL.md, lines 1-4.)
parallel-file-write-with-verify — WORKFLOW, 6 sessions
Origin: blog-series cluster 9. Sample-cited: 239ce6ee-467a-4437-914d-1cb51260c640/subagents/workflows/wf_5176ec98-1e1/agent-a72dccfcec0c806fe.jsonl. (curation.json, k-emitted.)
This one is the only Workflow-tier specimen the miner emitted from blog-series. The reason: WORKFLOW requires multi-phase shape with fan-out, repeated five-plus times. Cluster 9 has exactly that — parent workflows that scatter N writer-subagent spawns in parallel, followed by a verify pass. Six occurrences in the corpus. The distiller agent named it parallel-file-write-with-verify and inlined real source-of-truth paths from the blog-series tree as example targets:
const writeTargets = [
{ label: 'write-page', path: '/Users/nick/Desktop/blog-series/site/src/app/sublimate/page.tsx', ack: 'WROTE page' },
{ label: 'write-post-md', path: '/Users/nick/Desktop/blog-series/posts/post-35-sublimate/post.md', ack: 'WROTE post' },
// … six total
]
await parallel(writeTargets.map((t) => () =>
agent(`Write ${t.path} via the Write tool.\n\n…\nWhen the Write tool returns success, reply with exactly: "${t.ack}".`,
{ label: t.label, phase: 'write-fan-out' }
)
))
(.audit/k-emitted/cluster-9.workflow.js, lines 12-30, dogfood-emitted 2026-05-28.) The verify pass is one agent that Reads each written file, counts placeholders / AI-tells / cited specimens, and emits a markdown audit table. That second phase is the load-bearing part — fan-out without verify is just speed.
file-writer-worker — SUBAGENT, 12 sessions
Origin: blog-series cluster 8. Sample-cited: wf_20d2bf84-f00/agent-a12d5a2eb14aef09a.jsonl. (curation.json, k-emitted.)
The Subagent specimen is the cleanest illustration of why "Workflow" is not the answer to everything. Cluster 8 is twelve siblings — twelve workers spawned by a parent workflow, each writing exactly one file. Single repeated role. No orchestration. No phase boundary. Tools needed: Write. The distiller's contract:
"Input: one prompt containing a target absolute path, file purpose, and exact spec. Action: invoke
Writetool once with that path and the synthesized content. Output: literal confirmation stringWROTE <basename>(e.g.WROTE shingle.py)."
(.audit/k-emitted/cluster-8/AGENT.md, lines 11-15.) If this had been classified WORKFLOW the runtime would have wrapped a single-task pattern in a deterministic checkpoint scaffold for nothing. The rubric pulls patterns toward the lighter tier where they belong, not toward the heaviest tier because Workflows are the shiny new thing. The curator's rationale for cluster 8 was explicit about this: "workflow-subagent given one Write directive — 12 sibling spawns from parent workflow each writing one file. Single repeated role." (curation.json, record id=8.)
audit-e2e — SKILL, 6 sessions
Origin: blog-series cluster 11. Sample-cited: agent-a0e6cf9fa2bece81b.jsonl. (curation.json, k-emitted.)
This is the chrome-devtools e2e-audit pattern that ran on every recent ds-fix-vN team trial. Five user journeys (J1..J5) per teammate, mandatory skill receipts (e2e-validate, agent-browser, functional-validation), per-journey new_page → take_screenshot → click via uid → close_page. The distiller's allowed-tools list captures it precisely:
allowed-tools: mcp__chrome-devtools__list_pages, mcp__chrome-devtools__new_page,
mcp__chrome-devtools__select_page, mcp__chrome-devtools__take_screenshot,
mcp__chrome-devtools__take_snapshot, mcp__chrome-devtools__click,
mcp__chrome-devtools__evaluate_script, mcp__chrome-devtools__close_page,
Bash, Write, TaskCreate, TaskUpdate
(.audit/k-emitted/cluster-11/SKILL.md, line 4.) The body documents the new_page → list_pages → select_page → snapshot pitfall (snapshot returns about:blank if you forget the re-select), enumerates five common journey shapes, prescribes a FAIL-handling protocol. None of that was written by me. The distiller agent extracted it from two real audit-e2e team-trial transcripts.
Cluster 11 has three parallel siblings the miner also surfaced — cluster 12 (a11y), cluster 13 (perf), cluster 14 (responsive). Same fan-out shape, four different dimensions of audit. All four KEEP. All four polished. (curation.json, ids 11-14.)
What the miner gets right
Three things, named plainly.
It refuses to invent shape. PrefixSpan only emits subsequences that actually repeat in the corpus. If your sessions never converged on a pattern, the miner returns nothing for that cluster. Cluster 0, cluster 6, cluster 10 in the blog-series run all came back SKIP — the curator's rationale for cluster 0 was "Mixed bridge-session bookkeeping plus one /dream subagent; no coherent procedure across 4 samples." (curation.json id=0.) Honesty by mechanism.
It separates discovery from authorship. Python does the heavy mining over 500 JSONL files in 1.36 seconds. The LLM does the prompt distillation per cluster, reading sample sessions and writing real agent() prompts. Each layer does what it is best at.
It surfaces shape regardless of tier. The miner does not know what a Workflow is. It finds patterns. The cluster-curator agent classifies each cluster by the three-tier rubric. That is why Subagent and Skill candidates come out alongside Workflow candidates, instead of every cluster getting forced into a .workflow.js.
What the miner gets wrong
Three things, also named plainly.
Tool-name granularity is coarse. Read → Edit → Bash is a thousand different procedures. Semantic intent is not encoded in tool names. The miner clusters by shape. You decide which clusters share intent.
Phase boundaries are heuristic. Right now they cut at user-prompt edges. Sometimes that is right (the user re-orients). Sometimes it is wrong (the user nudges mid-phase). A future revision should look at intent shifts in the assistant's tool use, not just at where the human spoke.
The first attempt blew up. The dogfood run surfaced four shippable bugs the static plan never would have. The marketplace schema rejected "source": ".". The Python relative-import command was wrong. The emit loop ran without a cap and produced a 438MB file for one dense cluster (cluster 12 of the blog-series corpus before the L3 fix). The cluster-curator's documented input schema referenced fields the miner does not emit. Four FAILs, four fixes. (plans/260528-2330-sublimate-v0.2-pivot/.audit/l-fix-log.md, 2026-05-28.) The point is not that the plugin was unfinished. The point is that "the plugin works as designed" is the kind of claim only dogfooding can verify.
Cross-corpus signal
Same /sublimate:distill, two more corpora.
The yt-transition-shorts-detector corpus (500 sessions sampled from 754) emitted thirteen clusters. The richest one was cluster 5: size 18, top pattern Read → StructuredOutput. That is the canonical Subagent shape — a single read followed by a structured-output classification, twelve to eighteen identical spawns per parent. (m-yt/clusters.json, dogfood 2026-05-28.) The first time I tried to mine this same corpus I named that pattern by hand and called it vfr-code-classify (post v0.1, commit 15ff750). The second time I let the miner find it. The miner found it.
The ils-ios corpus (124 sessions) was thinner. Nine clusters, only one big enough to emit. iOS sessions are more idiosyncratic — Xcode is one tool, the simulator is another, the code itself reads differently than web work. The miner returning "nothing here" for most of an ils-ios corpus is the same honesty-by-mechanism principle as the SKIP verdicts on blog-series cluster 0. Not every project distills.
The cross-corpus signal is the most important thing. Three runs, three different cluster shapes, the same algorithm, the same artifact format. No special-casing per project. The miner walks JSONL and clusters by shape. The curator agent and prompt-distiller agent do the rest.
Caveats
v0.2 is heuristic. Tool-call shapes are not semantic intent. The Python proposes, you curate.
Dynamic Workflows requires Claude Code v2.1.154+ on Pro / Max / Team / Enterprise. The Sublimate miner itself runs anywhere with Python 3.10 and your own session JSONL files. No Anthropic account needed for the mining step. The output is portable JavaScript and Markdown. You decide where it runs.
The blog-series Phase K run took ten and a half minutes wall-clock with the curator + 8 prompt-distillers fanning out. That is real LLM cost. The Python miner stage alone is 1.36 seconds — almost free. If you only want the cluster table to scan by eye, you can stop after Stage 2 and skip the LLM passes entirely.
What I want you to try
claude plugin marketplace add krzemienski/sublimate
claude plugin install sublimate@sublimate-marketplace
/sublimate:distill
Three steps after that:
- Read the
examples/directory in the repo — these are the polished specimens from the blog-series Phase K dogfood. Skim how the distiller agent named and phased them. - Run the slash command against your highest-volume project. Skim the cluster table.
- Promote one. Hand-polish the prompts the distiller produced, or accept them as-is for a first run. Drop the file into your project's
.claude/workflows/or.claude/skills/directory via/sublimate:promote <cluster-id>.
One pattern you did not know you had is a win. One pattern you knew about but never wrote down is also a win. Eight candidates surface, three earn a place — the right ratio. (blog-series Phase K dogfood, 2026-05-28.)
Why this matters now
Patterns that took serious agent-builders six months to converge on are now first-class primitives in the runtime. That is the story of every developer-tools generation. A few people build something by hand. The platform watches what they do. The platform primitivizes it. The capability becomes available to everyone. (post-15, claude-code-skills-factory.) Today is one of those days for orchestration.
The patterns the miner found in my own corpus are not clever. They are obvious in hindsight. The reason I never wrote them down as Workflows or Skills before today is that I did not have a runtime that read them as code, and I did not have a rubric that told me which tier each one belonged to. Now I have both.
You probably have your own three or four. Go find them.
- Repo: github.com/krzemienski/sublimate
- Hyper-landing: workflows.withagents.dev
- Apex catalog: withagents.dev/products/sublimate
- LinkedIn Pulse companion: "The Sublimate Moment"
- Anthropic announcement: claude.com/blog/introducing-dynamic-workflows-in-claude-code
- Workflows docs: code.claude.com/docs/en/workflows.md
Continue the series
- 36SeriesShannon v1.2.0: Multi-Stage Agentic Work as a Sequence of Provable StepsA Claude Code plugin that refuses to say 'done' until the evidence is on disk. 36 skills, 11 agents, 22 commands, 7 hooks — and a doctor that reads its own contract.
- 37SeriesLinkedIn Has No Pulse API: Designing a Pipeline Around a Manual GateThe publisher fires LinkedIn feed posts on its own. It cannot create a Pulse article. So I built the whole content OS around one irreducible human paste.
- 38SeriesAuditing the Agent: Mining My Own Sessions to Catch 27 MistakesThe agent's session transcripts are a labeled record of every time it diverged from what I asked. So I mined them — and made it grade its own work.
- 39SeriesThe Machine That Writes These PostsA content pipeline of 24 commands and 11 skills mines my sessions, drafts the post, and refuses to let any machine click Publish. This one was made by it.