rote-cli 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,546 @@
1
+ Metadata-Version: 2.4
2
+ Name: rote-cli
3
+ Version: 0.1.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
+ `rote` is a CLI that takes an Anthropic-style Skill (a `SKILL.md` plus
52
+ `references/`) and turns it into a runnable background pipeline in one
53
+ shot. An LLM agent (itself defined as a skill) reads the source skill,
54
+ applies a structured graduation rubric, and emits:
55
+
56
+ - a runtime-agnostic intermediate representation (`pipeline.yaml`),
57
+ - extracted Python modules for the deterministic parts of the skill,
58
+ - typed signature stubs for the LLM-judge parts,
59
+ - and runtime code for your durable execution engine of choice.
60
+
61
+ ```sh
62
+ # Two runtimes shipped today — emit Python for Temporal, or TypeScript
63
+ # for Cloudflare Workflows:
64
+ rote graduate ./examples/bdr-outreach/skill --runtime temporal --out ./graduated/
65
+ rote graduate ./examples/bdr-outreach/skill --runtime cloudflare --out ./graduated/
66
+ ```
67
+
68
+ The name comes from *rote learning* — doing something so many times, so
69
+ reliably, that it becomes mechanical. That's what graduation does to a
70
+ skill: a fuzzy 10-20 minute agent loop becomes a deterministic pipeline
71
+ that runs in the background, costs a fraction of the tokens, and can be
72
+ regression-tested.
73
+
74
+ ---
75
+
76
+ ## Why compile agents?
77
+
78
+ There's now third-party data for what compilation buys.
79
+ ["Compiled AI: Deterministic Code Generation for LLM-Based Workflow
80
+ Automation"](https://arxiv.org/abs/2604.05150) (Trooskens et al.,
81
+ Apr 2026) measured compiling LLM workflows into deterministic code
82
+ against running them through direct LLM calls: **57× fewer tokens** at
83
+ 1,000 transactions, **450× lower** median latency, **100%
84
+ reproducibility** where direct inference at temperature 0 managed 95%,
85
+ and roughly **40× lower TCO** at a million transactions a month. The
86
+ numbers come from a structured function-calling benchmark (BFCL), the
87
+ friendliest case for compilation, and the token and cost multiples
88
+ grow with volume. But the shape of the result holds: once a workflow
89
+ is proven, every run through an agent loop pays LLM prices for work
90
+ code does for free.
91
+
92
+ One distinction worth being precise about. Durable-execution vendors
93
+ make fuzzy agents *durable*: wrap the loop in retries and state so it
94
+ survives crashes, still fuzzy inside. rote removes the fuzzy loop:
95
+ compile the proven parts to deterministic code and keep the LLM only
96
+ where inputs are genuinely unbounded. The two compose rather than
97
+ compete — Temporal and Cloudflare Workflows are rote's compile
98
+ targets, not its rivals.
99
+
100
+ **When not to use rote:** exploratory and one-off work should stay an
101
+ agent loop; flexibility is the whole point there, and there's nothing
102
+ proven to compile yet. rote is for the skill you've run twenty times
103
+ and want to run a thousand more, unattended.
104
+
105
+ ---
106
+
107
+ ## What just happened on the bundled example
108
+
109
+ The repository includes a real BDR outreach skill (lead generation,
110
+ contact vetting, CRM upload, mandatory exclusion checks, email
111
+ personalization, manual enrollment handoff). Running `rote graduate` on
112
+ it with the default `claude` driver and Sonnet 4.6 produces:
113
+
114
+ | Output | Value |
115
+ | --- | --- |
116
+ | Total nodes in the produced IR | **22** |
117
+ | Codifiable percentage | **78.9 %** (15 of 19 non-gate nodes) |
118
+ | Extracted Python modules | **5** (`zoominfo`, `hubspot`, `conference`, `exclusions`, `report`) |
119
+ | Typed LLM-judge signatures | **2** (`vet_contact`, `personalize_email`) |
120
+ | Mandatory nodes (cannot be skipped) | **4** |
121
+ | Human-in-the-loop gates | **3** |
122
+ | Wall-clock time | ~13 minutes |
123
+ | Subscription cost | ~$0.70 (Sonnet 4.6 via Claude Code) |
124
+
125
+ The graduator independently:
126
+
127
+ - Identified the three MANDATORY exclusion checks from prose-only
128
+ enforcement and marked them `mandatory: true` in the IR.
129
+ - Extracted four batch-size constants (`10`, `100`, `250`, `30`-day
130
+ window) that lived only in prompt prose.
131
+ - Lifted a literal Python keyword classifier out of a reference file
132
+ into a real module.
133
+ - Modeled a parallel "conference list" entry path with its own HITL
134
+ gate that the human-written baseline missed.
135
+ - Surfaced five Open Questions with explicit "review ask" notes for
136
+ the human reviewer (e.g. *"how does the adapter dispatch
137
+ external_call nodes — via the impl Python function or via an MCP
138
+ tool registry?"*).
139
+
140
+ After the agent finishes, a runtime adapter consumes the IR and emits
141
+ the target runtime's native code shape:
142
+
143
+ - The **Temporal** adapter emits `workflow.py` (the orchestration
144
+ class with `@workflow.defn` and signal handlers for the HITL gates)
145
+ and `activities.py` (one `@activity.defn` per node, lazy-importing
146
+ the extracted functions).
147
+ - The **Cloudflare Workflows** adapter emits a TypeScript
148
+ `WorkflowEntrypoint` class with `step.do(...)` for each unit of
149
+ work and `step.waitForEvent(...)` for each HITL gate, plus
150
+ `signatures/*.ts` (Zod schemas + Anthropic SDK calls) and the
151
+ supporting `wrangler.jsonc` / `package.json` / `tsconfig.json`. The
152
+ output is `wrangler deploy`-ready.
153
+
154
+ None of the emitted code references an MCP runtime, in either
155
+ language — the agent's crystallization step replaces tool calls with
156
+ deterministic implementations.
157
+
158
+ ---
159
+
160
+ ## Why this exists
161
+
162
+ Fuzzy AI skills work, but in production they're slow, expensive, and
163
+ non-deterministic:
164
+
165
+ - **Slow.** A 10-20 minute agent loop per run is fine for human-in-the-loop
166
+ use, but unacceptable as a background job.
167
+ - **Expensive.** Multi-agent loops use ~15× the tokens of a single chat,
168
+ per Anthropic's own measurements. Most of those tokens go to re-deriving
169
+ procedures the skill author already wrote down.
170
+ - **Non-deterministic.** A "MANDATORY" check enforced only by prose can be
171
+ silently skipped if prompt drift is bad or the trajectory gets long.
172
+ There's no way to regression-test a behavior the LLM has to remember.
173
+
174
+ The fix is to identify which parts of a skill are *actually* fuzzy and
175
+ which are deterministic procedures wearing fuzzy clothing. Then move
176
+ the deterministic parts into code, keep the LLM at the points where the
177
+ input is genuinely unbounded (parsing, classifying, drafting), and wrap
178
+ the whole thing in a durable execution engine with explicit HITL gates.
179
+
180
+ That graduation step is what `rote` automates.
181
+
182
+ ---
183
+
184
+ ## How it works
185
+
186
+ `rote` is a three-layer system. Each layer has one job and contracts on
187
+ a small interface:
188
+
189
+ ```
190
+ ┌────────────────────┐
191
+ │ SKILL.md + │ Source skill bundle (untouched)
192
+ │ references/ │
193
+ └─────────┬──────────┘
194
+
195
+ │ rote graduate
196
+
197
+ ┌────────────────────┐
198
+ │ graduator agent │ LLM agent runs the rote-graduate
199
+ │ (Claude / Codex / │ skill against the source bundle.
200
+ │ Anthropic SDK) │ Pluggable driver layer.
201
+ └─────────┬──────────┘
202
+
203
+ │ filesystem contract:
204
+ │ work_dir/pipeline.yaml + extracted/ + signatures/
205
+
206
+ ┌────────────────────┐
207
+ │ Pipeline IR │ Pydantic-validated DAG of typed
208
+ │ (pipeline.yaml) │ nodes. Five node kinds. Runtime-
209
+ │ │ agnostic.
210
+ └─────────┬──────────┘
211
+
212
+ │ rote.adapters.<runtime>
213
+
214
+ ┌────────────────────┐
215
+ │ emitted runtime │ Workflow + activities for the
216
+ │ code │ target durable execution engine.
217
+ └────────────────────┘
218
+ ```
219
+
220
+ The three layers are:
221
+
222
+ 1. **The graduator agent** (`skills/rote-graduate/`) — a regular
223
+ Anthropic Skill with a `SKILL.md` and four reference files
224
+ (`node-kinds.md`, `crystallization-heuristics.md`, `ir-schema.md`,
225
+ `llm-judge-extraction.md`). This is the *brain* of `rote`. It can
226
+ run inside any Skills-compatible surface; you don't need rote to
227
+ use it.
228
+ 2. **The IR** (`src/rote/ir.py`) — Pydantic models for the five node
229
+ kinds plus edges, retries, HITL gates, and pipeline metadata. The
230
+ IR is the source of truth; everything downstream is template
231
+ substitution from it.
232
+ 3. **Runtime adapters** (`src/rote/adapters/<runtime>.py`) — pluggable
233
+ modules that consume an IR and emit runnable code for a specific
234
+ durable execution engine.
235
+
236
+ The graduator's job ends when it has produced a valid `pipeline.yaml`
237
+ (plus extracted modules and signatures). It does not emit runtime code.
238
+ Code emission is *deterministic Python* in `rote.adapters` — never
239
+ agent-driven — so the same IR always produces byte-identical output.
240
+
241
+ ---
242
+
243
+ ## Quickstart
244
+
245
+ ### Install
246
+
247
+ `rote` is not on PyPI yet. Clone and install in editable mode:
248
+
249
+ ```sh
250
+ git clone https://github.com/trevhud/rote.git
251
+ cd rote
252
+ python3 -m venv .venv
253
+ source .venv/bin/activate
254
+ pip install -e ".[dev]"
255
+ ```
256
+
257
+ This installs `rote` plus everything you need to run the tests
258
+ (`temporalio`, `anthropic`, `pytest`, `pytest-asyncio`).
259
+
260
+ ### Run on the bundled example
261
+
262
+ The repository includes a real BDR outreach skill in
263
+ `examples/bdr-outreach/skill/`. Graduate it:
264
+
265
+ ```sh
266
+ rote graduate examples/bdr-outreach/skill \
267
+ --runtime temporal \
268
+ --out /tmp/bdr-graduated
269
+ ```
270
+
271
+ By default `rote` auto-detects an available agent driver in this
272
+ order: `claude` (Claude Code CLI) → `codex` (Codex CLI) → `api`
273
+ (Anthropic SDK with `ANTHROPIC_API_KEY`). Override with `--agent`:
274
+
275
+ ```sh
276
+ rote graduate examples/bdr-outreach/skill --agent api --out /tmp/bdr-graduated
277
+ ```
278
+
279
+ The output directory is structured as:
280
+
281
+ ```
282
+ /tmp/bdr-graduated/
283
+ ├── graduated/ # produced by the graduator agent
284
+ │ ├── pipeline.yaml # the IR
285
+ │ ├── extracted/*.py # deterministic functions
286
+ │ ├── signatures/*.py # typed LLM-judge signatures
287
+ │ ├── evals/*.jsonl # seed eval examples
288
+ │ └── graduation-report.md # human-readable summary
289
+ └── runtime/temporal/ # produced by the adapter
290
+ ├── workflow.py
291
+ ├── activities.py
292
+ └── __init__.py
293
+ ```
294
+
295
+ ### Render an IR without re-running the agent
296
+
297
+ If you already have a `pipeline.yaml` (hand-written or from a previous
298
+ graduation), `rote emit` runs just the adapter step:
299
+
300
+ ```sh
301
+ rote emit /path/to/pipeline.yaml --runtime temporal --out /tmp/emitted/
302
+ ```
303
+
304
+ This is the cheap inner loop while iterating on adapters or IR shapes.
305
+
306
+ ---
307
+
308
+ ## The five node kinds
309
+
310
+ Every step in a graduated pipeline is exactly one of five kinds. The
311
+ target runtime's adapter knows how to emit each one. Full classification
312
+ guidance lives in
313
+ [`skills/rote-graduate/references/node-kinds.md`](skills/rote-graduate/references/node-kinds.md).
314
+
315
+ | Kind | What it is | Where the LLM lives |
316
+ | --- | --- | --- |
317
+ | `pure_function` | Fixed logic, deterministic I/O | Not involved |
318
+ | `external_call` | Vendor API call with fixed semantics + retries | Not involved |
319
+ | `llm_judge` | Fuzzy classification against a rubric, typed I/O | Typed signature: DSPy/BAML in Python; Zod + vendor SDK in TypeScript. The IR carries a runtime-agnostic `signature_spec` (JSON Schema + prompt) so each adapter derives the right native shape. |
320
+ | `agent_loop` | Genuinely exploratory tool use | Bounded agent loop |
321
+ | `hitl_gate` | Explicit human approval, suspend until signal | Durable suspend/resume |
322
+
323
+ The guiding rule: **keep the LLM at points where the input is unbounded
324
+ or ambiguous, and codify everything else.** When a step could be
325
+ classified two ways, prefer the more deterministic kind.
326
+
327
+ ---
328
+
329
+ ## Driver matrix
330
+
331
+ `rote` ships three interchangeable graduator drivers. Pick whichever
332
+ matches your auth situation; the same `pipeline.yaml` comes out either
333
+ way.
334
+
335
+ | Driver | Backend | Auth | Install | Default model |
336
+ | --- | --- | --- | --- | --- |
337
+ | `claude` | `claude -p` subprocess | Claude Max/Pro OAuth or `CLAUDE_CODE_OAUTH_TOKEN` | Install Claude Code separately | `claude-sonnet-4-6` |
338
+ | `codex` | `codex exec` subprocess | ChatGPT Plus/Pro OAuth | Install Codex CLI separately | (driver default) |
339
+ | `api` | `anthropic` Python SDK | `ANTHROPIC_API_KEY` env var | `pip install 'rote-cli[api]'` | `claude-sonnet-4-6` |
340
+
341
+ The `claude` driver is the default for subscription users — it scrubs
342
+ `ANTHROPIC_API_KEY` from the subprocess environment so the user's
343
+ Claude Code login wins, sets
344
+ `CLAUDE_CODE_DISABLE_NONINTERACTIVE_ANIMATIONS=1` for clean output,
345
+ and limits the agent to read/write/glob/grep tools (no shell, no
346
+ network). See [`docs/agent-runtime.md`](docs/agent-runtime.md) for the
347
+ full design record including the auth gotcha that motivates the env
348
+ scrub.
349
+
350
+ The model defaults to **Sonnet 4.6** rather than Opus because the
351
+ graduator's task is structured-rubric-following, not deep reasoning.
352
+ Sonnet brings per-run cost from ~$3.50 to ~$0.70 in subscription
353
+ accounting, which makes iterative rubric tuning feasible. Override
354
+ with `rote graduate --model claude-opus-4-6` for complex skills where
355
+ Opus's extra reasoning earns its cost.
356
+
357
+ ---
358
+
359
+ ## Status
360
+
361
+ `rote` is **pre-1.0**. The end-to-end flow works on the BDR example
362
+ and the test suite covers each layer (133 tests in the fast suite,
363
+ plus 3 slow tests that compile the emitted Cloudflare TypeScript
364
+ against the real `@cloudflare/workers-types` definitions and drive a
365
+ real workflow instance through both HITL gates via `wrangler dev`).
366
+ Run `pytest tests/` for the fast suite; `pytest tests/ -m slow` for
367
+ the toolchain-dependent integration tests.
368
+
369
+ | Component | Status |
370
+ | --- | --- |
371
+ | IR (Pydantic schema, validation, YAML loader) | working |
372
+ | Temporal adapter | working (validated with mocked-activities e2e test) |
373
+ | Cloudflare Workflows adapter | working (validated with `tsc --noEmit` over the real emitted output) |
374
+ | DBOS adapter | working (validated against a real DBOS runtime over SQLite in the e2e test) |
375
+ | Graduator orchestrator | working |
376
+ | `rote graduate` / `rote emit` CLI commands | working |
377
+ | `claude` driver | working |
378
+ | `api` (Anthropic SDK) driver | working |
379
+ | `codex` driver | stub (`is_available` works; `run` not implemented) |
380
+ | Inngest / Restate adapters | planned |
381
+ | Real implementations of the extracted modules | the agent produces stubs that raise `NotImplementedError`; humans fill them in with real API client code |
382
+ | Workflow data flow between activities | working — nodes declare `inputs:` bindings and all three adapters (Temporal, Cloudflare, DBOS) thread real payloads through the DAG, validated in the runtime e2e tests |
383
+ | Distribution via PyPI | not yet published — install from source. The release pipeline (tag-driven, Trusted Publishing) is in place; see [docs/releasing.md](docs/releasing.md) |
384
+
385
+ The project explicitly **does not** depend on `claude-agent-sdk`.
386
+ Anthropic's terms of service forbid third-party agents built on the
387
+ Agent SDK from using claude.ai login credentials without prior
388
+ approval, which would defeat the subscription path. We use the bare
389
+ `anthropic` SDK or spawn `claude` directly instead.
390
+
391
+ ---
392
+
393
+ ## Repository layout
394
+
395
+ ```
396
+ rote/
397
+ ├── README.md
398
+ ├── LICENSE # Apache-2.0
399
+ ├── pyproject.toml # rote + optional [temporal] / [api] / [dev] extras
400
+ ├── docs/
401
+ │ └── agent-runtime.md # decision record for the driver layer
402
+ ├── skills/
403
+ │ └── rote-graduate/
404
+ │ ├── SKILL.md # the graduator agent's instructions
405
+ │ └── references/
406
+ │ ├── node-kinds.md # 5-kind classification rubric
407
+ │ ├── crystallization-heuristics.md # patterns for moving prose into code
408
+ │ ├── ir-schema.md # pipeline.yaml reference
409
+ │ └── llm-judge-extraction.md # how to design typed signatures
410
+ ├── src/rote/
411
+ │ ├── cli.py # rote graduate / rote emit
412
+ │ ├── ir.py # Pydantic IR models + load_pipeline
413
+ │ ├── graduator/
414
+ │ │ ├── __init__.py # Graduator orchestrator
415
+ │ │ └── drivers/
416
+ │ │ ├── __init__.py # Protocol + registry + auto_detect
417
+ │ │ ├── claude.py # ClaudeDriver (subprocess)
418
+ │ │ ├── codex.py # CodexDriver (stub)
419
+ │ │ └── anthropic_api.py # AnthropicApiDriver (in-process)
420
+ │ └── adapters/
421
+ │ ├── __init__.py # adapter registry
422
+ │ ├── temporal.py # TemporalAdapter (Python emitter)
423
+ │ └── cloudflare.py # CloudflareAdapter (TypeScript emitter)
424
+ ├── examples/
425
+ │ └── bdr-outreach/
426
+ │ ├── skill/ # the source skill (graduator input)
427
+ │ ├── expected/ # hand-drafted IR + stubs (regression baseline)
428
+ │ └── runs/ # snapshots of real graduator runs
429
+ └── tests/ # 136 passing tests across 11 files
430
+ ```
431
+
432
+ ---
433
+
434
+ ## How it differs from other tools
435
+
436
+ - **vs. raw Temporal / Cloudflare Workflows / Inngest / Restate:**
437
+ durable execution engines give you the workflow runtime; they don't
438
+ help you decide *what should be a workflow in the first place*.
439
+ `rote` is the missing step that converts a working skill into
440
+ something worth running on a durable engine.
441
+ - **vs. LangGraph:** LangGraph is an excellent state machine for
442
+ agent loops, but its graph is hand-built. `rote` produces a graph
443
+ from prose, classifies its nodes by determinism, and pushes work
444
+ out of the agent loop wherever the data supports it.
445
+ - **vs. just using Claude Code Skills directly:** Skills run great in
446
+ interactive use. `rote` is what you reach for when a skill becomes
447
+ business-critical and needs to run unattended in the background
448
+ with hard reliability guarantees and per-step regression tests.
449
+ - **vs. `claude-agent-sdk`:** see the *Status* section. The Agent SDK
450
+ is API-key-only for third-party tooling per Anthropic's ToS, which
451
+ defeats the subscription path that `rote`'s primary `claude`
452
+ driver enables.
453
+
454
+ ---
455
+
456
+ ## Documentation index
457
+
458
+ - [`docs/agent-runtime.md`](docs/agent-runtime.md) — design record for
459
+ the driver abstraction, including the `claude -p` env-var gotcha and
460
+ the explicit non-use of `claude-agent-sdk`
461
+ - [`docs/releasing.md`](docs/releasing.md) — how releases work
462
+ (tag-driven, PyPI Trusted Publishing) and the one-time setup
463
+ - [`skills/rote-graduate/SKILL.md`](skills/rote-graduate/SKILL.md) —
464
+ the graduator agent's procedural instructions (the "brain")
465
+ - [`skills/rote-graduate/references/node-kinds.md`](skills/rote-graduate/references/node-kinds.md) —
466
+ the 5-kind classification rubric with BDR examples
467
+ - [`skills/rote-graduate/references/crystallization-heuristics.md`](skills/rote-graduate/references/crystallization-heuristics.md) —
468
+ the seven patterns for moving prose into deterministic code
469
+ - [`skills/rote-graduate/references/ir-schema.md`](skills/rote-graduate/references/ir-schema.md) —
470
+ the `pipeline.yaml` reference (matches `src/rote/ir.py`)
471
+ - [`skills/rote-graduate/references/llm-judge-extraction.md`](skills/rote-graduate/references/llm-judge-extraction.md) —
472
+ how to turn a fuzzy rubric into a typed signature
473
+ - [`examples/bdr-outreach/`](examples/bdr-outreach/) — the canonical
474
+ source skill, the hand-drafted ground-truth IR, and snapshotted real
475
+ graduator runs
476
+
477
+ ---
478
+
479
+ ## Roadmap
480
+
481
+ In rough priority order:
482
+
483
+ 1. **`CodexDriver` implementation.** Same shape as `ClaudeDriver` but
484
+ spawning `codex exec`. Unlocks ChatGPT subscribers.
485
+ 2. **End-to-end re-graduation of BDR with `signature_spec`.** The
486
+ current bundled `pipeline.yaml` was hand-extended with structured
487
+ schemas for the Cloudflare adapter; the rubric in
488
+ `skills/rote-graduate/references/` was updated to teach the
489
+ graduator the new field, but no real graduator run has produced
490
+ one yet. Re-running `rote graduate examples/bdr-outreach/skill`
491
+ should produce the structured form natively.
492
+ 3. **A third runtime adapter.** Probably Inngest, since its
493
+ programming model is meaningfully different from both Temporal and
494
+ Cloudflare. Each new adapter is also a stress test on whether the
495
+ IR is genuinely runtime-agnostic vs. accidentally shaped like one
496
+ of the existing targets.
497
+ 4. **Pre-filter as `pure_function` node.** Today the rubric lifts
498
+ hard thresholds into a Python `forward()` method, which works for
499
+ Temporal but not for Cloudflare. Modeling the pre-filter as a
500
+ separate `pure_function` node before the `llm_judge` makes the
501
+ short-circuit work uniformly across runtimes.
502
+ 5. **Explicit data-flow threading.** *(Done.)* Nodes declare
503
+ `inputs:` — a parameter → source-reference mapping with a
504
+ deliberately tiny grammar (`pipeline.input[.field]` /
505
+ `<node_id>.output[.field]`) — and both adapters thread real
506
+ payloads through the DAG. Remaining follow-up: per-element
507
+ dispatch for `fan_out` nodes, which currently receive the whole
508
+ upstream list in one invocation.
509
+ 6. **More example skills.** BDR is rich but it's one shape of skill.
510
+ Additional examples (research-heavy, retrieval-heavy, code-review)
511
+ stress-test the IR and the rubric in different ways.
512
+ 7. **PyPI distribution.** Once the API is stable enough.
513
+ 8. **The graduator graduating itself.** The `rote-graduate` skill is
514
+ itself a SKILL.md. Pointing `rote graduate` at it should produce a
515
+ graduated meta-graduator where the rubric-grade pieces are
516
+ crystallized into Python and only the genuinely fuzzy judgments
517
+ stay in the agent loop.
518
+
519
+ ---
520
+
521
+ ## Contributing
522
+
523
+ The most useful contributions right now are:
524
+
525
+ - **Run `rote graduate` on a real skill of your own and report what
526
+ happens.** The rubric was designed against one skill (BDR); it
527
+ needs to be tested against more.
528
+ - **Add a runtime adapter.** The Temporal adapter in
529
+ `src/rote/adapters/temporal.py` is ~450 lines and follows a clear
530
+ pattern. Inngest, Restate, and Hatchet are all good targets.
531
+ - **Add a graduator driver.** The Protocol in
532
+ `src/rote/graduator/drivers/__init__.py` is simple. Aider, Gemini
533
+ CLI, and Cursor Agent are reasonable additions.
534
+ - **Improve the rubric.** Every change to a file under
535
+ `skills/rote-graduate/references/` is tracked in git, so improvements
536
+ can be A/B tested across runs.
537
+
538
+ The test suite (`pytest tests/`) covers each layer in isolation plus
539
+ the full pipeline against the BDR example. New work should land with
540
+ matching tests.
541
+
542
+ ---
543
+
544
+ ## License
545
+
546
+ Apache-2.0. See [LICENSE](LICENSE).
@@ -0,0 +1,27 @@
1
+ rote/__init__.py,sha256=fFcMhL873w7LrVsqUfVFPDH1qW6uBMpwQQhQnmLKIhc,93
2
+ rote/cli.py,sha256=yVK2EOegFuG-Nxj6kLSIuPz9y0AOturFzZz5liKSxvQ,17225
3
+ rote/ir.py,sha256=YogBEO_wZcv_MIReYzajcKdO_D9DAM1lImLGxuPvto8,18244
4
+ rote/adapters/__init__.py,sha256=ki-r4y2E-Fkb0Whjr52zxNHo8q_FTMSpLIvp7E175Ug,2092
5
+ rote/adapters/_common.py,sha256=MMJngaDhM5mdbnQiW9VgGdoykkWT9RdCOfKcCHPyJ38,5286
6
+ rote/adapters/cloudflare.py,sha256=wmAzbbFeLI96ZsEP1X7OnZpq4DcQnM5o1x4CElTMqBU,36212
7
+ rote/adapters/dbos.py,sha256=Q0pVseXDwwjPZodEuUKIVaKKzIALNJgi_pGc89jdAxs,48100
8
+ rote/adapters/temporal.py,sha256=9Evq9VVsQa5kF68FRppB3uvdYp39DhN0T1DbKDPpnYA,20913
9
+ rote/graduator/__init__.py,sha256=pIcuc-K83eGH-8TGYe6qOI2wawWtog0Fp-5BqadtIOQ,9015
10
+ rote/graduator/drivers/__init__.py,sha256=2Zt_cWI6VLXUXMja0phJllHc7MX8I5LrDdaK_nwUMJc,7359
11
+ rote/graduator/drivers/anthropic_api.py,sha256=mQ1O_u6Y0UZovG3iT5DQ-38RoqR8QRDfZ-FU-YquefY,15407
12
+ rote/graduator/drivers/claude.py,sha256=bMMR2obdx6OLCZGSEIIz5nXzoc3sN_BA3B8wR3nbuSw,12540
13
+ rote/graduator/drivers/codex.py,sha256=2pg5gQc4G8qY_D5DDxTtUL3809-Z7l9E1fzp8YbJL5U,2957
14
+ rote/serve/__init__.py,sha256=csLVvyGwT6KSNwTw6_Vzn-4XqiK3fLSW5CwQUPzg91g,668
15
+ rote/serve/backends.py,sha256=e1HYBxPnrQz8ZtdUM6SqgUJinrsmtTwlJzFXoxo5bXI,5945
16
+ rote/serve/registry.py,sha256=VWl2v5bBriaSWFHV-26_afiTXekbQqsogGbrliwy8vk,7263
17
+ rote/serve/server.py,sha256=_6iXyUOQwN0YXBgfuXXpNyarGmjhaVhDkrB_I8xWWgE,8930
18
+ rote/skills/rote-graduate/SKILL.md,sha256=RN_5O6JsnogSPeXghb7BhUYGawlhGx3u3Q9MeEIpOrU,10425
19
+ rote/skills/rote-graduate/references/crystallization-heuristics.md,sha256=V4RWcNLpTHOOras1ZdY13R-tX-JXyehPySGrRuUmVQ0,10702
20
+ rote/skills/rote-graduate/references/ir-schema.md,sha256=_xN7ZGygahmN6YWKySdloBP2dsnTeU5DOhbijWge2xM,15488
21
+ rote/skills/rote-graduate/references/llm-judge-extraction.md,sha256=LsrGCmbF3Qcms78sgyxzGftN-U9A3AzzmghVTl7Or1I,13664
22
+ rote/skills/rote-graduate/references/node-kinds.md,sha256=Eycm11yPqrKYm07GV8gIfReGnLHdbY7Wd-awjmnWm-k,9436
23
+ rote_cli-0.1.0.dist-info/METADATA,sha256=EmIZhv1XJxD0bjlH4PXPB-xLt1TLST9Q1KK0l_EaDUE,24804
24
+ rote_cli-0.1.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
25
+ rote_cli-0.1.0.dist-info/entry_points.txt,sha256=grzitu-eAYBcZ_3crz983KNZLgDYuNp_tG0mzsaSvXA,39
26
+ rote_cli-0.1.0.dist-info/licenses/LICENSE,sha256=YRsI6sP7T8GE1IOJs5VbMVTq4yUKo8A07w3Dmcm2UIM,11300
27
+ rote_cli-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.30.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ rote = rote.cli:main