rote-cli 0.4.0__tar.gz → 0.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. {rote_cli-0.4.0 → rote_cli-0.6.0}/.gitignore +4 -0
  2. rote_cli-0.6.0/PKG-INFO +416 -0
  3. rote_cli-0.6.0/README.md +370 -0
  4. {rote_cli-0.4.0 → rote_cli-0.6.0}/skills/rote-graduate/SKILL.md +10 -0
  5. rote_cli-0.6.0/skills/rote-graduate/references/eval-estimates.md +112 -0
  6. {rote_cli-0.4.0 → rote_cli-0.6.0}/skills/rote-graduate/references/ir-schema.md +11 -0
  7. {rote_cli-0.4.0 → rote_cli-0.6.0}/skills/rote-graduate/references/llm-judge-extraction.md +9 -0
  8. {rote_cli-0.4.0 → rote_cli-0.6.0}/src/rote/__init__.py +1 -1
  9. rote_cli-0.6.0/src/rote/adapters/__init__.py +105 -0
  10. {rote_cli-0.4.0 → rote_cli-0.6.0}/src/rote/adapters/_common.py +166 -1
  11. rote_cli-0.6.0/src/rote/adapters/_py_common.py +799 -0
  12. rote_cli-0.6.0/src/rote/adapters/_ts_common.py +702 -0
  13. {rote_cli-0.4.0 → rote_cli-0.6.0}/src/rote/adapters/cloudflare.py +94 -210
  14. rote_cli-0.6.0/src/rote/adapters/dbos.py +807 -0
  15. {rote_cli-0.4.0 → rote_cli-0.6.0}/src/rote/adapters/dbos_ts.py +56 -212
  16. rote_cli-0.6.0/src/rote/adapters/inngest.py +845 -0
  17. rote_cli-0.6.0/src/rote/adapters/python.py +647 -0
  18. {rote_cli-0.4.0 → rote_cli-0.6.0}/src/rote/adapters/temporal.py +19 -72
  19. rote_cli-0.6.0/src/rote/cli.py +1065 -0
  20. rote_cli-0.6.0/src/rote/eval/__init__.py +43 -0
  21. rote_cli-0.6.0/src/rote/eval/empirical.py +617 -0
  22. rote_cli-0.6.0/src/rote/eval/estimate.py +399 -0
  23. rote_cli-0.6.0/src/rote/eval/pricing.py +457 -0
  24. rote_cli-0.6.0/src/rote/eval/priors.py +106 -0
  25. rote_cli-0.6.0/src/rote/eval/scorecard.py +357 -0
  26. rote_cli-0.6.0/src/rote/eval/sidecar.py +97 -0
  27. rote_cli-0.6.0/src/rote/eval/tokens.py +96 -0
  28. {rote_cli-0.4.0 → rote_cli-0.6.0}/src/rote/graduator/__init__.py +140 -3
  29. {rote_cli-0.4.0 → rote_cli-0.6.0}/src/rote/graduator/drivers/__init__.py +10 -1
  30. {rote_cli-0.4.0 → rote_cli-0.6.0}/src/rote/graduator/drivers/anthropic_api.py +11 -11
  31. {rote_cli-0.4.0 → rote_cli-0.6.0}/src/rote/graduator/drivers/claude.py +29 -16
  32. {rote_cli-0.4.0 → rote_cli-0.6.0}/src/rote/graduator/drivers/codex.py +1 -0
  33. rote_cli-0.6.0/src/rote/graduator/update.py +152 -0
  34. {rote_cli-0.4.0 → rote_cli-0.6.0}/src/rote/ir.py +184 -4
  35. rote_cli-0.6.0/src/rote/serve/backends.py +343 -0
  36. {rote_cli-0.4.0 → rote_cli-0.6.0}/src/rote/serve/registry.py +49 -2
  37. {rote_cli-0.4.0 → rote_cli-0.6.0}/src/rote/serve/server.py +65 -0
  38. rote_cli-0.6.0/src/rote/skill_source.py +135 -0
  39. rote_cli-0.4.0/PKG-INFO +0 -604
  40. rote_cli-0.4.0/README.md +0 -558
  41. rote_cli-0.4.0/src/rote/adapters/__init__.py +0 -77
  42. rote_cli-0.4.0/src/rote/adapters/_ts_common.py +0 -338
  43. rote_cli-0.4.0/src/rote/adapters/dbos.py +0 -1255
  44. rote_cli-0.4.0/src/rote/cli.py +0 -532
  45. rote_cli-0.4.0/src/rote/serve/backends.py +0 -187
  46. {rote_cli-0.4.0 → rote_cli-0.6.0}/LICENSE +0 -0
  47. {rote_cli-0.4.0 → rote_cli-0.6.0}/pyproject.toml +0 -0
  48. {rote_cli-0.4.0 → rote_cli-0.6.0}/skills/rote-graduate/references/crystallization-heuristics.md +0 -0
  49. {rote_cli-0.4.0 → rote_cli-0.6.0}/skills/rote-graduate/references/node-kinds.md +0 -0
  50. {rote_cli-0.4.0 → rote_cli-0.6.0}/src/rote/serve/__init__.py +0 -0
@@ -108,3 +108,7 @@ TODO.local.md
108
108
 
109
109
  # ── Claude Code agent worktrees ──
110
110
  .claude/worktrees/
111
+ .worktrees/
112
+
113
+ # Proprietary hosted platform — now the separate private rote-cloud repo
114
+ cloud/
@@ -0,0 +1,416 @@
1
+ Metadata-Version: 2.4
2
+ Name: rote-cli
3
+ Version: 0.6.0
4
+ Summary: Graduate fuzzy AI skills into deterministic, reliable workflows
5
+ Project-URL: Homepage, https://github.com/trevhud/rote
6
+ Project-URL: Repository, https://github.com/trevhud/rote
7
+ Project-URL: Issues, https://github.com/trevhud/rote/issues
8
+ Project-URL: Documentation, https://github.com/trevhud/rote#readme
9
+ Author: Trevor Hudson
10
+ License-Expression: Apache-2.0
11
+ License-File: LICENSE
12
+ Keywords: agent,ai,anthropic,claude,cloudflare,dspy,graduation,llm,skill,temporal,workflow
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Software Development :: Code Generators
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: pydantic>=2.7
24
+ Requires-Dist: pyyaml>=6.0
25
+ Provides-Extra: api
26
+ Requires-Dist: anthropic>=0.89; extra == 'api'
27
+ Provides-Extra: dbos
28
+ Requires-Dist: dbos>=2.26; extra == 'dbos'
29
+ Provides-Extra: dev
30
+ Requires-Dist: anthropic>=0.89; extra == 'dev'
31
+ Requires-Dist: dbos>=2.26; extra == 'dev'
32
+ Requires-Dist: fastmcp>=3.4.2; extra == 'dev'
33
+ Requires-Dist: httpx>=0.28; extra == 'dev'
34
+ Requires-Dist: mypy>=1.10; extra == 'dev'
35
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
36
+ Requires-Dist: pytest>=8.0; extra == 'dev'
37
+ Requires-Dist: ruff>=0.6; extra == 'dev'
38
+ Requires-Dist: temporalio>=1.7; extra == 'dev'
39
+ Requires-Dist: types-pyyaml; extra == 'dev'
40
+ Provides-Extra: serve
41
+ Requires-Dist: fastmcp>=3.4.2; extra == 'serve'
42
+ Requires-Dist: httpx>=0.28; extra == 'serve'
43
+ Provides-Extra: temporal
44
+ Requires-Dist: temporalio>=1.7; extra == 'temporal'
45
+ Description-Content-Type: text/markdown
46
+
47
+ # rote
48
+
49
+ **Graduate fuzzy AI skills into deterministic, reliable workflows.**
50
+
51
+ [![CI](https://github.com/trevhud/rote/actions/workflows/ci.yml/badge.svg)](https://github.com/trevhud/rote/actions/workflows/ci.yml)
52
+ [![PyPI](https://img.shields.io/pypi/v/rote-cli.svg)](https://pypi.org/project/rote-cli/)
53
+ [![Python versions](https://img.shields.io/pypi/pyversions/rote-cli.svg)](https://pypi.org/project/rote-cli/)
54
+ [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
55
+
56
+ `rote` is a CLI that takes an Anthropic-style Skill (a `SKILL.md` plus
57
+ `references/`) and turns it into a runnable background pipeline in one
58
+ shot. An LLM agent (itself defined as a skill) reads the source skill,
59
+ applies a structured graduation rubric, and emits a runtime-agnostic
60
+ intermediate representation (`pipeline.yaml`), extracted Python modules
61
+ for the deterministic parts, typed signature stubs for the LLM-judge
62
+ parts, and runnable code for the durable execution engine of your
63
+ choice.
64
+
65
+ ```sh
66
+ pip install rote-cli # or zero-install: uvx --from rote-cli rote ...
67
+
68
+ # `rote graduate` runs an LLM agent, so it needs a driver: Claude Code
69
+ # (`claude`) or Codex (`codex`) installed and authed, or ANTHROPIC_API_KEY
70
+ # for the in-process `api` driver. The BDR run below takes ~13 min and
71
+ # ~$0.70 with Sonnet. (`rote emit` needs no LLM — see below.)
72
+
73
+ # Default target is DBOS — durable execution as a plain Python library,
74
+ # no orchestrator to run, SQLite for dev / Postgres for prod:
75
+ rote graduate ./examples/bdr-outreach/skill --out ./graduated/
76
+
77
+ # Or pick another runtime (see the table below):
78
+ rote graduate ./examples/bdr-outreach/skill --runtime temporal --out ./graduated/
79
+ rote graduate ./examples/bdr-outreach/skill --runtime cloudflare --out ./graduated/
80
+ ```
81
+
82
+ The name comes from *rote learning* — doing something so many times, so
83
+ reliably, that it becomes mechanical. That's what graduation does to a
84
+ skill: a fuzzy 10–20 minute agent loop becomes a deterministic pipeline
85
+ that runs in the background, costs a fraction of the tokens, and can be
86
+ regression-tested.
87
+
88
+ ---
89
+
90
+ ## Why
91
+
92
+ Fuzzy AI skills work, but in production they're slow (a 10–20 minute
93
+ agent loop is unacceptable as a background job), expensive (multi-agent
94
+ loops use ~15× the tokens of a single chat, mostly re-deriving
95
+ procedures the author already wrote down), and non-deterministic (a
96
+ "MANDATORY" check enforced only by prose can be silently skipped, and
97
+ there's no way to regression-test a behavior the LLM has to remember).
98
+
99
+ The fix is to separate the parts of a skill that are *actually* fuzzy
100
+ from the deterministic procedures wearing fuzzy clothing. Move the
101
+ deterministic parts into code, keep the LLM only where the input is
102
+ genuinely unbounded (parsing, classifying, drafting), and wrap the whole
103
+ thing in a durable execution engine with explicit human-in-the-loop
104
+ gates. That graduation step is what `rote` automates.
105
+
106
+ There's third-party data for what this buys. ["Compiled AI: Deterministic
107
+ Code Generation for LLM-Based Workflow Automation"](https://arxiv.org/abs/2604.05150)
108
+ (Trooskens et al., Apr 2026) measured compiling LLM workflows into
109
+ deterministic code: **57× fewer tokens** at 1,000 transactions, **450×
110
+ lower** median latency, **100% reproducibility** (vs. 95% for direct
111
+ inference at temperature 0), and ~**40× lower TCO** at a million
112
+ transactions a month. The multiples grow with volume — once a workflow
113
+ is proven, every run through an agent loop pays LLM prices for work code
114
+ does for free.
115
+
116
+ A distinction worth being precise about: durable-execution vendors make
117
+ fuzzy agents *durable* (wrap the loop in retries and state so it survives
118
+ crashes — still fuzzy inside). `rote` *removes* the fuzzy loop. The two
119
+ compose: Temporal, Cloudflare Workflows, and the rest are `rote`'s
120
+ compile targets, not its rivals.
121
+
122
+ **When not to use `rote`:** exploratory and one-off work should stay an
123
+ agent loop — flexibility is the whole point there, and there's nothing
124
+ proven to compile yet. `rote` is for the skill you've run twenty times
125
+ and want to run a thousand more, unattended.
126
+
127
+ ---
128
+
129
+ ## How it works
130
+
131
+ `rote` is a three-layer system; each layer has one job and contracts on
132
+ a small interface.
133
+
134
+ ```
135
+ SKILL.md + references/ Source skill bundle (untouched)
136
+ │ rote graduate
137
+
138
+ graduator agent An LLM agent (Claude / Codex /
139
+ (pluggable driver) Anthropic SDK) runs the rote-graduate
140
+ │ skill against the source bundle.
141
+ │ filesystem contract: work_dir/pipeline.yaml
142
+ ▼ + extracted/ + signatures/
143
+ Pipeline IR (pipeline.yaml) Pydantic-validated DAG of typed
144
+ │ nodes. Five node kinds. Runtime-agnostic.
145
+ │ rote.adapters.<runtime>
146
+
147
+ emitted runtime code Native code for the target durable
148
+ execution engine.
149
+ ```
150
+
151
+ 1. **The graduator agent** (`skills/rote-graduate/`) — a regular
152
+ Anthropic Skill (`SKILL.md` + four reference files). This is the
153
+ *brain*; it runs inside any Skills-compatible surface, and you don't
154
+ need `rote` to use it.
155
+ 2. **The IR** (`src/rote/ir.py`) — Pydantic models for the five node
156
+ kinds plus edges, retries, HITL gates, and metadata. The IR is the
157
+ source of truth; everything downstream is template substitution.
158
+ 3. **Runtime adapters** (`src/rote/adapters/`) — pluggable modules that
159
+ consume an IR and emit runnable code for one engine.
160
+
161
+ The graduator's job ends when it has produced a valid `pipeline.yaml`.
162
+ Code emission is *deterministic Python* — never agent-driven — so the
163
+ same IR always produces byte-identical output.
164
+
165
+ ---
166
+
167
+ ## Quickstart
168
+
169
+ ### From Claude Code (recommended)
170
+
171
+ `rote` ships as a Claude Code plugin, so you can graduate a skill without
172
+ touching Python tooling:
173
+
174
+ ```
175
+ /plugin marketplace add trevhud/rote
176
+ /plugin install rote@rote
177
+ ```
178
+
179
+ Then say "graduate this skill" (or run `/rote:graduate`). It confirms the
180
+ source directory, asks which runtime you want, runs the CLI via
181
+ [uv](https://docs.astral.sh/uv/) in the background, and reports the
182
+ emitted pipeline. A second skill, `/rote:serve`, wires graduated
183
+ pipelines up as MCP tools so Claude can trigger the deployed workflows
184
+ (see [docs/mcp-trigger.md](docs/mcp-trigger.md)).
185
+
186
+ Prefer a terminal? The same thing is one `uvx` command:
187
+
188
+ ```sh
189
+ uvx --from rote-cli rote graduate ./my-skill --runtime dbos --out ./graduated
190
+ ```
191
+
192
+ > **Naming note:** the `rote` package on PyPI is an unrelated
193
+ > memoization library that also installs `import rote`, so the two can't
194
+ > share an environment. This project's distribution is `rote-cli` while
195
+ > the CLI command and import name stay `rote` — hence
196
+ > `uvx --from rote-cli rote ...`. See [docs/releasing.md](docs/releasing.md).
197
+
198
+ ### Run on the bundled example
199
+
200
+ The repo includes a real BDR outreach skill (lead generation, contact
201
+ vetting, CRM upload, mandatory exclusion checks, email personalization,
202
+ manual enrollment handoff) in `examples/bdr-outreach/skill/`:
203
+
204
+ ```sh
205
+ rote graduate examples/bdr-outreach/skill --out /tmp/bdr-graduated
206
+ ```
207
+
208
+ On that skill the graduator produces a 22-node IR that's **78.9%
209
+ codifiable** (15 of 19 non-gate nodes), extracts 5 Python modules and 2
210
+ typed judge signatures, and flags 4 mandatory nodes and 3 HITL gates —
211
+ in ~13 minutes for ~$0.70 (Sonnet via Claude Code). Along the way it
212
+ independently lifts the three MANDATORY exclusion checks out of prose,
213
+ pulls four batch-size constants out of prompt text, and models a
214
+ parallel entry path the hand-written baseline missed.
215
+
216
+ `rote` auto-detects a driver in the order `claude` → `codex` → `api`;
217
+ override with `--agent`. The output directory splits into `graduated/`
218
+ (the agent's `pipeline.yaml`, `extracted/`, `signatures/`, eval seeds,
219
+ and a `graduation-report.md`) and `runtime/<runtime>/` (the adapter's
220
+ emitted code + a README on how to run, signal gates, and deploy).
221
+
222
+ ### Other commands
223
+
224
+ - **`rote emit <pipeline.yaml>`** — run just the adapter step on an
225
+ existing IR (no LLM, no cost). The cheap inner loop while iterating on
226
+ adapters or IR shapes. Re-emitting is safe: a `.rote-manifest.json`
227
+ tracks what `rote` wrote, and files you've edited are left untouched
228
+ (the fresh version lands as `<name>.new`).
229
+ - **`rote graduate --update`** — re-graduate incrementally when the skill
230
+ changes. `rote` diffs the skill against the previous run's
231
+ `provenance.json` and re-derives only the nodes whose source sections
232
+ changed; unchanged nodes keep their ids (so in-flight durable workflows
233
+ aren't orphaned) and implemented stubs are kept. No change → no agent run.
234
+ - **`rote eval <graduated>`** — render the before/after scorecard (wall
235
+ clock, cost across the current model lineup at live prices, and how
236
+ much of the run is still LLM-decided). `rote graduate` writes this to
237
+ `graduated/scorecard.md` automatically. Add `--run` to *measure*
238
+ instead of estimate: it executes both sides for real and appends
239
+ measured cost, turns, and output agreement across trials.
240
+ - **Per-node inference** — emitted judges read `ROTE_MODEL_<ID>` and
241
+ `ROTE_BASE_URL_<ID>` at runtime, so you can swap the model or point at
242
+ any OpenAI-compatible endpoint (Ollama, vLLM, a gateway) without
243
+ re-emitting.
244
+
245
+ ---
246
+
247
+ ## The five node kinds
248
+
249
+ Every step in a graduated pipeline is exactly one of five kinds. Full
250
+ guidance:
251
+ [`references/node-kinds.md`](skills/rote-graduate/references/node-kinds.md).
252
+
253
+ | Kind | What it is | Where the LLM lives |
254
+ | --- | --- | --- |
255
+ | `pure_function` | Fixed logic, deterministic I/O | Not involved |
256
+ | `external_call` | Vendor API call with fixed semantics + retries | Not involved |
257
+ | `llm_judge` | Fuzzy classification against a rubric, typed I/O | Typed signature (DSPy/BAML in Python; Zod + vendor SDK in TS), from the IR's runtime-agnostic `signature_spec` |
258
+ | `agent_loop` | Genuinely exploratory tool use | Bounded agent loop |
259
+ | `hitl_gate` | Explicit human approval, suspend until signal | Durable suspend/resume |
260
+
261
+ The guiding rule: **keep the LLM at points where the input is unbounded
262
+ or ambiguous, and codify everything else.** When a step could go either
263
+ way, prefer the more deterministic kind.
264
+
265
+ ---
266
+
267
+ ## Runtimes
268
+
269
+ Pick with `--runtime`; the same IR drives all of them. None of the
270
+ emitted code references MCP — the crystallization step replaces tool
271
+ calls with direct vendor API calls.
272
+
273
+ | Runtime | `--runtime` | Language | Shape | Notes |
274
+ | --- | --- | --- | --- | --- |
275
+ | **DBOS** (default) | `dbos` | Python | `main.py` — `@DBOS.workflow` + `@DBOS.step` per node | No orchestrator to deploy; SQLite (dev) / Postgres (prod) |
276
+ | Temporal | `temporal` | Python | `workflow.py` + `activities.py` | Signal handlers for HITL gates |
277
+ | Plain Python | `python` | Python | single `main.py` script | Max legibility, stdlib only; refuses HITL-gate pipelines |
278
+ | Cloudflare Workflows | `cloudflare` | TypeScript | `WorkflowEntrypoint` + `wrangler.jsonc` | `wrangler deploy`-ready |
279
+ | DBOS (TypeScript) | `dbos-ts` | TypeScript | `src/main.ts` (DBOS Transact) | Zero-orchestrator; Postgres-only |
280
+ | Inngest | `inngest` | TypeScript | one `inngest.createFunction` | Mounts into an existing Node/Next.js app; retries are function-level |
281
+
282
+ ---
283
+
284
+ ## Drivers
285
+
286
+ `rote` ships three interchangeable graduator drivers — pick whichever
287
+ matches your auth. The same `pipeline.yaml` comes out either way.
288
+
289
+ | Driver | Backend | Auth | Install |
290
+ | --- | --- | --- | --- |
291
+ | `claude` (default) | `claude -p` subprocess | Claude Max/Pro OAuth or `CLAUDE_CODE_OAUTH_TOKEN` | Install Claude Code separately |
292
+ | `codex` | `codex exec` subprocess | ChatGPT Plus/Pro OAuth | Install Codex CLI separately |
293
+ | `api` | `anthropic` Python SDK | `ANTHROPIC_API_KEY` | `pip install 'rote-cli[api]'` |
294
+
295
+ The `claude` driver scrubs `ANTHROPIC_API_KEY` from the subprocess so a
296
+ subscription login wins, and limits the agent to read/write/glob/grep
297
+ tools. The default model is **Sonnet** rather than Opus — the task is
298
+ structured-rubric-following, not deep reasoning, and Sonnet brings
299
+ per-run cost from ~$3.50 to ~$0.70. Override with `--model` for skills
300
+ where Opus earns its cost. Full design record, including the auth gotcha:
301
+ [docs/agent-runtime.md](docs/agent-runtime.md).
302
+
303
+ `rote` explicitly **does not** depend on `claude-agent-sdk`: Anthropic's
304
+ ToS forbids third-party agents built on the Agent SDK from using
305
+ claude.ai login credentials without approval, which would defeat the
306
+ subscription path.
307
+
308
+ ---
309
+
310
+ ## How it differs from other tools
311
+
312
+ - **vs. raw durable engines (Temporal / Cloudflare / Inngest / Restate):**
313
+ they give you the workflow *runtime*; they don't help you decide *what
314
+ should be a workflow*. `rote` is the missing step that turns a working
315
+ skill into something worth running on one.
316
+ - **vs. LangGraph:** LangGraph is an excellent state machine, but its
317
+ graph is hand-built. `rote` produces a graph *from prose*, classifies
318
+ nodes by determinism, and pushes work out of the agent loop wherever
319
+ the data supports it.
320
+ - **vs. using Skills directly:** Skills run great interactively. `rote`
321
+ is what you reach for when a skill becomes business-critical and needs
322
+ to run unattended with hard reliability guarantees and per-step
323
+ regression tests.
324
+
325
+ ---
326
+
327
+ ## Status
328
+
329
+ `rote` is **pre-1.0**. The end-to-end flow works on the BDR example, and
330
+ all six adapters are validated by a `slow`-marked e2e suite that runs the
331
+ emitted code against real runtimes (DBOS over SQLite, Temporal's
332
+ time-skipping server, the TypeScript targets compiled with `tsc --noEmit`
333
+ and driven through both HITL gates on live dev servers, the plain-Python
334
+ script as a subprocess, and the MCP server over real stdio). The fast
335
+ suite (`pytest tests/`) makes no real API calls; the integration suite is
336
+ `pytest tests/ -m slow`.
337
+
338
+ Known gaps: the `codex` driver is a stub (`is_available` works, `run`
339
+ isn't implemented), the extracted modules are `NotImplementedError` stubs
340
+ you fill in with real API-client code, a Restate adapter is planned, and
341
+ `fan_out` nodes currently receive the whole upstream list in one
342
+ invocation (per-element dispatch is a planned enhancement). Published on
343
+ PyPI as [`rote-cli`](https://pypi.org/project/rote-cli/) via tag-driven
344
+ Trusted Publishing ([docs/releasing.md](docs/releasing.md)).
345
+
346
+ ---
347
+
348
+ ## Repository layout
349
+
350
+ ```
351
+ rote/
352
+ ├── docs/ agent-runtime · mcp-trigger · releasing
353
+ ├── skills/rote-graduate/ the graduator agent (SKILL.md + 4 reference files)
354
+ ├── src/rote/
355
+ │ ├── cli.py rote graduate / emit / eval / serve
356
+ │ ├── ir.py Pydantic IR models + load_pipeline
357
+ │ ├── graduator/ orchestrator + drivers/ (claude · codex · anthropic_api)
358
+ │ └── adapters/ dbos · temporal · python · cloudflare · dbos_ts · inngest
359
+ │ (+ _common / _py_common / _ts_common emit helpers)
360
+ ├── examples/bdr-outreach/ source skill · hand-drafted IR baseline · run snapshots
361
+ └── tests/ fast + slow suites (pytest -m slow)
362
+ ```
363
+
364
+ ---
365
+
366
+ ## Documentation
367
+
368
+ - [`docs/agent-runtime.md`](docs/agent-runtime.md) — design record for the
369
+ driver abstraction (the `claude -p` env gotcha; the non-use of
370
+ `claude-agent-sdk`)
371
+ - [`docs/mcp-trigger.md`](docs/mcp-trigger.md) — `rote register` +
372
+ `rote serve`: graduated pipelines as MCP tools (FastMCP 3.x)
373
+ - [`docs/releasing.md`](docs/releasing.md) — tag-driven PyPI Trusted
374
+ Publishing
375
+ - [`skills/rote-graduate/`](skills/rote-graduate/) — the graduator's
376
+ `SKILL.md` and its four rubric files (node kinds, crystallization
377
+ heuristics, IR schema, LLM-judge extraction)
378
+ - [`examples/bdr-outreach/`](examples/bdr-outreach/) — the canonical
379
+ skill, its ground-truth IR, and snapshotted real graduator runs
380
+
381
+ ---
382
+
383
+ ## Roadmap
384
+
385
+ In rough priority order:
386
+
387
+ 1. **`CodexDriver` implementation** — same shape as `ClaudeDriver` but
388
+ spawning `codex exec`; unlocks ChatGPT subscribers.
389
+ 2. **Re-graduate BDR end-to-end with `signature_spec`** — the bundled IR
390
+ was hand-extended with structured schemas; the rubric now teaches the
391
+ field, but no real run has produced one yet.
392
+ 3. **Pre-filter as a `pure_function` node** — today hard thresholds are
393
+ lifted into a judge's `forward()`, which works for Temporal but not
394
+ Cloudflare; a separate node makes the short-circuit uniform.
395
+ 4. **More example skills** — BDR is one shape; research-heavy,
396
+ retrieval-heavy, and code-review skills stress the IR differently.
397
+ 5. **`fan_out` per-element dispatch** — currently the whole upstream list
398
+ arrives in one invocation.
399
+ 6. **The graduator graduating itself** — `rote-graduate` is a SKILL.md;
400
+ pointing `rote graduate` at it should crystallize its rubric-grade
401
+ pieces and leave only the genuinely fuzzy judgments in the loop.
402
+
403
+ ---
404
+
405
+ ## Contributing
406
+
407
+ The most useful contribution right now is to **run `rote graduate` on a
408
+ real skill of your own and report what happens** — the rubric was
409
+ designed against one skill and needs more. Adding a runtime adapter or a
410
+ graduator driver, or improving the rubric, are all good next steps. See
411
+ [CONTRIBUTING.md](CONTRIBUTING.md) for dev setup, the test layout, and
412
+ the adapter/driver how-tos.
413
+
414
+ ## License
415
+
416
+ Apache-2.0. See [LICENSE](LICENSE).