rote-cli 0.5.0__tar.gz → 0.7.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.
- {rote_cli-0.5.0 → rote_cli-0.7.0}/.gitignore +4 -0
- rote_cli-0.7.0/PKG-INFO +422 -0
- rote_cli-0.7.0/README.md +376 -0
- {rote_cli-0.5.0 → rote_cli-0.7.0}/skills/rote-graduate/SKILL.md +10 -0
- rote_cli-0.7.0/skills/rote-graduate/references/eval-estimates.md +112 -0
- {rote_cli-0.5.0 → rote_cli-0.7.0}/skills/rote-graduate/references/ir-schema.md +11 -0
- {rote_cli-0.5.0 → rote_cli-0.7.0}/skills/rote-graduate/references/llm-judge-extraction.md +9 -0
- {rote_cli-0.5.0 → rote_cli-0.7.0}/src/rote/__init__.py +1 -1
- {rote_cli-0.5.0 → rote_cli-0.7.0}/src/rote/adapters/__init__.py +29 -15
- {rote_cli-0.5.0 → rote_cli-0.7.0}/src/rote/adapters/_common.py +170 -1
- {rote_cli-0.5.0 → rote_cli-0.7.0}/src/rote/adapters/_py_common.py +168 -11
- rote_cli-0.7.0/src/rote/adapters/_ts_common.py +702 -0
- {rote_cli-0.5.0 → rote_cli-0.7.0}/src/rote/adapters/cloudflare.py +94 -210
- {rote_cli-0.5.0 → rote_cli-0.7.0}/src/rote/adapters/dbos.py +157 -92
- {rote_cli-0.5.0 → rote_cli-0.7.0}/src/rote/adapters/dbos_ts.py +56 -212
- {rote_cli-0.5.0 → rote_cli-0.7.0}/src/rote/adapters/inngest.py +55 -206
- {rote_cli-0.5.0 → rote_cli-0.7.0}/src/rote/adapters/python.py +39 -63
- {rote_cli-0.5.0 → rote_cli-0.7.0}/src/rote/adapters/temporal.py +19 -72
- rote_cli-0.7.0/src/rote/cli.py +1328 -0
- rote_cli-0.7.0/src/rote/eval/__init__.py +46 -0
- rote_cli-0.7.0/src/rote/eval/empirical.py +634 -0
- rote_cli-0.7.0/src/rote/eval/estimate.py +433 -0
- rote_cli-0.7.0/src/rote/eval/pricing.py +457 -0
- rote_cli-0.7.0/src/rote/eval/priors.py +178 -0
- rote_cli-0.7.0/src/rote/eval/scorecard.py +357 -0
- rote_cli-0.7.0/src/rote/eval/sidecar.py +97 -0
- rote_cli-0.7.0/src/rote/eval/tokens.py +96 -0
- rote_cli-0.7.0/src/rote/graduator/__init__.py +442 -0
- {rote_cli-0.5.0 → rote_cli-0.7.0}/src/rote/graduator/drivers/__init__.py +10 -1
- {rote_cli-0.5.0 → rote_cli-0.7.0}/src/rote/graduator/drivers/anthropic_api.py +11 -11
- {rote_cli-0.5.0 → rote_cli-0.7.0}/src/rote/graduator/drivers/claude.py +29 -16
- rote_cli-0.7.0/src/rote/graduator/drivers/codex.py +285 -0
- rote_cli-0.7.0/src/rote/graduator/update.py +152 -0
- {rote_cli-0.5.0 → rote_cli-0.7.0}/src/rote/ir.py +170 -4
- rote_cli-0.7.0/src/rote/skill_source.py +135 -0
- rote_cli-0.5.0/PKG-INFO +0 -620
- rote_cli-0.5.0/README.md +0 -574
- rote_cli-0.5.0/src/rote/adapters/_ts_common.py +0 -338
- rote_cli-0.5.0/src/rote/cli.py +0 -616
- rote_cli-0.5.0/src/rote/graduator/__init__.py +0 -259
- rote_cli-0.5.0/src/rote/graduator/drivers/codex.py +0 -83
- {rote_cli-0.5.0 → rote_cli-0.7.0}/LICENSE +0 -0
- {rote_cli-0.5.0 → rote_cli-0.7.0}/pyproject.toml +0 -0
- {rote_cli-0.5.0 → rote_cli-0.7.0}/skills/rote-graduate/references/crystallization-heuristics.md +0 -0
- {rote_cli-0.5.0 → rote_cli-0.7.0}/skills/rote-graduate/references/node-kinds.md +0 -0
- {rote_cli-0.5.0 → rote_cli-0.7.0}/src/rote/serve/__init__.py +0 -0
- {rote_cli-0.5.0 → rote_cli-0.7.0}/src/rote/serve/backends.py +0 -0
- {rote_cli-0.5.0 → rote_cli-0.7.0}/src/rote/serve/registry.py +0 -0
- {rote_cli-0.5.0 → rote_cli-0.7.0}/src/rote/serve/server.py +0 -0
rote_cli-0.7.0/PKG-INFO
ADDED
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rote-cli
|
|
3
|
+
Version: 0.7.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
|
+
[](https://github.com/trevhud/rote/actions/workflows/ci.yml)
|
|
52
|
+
[](https://pypi.org/project/rote-cli/)
|
|
53
|
+
[](https://pypi.org/project/rote-cli/)
|
|
54
|
+
[](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. The
|
|
330
|
+
fast suite (`pytest tests/`) makes no real API calls and is what CI runs
|
|
331
|
+
on every push, alongside a Python e2e (DBOS over SQLite + the MCP server
|
|
332
|
+
over real stdio). Each adapter also has a `slow`-marked e2e that runs its
|
|
333
|
+
emitted code against the real runtime (Temporal's time-skipping server,
|
|
334
|
+
the TypeScript targets via `tsc --noEmit` and live dev servers, the
|
|
335
|
+
plain-Python subprocess); those need a Node toolchain / Docker, so they
|
|
336
|
+
run locally with `pytest tests/ -m slow`, not in CI.
|
|
337
|
+
|
|
338
|
+
Known gaps: the extracted modules are `NotImplementedError` stubs
|
|
339
|
+
you fill in with real API-client code, a Restate adapter is planned, and
|
|
340
|
+
`fan_out` nodes currently receive the whole upstream list in one
|
|
341
|
+
invocation (per-element dispatch is a planned enhancement). Published on
|
|
342
|
+
PyPI as [`rote-cli`](https://pypi.org/project/rote-cli/) via tag-driven
|
|
343
|
+
Trusted Publishing ([docs/releasing.md](docs/releasing.md)).
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## Repository layout
|
|
348
|
+
|
|
349
|
+
```
|
|
350
|
+
rote/
|
|
351
|
+
├── docs/ agent-runtime · mcp-trigger · releasing
|
|
352
|
+
├── skills/rote-graduate/ the graduator agent (SKILL.md + 4 reference files)
|
|
353
|
+
├── src/rote/
|
|
354
|
+
│ ├── cli.py rote graduate / emit / eval / serve
|
|
355
|
+
│ ├── ir.py Pydantic IR models + load_pipeline
|
|
356
|
+
│ ├── graduator/ orchestrator + drivers/ (claude · codex · anthropic_api)
|
|
357
|
+
│ └── adapters/ dbos · temporal · python · cloudflare · dbos_ts · inngest
|
|
358
|
+
│ (+ _common / _py_common / _ts_common emit helpers)
|
|
359
|
+
├── examples/
|
|
360
|
+
│ ├── bdr-outreach/ canonical: all 5 node kinds · IR baseline · run snapshots
|
|
361
|
+
│ ├── ops-report/ 100% roteness: zero LLM nodes + a HITL gate
|
|
362
|
+
│ └── deal-monitor/ data-heavy: parallel waves · fan-out judges · template render
|
|
363
|
+
└── tests/ fast + slow suites (pytest -m slow)
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## Documentation
|
|
369
|
+
|
|
370
|
+
- [`docs/agent-runtime.md`](docs/agent-runtime.md) — design record for the
|
|
371
|
+
driver abstraction (the `claude -p` env gotcha; the non-use of
|
|
372
|
+
`claude-agent-sdk`)
|
|
373
|
+
- [`docs/mcp-trigger.md`](docs/mcp-trigger.md) — `rote register` +
|
|
374
|
+
`rote serve`: graduated pipelines as MCP tools (FastMCP 3.x)
|
|
375
|
+
- [`docs/releasing.md`](docs/releasing.md) — tag-driven PyPI Trusted
|
|
376
|
+
Publishing
|
|
377
|
+
- [`skills/rote-graduate/`](skills/rote-graduate/) — the graduator's
|
|
378
|
+
`SKILL.md` and its four rubric files (node kinds, crystallization
|
|
379
|
+
heuristics, IR schema, LLM-judge extraction)
|
|
380
|
+
- [`examples/bdr-outreach/`](examples/bdr-outreach/) — the canonical
|
|
381
|
+
skill, its ground-truth IR, and snapshotted real graduator runs
|
|
382
|
+
- [`examples/ops-report/`](examples/ops-report/) — the 100%-roteness
|
|
383
|
+
archetype: every step deterministic, one durable HITL gate, zero LLM
|
|
384
|
+
nodes after graduation
|
|
385
|
+
- [`examples/deal-monitor/`](examples/deal-monitor/) — the data-heavy
|
|
386
|
+
archetype: parallel entry waves, fan-out judges, and a template render
|
|
387
|
+
replacing per-run LLM-generated HTML
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## Roadmap
|
|
392
|
+
|
|
393
|
+
In rough priority order:
|
|
394
|
+
|
|
395
|
+
1. **Re-graduate BDR end-to-end with `signature_spec`** — the bundled IR
|
|
396
|
+
was hand-extended with structured schemas; the rubric now teaches the
|
|
397
|
+
field, but no real run has produced one yet.
|
|
398
|
+
2. **Pre-filter as a `pure_function` node** — today hard thresholds are
|
|
399
|
+
lifted into a judge's `forward()`, which works for Temporal but not
|
|
400
|
+
Cloudflare; a separate node makes the short-circuit uniform.
|
|
401
|
+
3. **More example skills** — BDR is one shape; research-heavy,
|
|
402
|
+
retrieval-heavy, and code-review skills stress the IR differently.
|
|
403
|
+
4. **`fan_out` per-element dispatch** — currently the whole upstream list
|
|
404
|
+
arrives in one invocation.
|
|
405
|
+
5. **The graduator graduating itself** — `rote-graduate` is a SKILL.md;
|
|
406
|
+
pointing `rote graduate` at it should crystallize its rubric-grade
|
|
407
|
+
pieces and leave only the genuinely fuzzy judgments in the loop.
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## Contributing
|
|
412
|
+
|
|
413
|
+
The most useful contribution right now is to **run `rote graduate` on a
|
|
414
|
+
real skill of your own and report what happens** — the rubric was
|
|
415
|
+
designed against one skill and needs more. Adding a runtime adapter or a
|
|
416
|
+
graduator driver, or improving the rubric, are all good next steps. See
|
|
417
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) for dev setup, the test layout, and
|
|
418
|
+
the adapter/driver how-tos.
|
|
419
|
+
|
|
420
|
+
## License
|
|
421
|
+
|
|
422
|
+
Apache-2.0. See [LICENSE](LICENSE).
|