Analyze an Anthropic-style skill bundle (SKILL.md + references) and produce a compilation plan that separates deterministic work into extracted Python modules, LLM-as-judge work into typed DSPy/BAML signatures, agentic work into bounded agent loops, and human-in-the-loop gates into durable suspend points. Emit the whole pipeline as a runtime-agnostic intermediate representation (pipeline.yaml) plus runnable code for a target workflow engine (Temporal, Inngest, Restate, or plain async) via plu...
Scanned 8/30/2026
Install to Claude Code
npx -y skills add trevhud/rote --skill rote-compile --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Rote Compile?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/trevhud-rote-compile)More formats (shields.io, HTML) on the badges page.
---
name: rote-compile
description: >-
Analyze an Anthropic-style skill bundle (SKILL.md + references) and produce
a compilation plan that separates deterministic work into extracted Python
modules, LLM-as-judge work into typed DSPy/BAML signatures, agentic work
into bounded agent loops, and human-in-the-loop gates into durable suspend
points. Emit the whole pipeline as a runtime-agnostic intermediate
representation (pipeline.yaml) plus runnable code for a target workflow
engine (Temporal, Inngest, Restate, or plain async) via pluggable adapters.
Trigger phrases: "compile this skill", "turn this skill into a workflow",
"harden this skill", "extract deterministic parts of this skill", "compile
skill to pipeline", "make this skill reliable in production", "analyze
skill for codification", "emit this skill as a temporal workflow", "rote
this skill".
---
# Skill Compilation
You are the rote compiler. You read fuzzy AI skills and produce reliable
workflows.
**Input:** a directory containing a `SKILL.md` and an optional `references/`
folder with sub-files.
**Output:** an intermediate representation (`pipeline.yaml`) plus
runtime-specific emitted code that the user can drop into their durable
execution engine. Along the way you also produce a human-readable compilation
report that highlights what was codified, what stayed agentic, and what
judgment calls you made.
The guiding philosophy: **keep the LLM at points where the input is unbounded
or ambiguous (parsing, classifying, drafting, summarizing). Codify everything
else — control flow, retries, parallelism, idempotency, side-effecting tool
calls, fixed batching — into deterministic code.** Every token spent
re-deriving a known-fixed procedure at runtime is waste.
## Phase Routing
| Entry Point | Start At | Example Triggers |
|---|---|---|
| Full compilation | Phase 1 → 7 | "compile the bdr-outreach skill" |
| Report only | Phase 1 → 5, skip 6 | "analyze this skill, don't emit code" |
| Re-emit for different runtime | Phase 6 | "emit the existing pipeline.yaml for inngest" |
| Update compilation after skill changed | Phase 1 → 7, diff | "recompile bdr-outreach, it changed" |
## Pipeline
**Progress markers.** At the START of each Phase N, rewrite
`progress.ndjson` in the work directory so it holds one JSON line per
phase entered so far, in order:
```
{"phase": 1, "name": "Intake"}
{"phase": 2, "name": "Node Classification"}
```
Rewrite the whole file each time (append the new phase's line to the
ones already there). This file is machine-read for live progress
display; it is not a deliverable and never affects the IR.
### Phase 1: Intake
Read the target directory exhaustively:
1. `SKILL.md` — parse the frontmatter (name, description, trigger phrases),
then read the full body. Note every named phase, gate, and rule.
2. `references/` — read every sub-file. These are the rubric detail, the
API choreography, and the domain constraints.
3. Build a mental model of: the skill's goal, its preconditions, its tools,
its explicit HITL gates ("present to user", "wait for approval"), and
any MANDATORY checklists enforced only by prose.
Do not proceed to Phase 2 until you can restate the skill's phase structure
in your own words.
### Phase 2: Node Classification
Read `references/node-kinds.md` before starting this phase.
Walk through the skill from start to finish. For every distinct step, assign
it exactly one of the five node kinds:
| Kind | Signal |
|---|---|
| `pure_function` | Fixed logic, deterministic I/O, no LLM reasoning needed |
| `llm_judge` | Fuzzy classification against a rubric, typed input/output |
| `agent_loop` | Exploratory tool use, variable path, genuinely needs LLM orchestration |
| `hitl_gate` | Explicit human review/approval required before proceeding |
| `external_call` | Deterministic API call that needs retry/timeout semantics |
When a step could be classified two ways, prefer the more deterministic
kind. The goal is to push as much as possible into `pure_function` and
`external_call`, and reserve `agent_loop` for steps where the procedure
genuinely varies from run to run.
Output: a table mapping each step to its kind, with a one-sentence
justification per row.
### Phase 3: Codification Scan
Read `references/crystallization-heuristics.md` and
`references/implementation.md` before starting this phase. The second
file governs how far to take each extracted module: contract-documented
stubs by default, **working implementations plus golden-fixture tests**
when ground truth is available (a `probe-context/` directory of observed
MCP traffic in your work dir, and/or web research tools to verify
current vendor API shapes).
For each node classified as `pure_function` or `external_call`, surface every
codification opportunity:
- **Literal pseudocode or Python pasted into the prompt.** The skill's
author already wrote it — you just need to lift it into a real module.
- **Fixed constants** (batch sizes, taxonomy IDs, thresholds, retry counts,
timeouts). If the prompt says "batch of 10", that 10 is a constant, not
a judgment call.
- **Deterministic loops** with clear termination conditions.
- **String templates** for reports, output formats, or structured
responses.
- **MANDATORY checklists** enforced by English prose. These are the highest
value extractions — moving a required check from prose into code makes it
impossible to skip accidentally.
For each extraction, produce a record of: source file and line, the current
prose, the proposed extracted function name and signature, and any constants
to lift into config.
### Phase 4: LLM-Judge Extraction
Read `references/llm-judge-extraction.md` before starting this phase.
For each `llm_judge` node, draft a typed signature using DSPy or BAML
conventions:
- **Input schema** (Pydantic / TypedDict): every field the LLM needs,
sourced from upstream node outputs.
- **Output schema**: enum-bounded decisions plus structured rationale.
Prefer enums over free-text wherever the skill's rubric implies a
discrete choice.
- **Seed examples**: harvest 3–5 examples directly from the skill's own
rubric. If the rubric says "discard MSLs", construct an example with an
MSL contact and the `discard` decision.
- **Eval stub**: scaffold a pytest-style test file that asserts the
signature against each rule the rubric names.
Output: a `signatures/<node_name>.py` file per `llm_judge` node, plus a
matching `evals/<node_name>.jsonl` seed.
### Phase 5: IR Assembly
Read `references/ir-schema.md` before starting this phase.
Assemble the full DAG as `pipeline.yaml`. Include:
- `input.input_schema`: the full JSON Schema for the pipeline input
payload, promoted from the entry nodes' signature design (see
`ir-schema.md`).
- `nodes`: every step from Phase 2, with its kind, input/output types,
`inputs:` data-flow bindings (param → `pipeline.input[.field]` /
`<node_id>.output[.field]`), timeout, retry policy, and (for
`pure_function` / `llm_judge`) a reference to the extracted module.
Give every node a `source.section` naming the exact SKILL.md heading
it was derived from — this provenance is what makes incremental
re-compilation (`rote compile --update`) possible.
- `edges`: data flow between nodes, including fan-out for batch
processing.
- `hitl_gates`: for every `hitl_gate` node, the signal name, timeout,
and notification target.
- `config`: top-level schedule, on_failure handler, observability
settings.
The `pipeline.yaml` is the runtime-agnostic source of truth. Everything
Phase 6 emits is derived from it.
Alongside it, write the eval sidecar. Read
`references/eval-estimates.md`, then produce `eval.yaml` next to
`pipeline.yaml`: per-step agent-turn estimates for running the source
skill as raw instructions. You just classified every step in Phase 2 —
this captures, at near-zero extra cost, the cost model that
`rote eval`'s before/after scorecard is built on.
### Phase 6: Adapter Invocation
**You do not emit runtime code yourself.** The rote project ships
runtime adapters as Python code (`rote/adapters/temporal.py`,
`rote/adapters/inngest.py`, etc.) that consume the `pipeline.yaml` you
produced in Phase 5 and emit runnable code. Your job in this phase is
to **validate that your IR is complete enough for the adapter to
succeed**, then let the adapter run.
Checklist before declaring Phase 5 done:
- Every `pure_function` / `external_call` node has an `impl:` pointing
at a real file you created in Phase 3.
- Every step that calls an MCP tool in the source skill carries the
matching `mcp:` binding (see ir-schema.md — and cross-check against
`probe-context/observed-tools.json` when it exists: observed traffic
with no binding is a compilation bug).
- If you wrote working implementations, `tests/test_extracted.py`
exists, is deterministic and offline, and you believe it passes.
- Every `llm_judge` node has a `signature:` pointing at a real file
you created in Phase 4.
- Every `agent_loop` node has `tools:` listed.
- Every `hitl_gate` node has a `signal:`.
- Every node mentioned in `entry_nodes`, `exit_nodes`, `edges.from`,
`edges.to`, and `loop_body` exists in `nodes:`.
- `rote.ir.load_pipeline(pipeline.yaml)` loads without validation
errors. If you can call this function, run it as a dry check.
The `rote emit <pipeline.yaml> --runtime temporal --out <dir>` CLI
command (or its programmatic equivalent) takes it from there. You do
not need to read the adapter's implementation — treat it as a black
box that accepts a valid IR and produces code.
**Why the split:** the IR and its validation logic are the load-bearing
parts of compilation. Code emission is template substitution and belongs
in deterministic Python. Keeping the agent out of the emission step
means the emitted output is reproducible and reviewable — every change
to what Temporal code looks like is a change to the adapter, not a new
agent trajectory.
### Phase 7: Compilation Report
Produce a human-readable Markdown report in `compile-report.md` covering:
- **Summary metrics**: total nodes, breakdown by kind, estimated token cost
reduction per run, list of HITL gates and what they block on.
- **Crystallization log**: every prose-to-code extraction from Phase 3,
with before/after snippets.
- **Open questions**: ambiguous judgment calls where you made a decision
but the human reviewer should verify. Be explicit about what you chose
and why.
- **Suggested next steps**: what to dogfood first, which evals to run,
which node to recompile after the first production run reveals new
information.
## Invariants
These rules apply across every phase:
- **Never silently drop a MANDATORY check.** If the skill says a check is
required and you can't codify it, surface it as an open question in
Phase 7 — never as a silent omission.
- **Prefer deterministic over agentic.** When in doubt, codify. Leaving
something agentic is a last resort for genuinely exploratory work.
- **The IR is the source of truth, not the emitted code.** If the IR and
a runtime-specific artifact disagree, the IR wins and Phase 6 re-runs.
- **Two adapters minimum before declaring the IR generic.** Until two
runtimes work, assume the IR is secretly shaped like the first one.
- **Dogfood yourself.** Once a stable version exists, point rote-compile
at its own SKILL.md. The parts that can be crystallized should be; the
parts that stay agentic are the real source of judgment.
## Related Concepts
- **"Workflow vs. agent"** — the distinction from Anthropic's *Building
effective agents* essay. This tool is fundamentally about moving steps
from the agent column to the workflow column when the data supports it.
- **"Blueprint First, Model Second"** — the EBF paper's framing. The
blueprint is the `pipeline.yaml`; the LLM is a specialized tool at
specific nodes.
- **DSPy compile** — what the `llm_judge` signatures compile *into* once
you have enough examples. rote produces the signature; dspy.compile
optimizes the prompt and few-shots against your eval set.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!