rote-cli 0.12.0__tar.gz → 0.13.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 (74) hide show
  1. {rote_cli-0.12.0 → rote_cli-0.13.0}/PKG-INFO +167 -81
  2. {rote_cli-0.12.0 → rote_cli-0.13.0}/README.md +156 -74
  3. {rote_cli-0.12.0 → rote_cli-0.13.0}/pyproject.toml +21 -6
  4. {rote_cli-0.12.0 → rote_cli-0.13.0}/skills/rote-compile/references/llm-judge-extraction.md +3 -3
  5. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/__init__.py +1 -1
  6. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/adapters/_common.py +76 -1
  7. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/adapters/_py_common.py +56 -42
  8. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/adapters/_ts_common.py +62 -0
  9. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/adapters/cloudflare.py +99 -6
  10. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/adapters/dbos.py +5 -1
  11. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/adapters/dbos_ts.py +46 -0
  12. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/adapters/inngest.py +72 -7
  13. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/adapters/python.py +48 -6
  14. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/adapters/temporal.py +87 -47
  15. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/cli.py +6 -0
  16. rote_cli-0.13.0/src/rote/py.typed +0 -0
  17. {rote_cli-0.12.0 → rote_cli-0.13.0}/.gitignore +0 -0
  18. {rote_cli-0.12.0 → rote_cli-0.13.0}/LICENSE +0 -0
  19. {rote_cli-0.12.0 → rote_cli-0.13.0}/skills/rote-compile/SKILL.md +0 -0
  20. {rote_cli-0.12.0 → rote_cli-0.13.0}/skills/rote-compile/references/crystallization-heuristics.md +0 -0
  21. {rote_cli-0.12.0 → rote_cli-0.13.0}/skills/rote-compile/references/eval-estimates.md +0 -0
  22. {rote_cli-0.12.0 → rote_cli-0.13.0}/skills/rote-compile/references/implementation.md +0 -0
  23. {rote_cli-0.12.0 → rote_cli-0.13.0}/skills/rote-compile/references/ir-schema.md +0 -0
  24. {rote_cli-0.12.0 → rote_cli-0.13.0}/skills/rote-compile/references/node-kinds.md +0 -0
  25. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/__main__.py +0 -0
  26. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/_dbos.py +0 -0
  27. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/adapters/__init__.py +0 -0
  28. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/app_registry.py +0 -0
  29. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/cloud_auth.py +0 -0
  30. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/cloud_compile.py +0 -0
  31. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/compiler/__init__.py +0 -0
  32. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/compiler/drivers/__init__.py +0 -0
  33. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/compiler/drivers/_fs_tools.py +0 -0
  34. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/compiler/drivers/anthropic_api.py +0 -0
  35. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/compiler/drivers/claude.py +0 -0
  36. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/compiler/drivers/codex.py +0 -0
  37. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/compiler/drivers/openai_api.py +0 -0
  38. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/compiler/events.py +0 -0
  39. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/compiler/update.py +0 -0
  40. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/config.py +0 -0
  41. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/contracts.py +0 -0
  42. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/deploy.py +0 -0
  43. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/deploy_rote_cloud.py +0 -0
  44. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/eval/__init__.py +0 -0
  45. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/eval/baseline.py +0 -0
  46. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/eval/empirical.py +0 -0
  47. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/eval/estimate.py +0 -0
  48. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/eval/pricing.py +0 -0
  49. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/eval/priors.py +0 -0
  50. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/eval/scorecard.py +0 -0
  51. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/eval/sidecar.py +0 -0
  52. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/eval/tokens.py +0 -0
  53. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/inference/__init__.py +0 -0
  54. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/inference/_runtime_helper.py +0 -0
  55. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/init_wizard.py +0 -0
  56. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/ir.py +0 -0
  57. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/mcp/__init__.py +0 -0
  58. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/mcp/_runtime_helper.py +0 -0
  59. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/mcp/auth.py +0 -0
  60. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/mcp/registry.py +0 -0
  61. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/mcp/release.py +0 -0
  62. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/mcp/tokens.py +0 -0
  63. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/probe.py +0 -0
  64. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/runners/__init__.py +0 -0
  65. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/runners/_node.py +0 -0
  66. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/runners/cloudflare.py +0 -0
  67. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/runners/dbos_ts.py +0 -0
  68. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/runners/inngest.py +0 -0
  69. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/runners/temporal.py +0 -0
  70. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/serve/__init__.py +0 -0
  71. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/serve/backends.py +0 -0
  72. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/serve/registry.py +0 -0
  73. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/serve/server.py +0 -0
  74. {rote_cli-0.12.0 → rote_cli-0.13.0}/src/rote/skill_source.py +0 -0
@@ -1,24 +1,28 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rote-cli
3
- Version: 0.12.0
4
- Summary: Compile fuzzy AI skills into deterministic, reliable workflows
5
- Project-URL: Homepage, https://github.com/trevhud/rote
3
+ Version: 0.13.0
4
+ Summary: Compile AI agent skills into cheap, fast, deterministic pipelines that run without an LLM in the loop
5
+ Project-URL: Homepage, https://roteskills.com
6
6
  Project-URL: Repository, https://github.com/trevhud/rote
7
- Project-URL: Issues, https://github.com/trevhud/rote/issues
8
7
  Project-URL: Documentation, https://github.com/trevhud/rote#readme
9
- Author: Trevor Hudson
8
+ Project-URL: Changelog, https://github.com/trevhud/rote/blob/main/CHANGELOG.md
9
+ Project-URL: Issues, https://github.com/trevhud/rote/issues
10
+ Author-email: Trevor Hudson <trevhud@gmail.com>
10
11
  License-Expression: Apache-2.0
11
12
  License-File: LICENSE
12
- Keywords: agent,agent-skills,ai,anthropic,claude,cloudflare,compilation,compiler,deterministic,dspy,durable-execution,llm,mcp,skill,temporal,workflow
13
- Classifier: Development Status :: 3 - Alpha
13
+ Keywords: agent,agent-skills,agent-workflow,ai,anthropic,claude,claude-code,claude-skills,cloudflare,compilation,compiler,dbos,deterministic,dspy,durable-execution,inngest,llm,mcp,pipeline,skill,temporal,token-cost,workflow
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Environment :: Console
14
16
  Classifier: Intended Audience :: Developers
15
17
  Classifier: Operating System :: OS Independent
16
18
  Classifier: Programming Language :: Python :: 3
17
19
  Classifier: Programming Language :: Python :: 3.11
18
20
  Classifier: Programming Language :: Python :: 3.12
19
21
  Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
23
  Classifier: Topic :: Software Development :: Code Generators
21
24
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
+ Classifier: Typing :: Typed
22
26
  Requires-Python: >=3.11
23
27
  Requires-Dist: pydantic>=2.7
24
28
  Requires-Dist: pyyaml>=6.0
@@ -52,21 +56,24 @@ Description-Content-Type: text/markdown
52
56
 
53
57
  # rote
54
58
 
55
- **Compile fuzzy AI skills into deterministic, reliable workflows.**
59
+ **Compile AI agent skills into cheap, fast, deterministic pipelines that
60
+ run without an LLM in the loop.**
56
61
 
57
62
  [![CI](https://github.com/trevhud/rote/actions/workflows/ci.yml/badge.svg)](https://github.com/trevhud/rote/actions/workflows/ci.yml)
58
63
  [![PyPI](https://img.shields.io/pypi/v/rote-cli.svg)](https://pypi.org/project/rote-cli/)
64
+ [![Downloads](https://img.shields.io/pypi/dm/rote-cli.svg)](https://pypi.org/project/rote-cli/)
59
65
  [![Python versions](https://img.shields.io/pypi/pyversions/rote-cli.svg)](https://pypi.org/project/rote-cli/)
60
66
  [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
61
67
 
62
- `rote` is a CLI that takes an Anthropic-style Skill (a `SKILL.md` plus
63
- `references/`) and turns it into a runnable background pipeline in one
64
- shot. An LLM agent (itself defined as a skill) reads the source skill,
65
- applies a structured compilation rubric, and emits a runtime-agnostic
66
- intermediate representation (`pipeline.yaml`), extracted Python modules
67
- for the deterministic parts, typed signature stubs for the LLM-judge
68
- parts, and runnable code for the durable execution engine of your
69
- choice.
68
+ **Your Claude skill works. Running it a thousand times does not.**
69
+
70
+ `rote` is an open source CLI that compiles a proven Claude skill or
71
+ agent skill (a `SKILL.md` plus `references/`) into a typed,
72
+ deterministic pipeline. It moves the fixed logic and tool orchestration
73
+ into reviewable code, and calls a model only for the steps that
74
+ genuinely need judgment. A 10 to 20 minute agent loop becomes a
75
+ background workflow that costs a fraction of the tokens and can be
76
+ regression tested.
70
77
 
71
78
  ```sh
72
79
  pip install rote-cli # or zero-install: uvx --from rote-cli rote ...
@@ -74,9 +81,9 @@ pip install rote-cli # or zero-install: uvx --from rote-cli rote ...
74
81
  # `rote compile` runs an LLM agent, so it needs a driver: Claude Code
75
82
  # (`claude`) or Codex (`codex`) installed and authed, or ANTHROPIC_API_KEY
76
83
  # for the in-process `api` driver. The BDR run below takes ~13 min and
77
- # ~$0.70 with Sonnet. (`rote emit` needs no LLM — see below.)
84
+ # ~$0.70 with Sonnet. (`rote emit` needs no LLM; see below.)
78
85
 
79
- # Default target is DBOS — durable execution as a plain Python library,
86
+ # Default target is DBOS: durable execution as a plain Python library,
80
87
  # no orchestrator to run, SQLite for dev / Postgres for prod:
81
88
  rote compile ./examples/bdr-outreach/skill --out ./compiled/
82
89
 
@@ -85,22 +92,24 @@ rote compile ./examples/bdr-outreach/skill --runtime temporal --out ./compiled
85
92
  rote compile ./examples/bdr-outreach/skill --runtime cloudflare --out ./compiled/
86
93
  ```
87
94
 
88
- The name comes from *rote learning* — doing something so many times, so
95
+ The name comes from *rote learning*: doing something so many times, so
89
96
  reliably, that it becomes mechanical. That's what compilation does to a
90
- skill: a fuzzy 10–20 minute agent loop becomes a deterministic pipeline
91
- that runs in the background, costs a fraction of the tokens, and can be
92
- regression-tested.
97
+ skill.
93
98
 
94
99
  ---
95
100
 
96
101
  ## Why
97
102
 
98
- Fuzzy AI skills work, but in production they're slow (a 10–20 minute
99
- agent loop is unacceptable as a background job), expensive (multi-agent
100
- loops use ~15× the tokens of a single chat, mostly re-deriving
101
- procedures the author already wrote down), and non-deterministic (a
102
- "MANDATORY" check enforced only by prose can be silently skipped, and
103
- there's no way to regression-test a behavior the LLM has to remember).
103
+ Agent skills work, but repeating them in production is expensive, slow,
104
+ and non-deterministic. Token cost is what bites first: every run
105
+ re-reads the skill text, the tool schemas, and a growing transcript to
106
+ re-derive a procedure the author already wrote down. The two production
107
+ skills adapted into `examples/` averaged ~0.9M and ~1.6M cache-read
108
+ tokens *per run* before compilation, for work that is mostly arithmetic
109
+ and fixed API calls. Latency is next (a 10 to 20 minute agent loop is
110
+ unacceptable as a background job), then determinism: a "MANDATORY"
111
+ check enforced only by prose can be silently skipped, and there's no
112
+ way to regression-test a behavior the LLM has to remember.
104
113
 
105
114
  The fix is to separate the parts of a skill that are *actually* fuzzy
106
115
  from the deterministic procedures wearing fuzzy clothing. Move the
@@ -109,24 +118,33 @@ genuinely unbounded (parsing, classifying, drafting), and wrap the whole
109
118
  thing in a durable execution engine with explicit human-in-the-loop
110
119
  gates. That compilation step is what `rote` automates.
111
120
 
121
+ | | Run the skill as an agent, every time | Compile it with `rote` |
122
+ | --- | --- | --- |
123
+ | Tokens per run | Full agent loop | Only the judgment steps |
124
+ | Latency | 10 to 20 minutes | Background, seconds to minutes |
125
+ | Reproducibility | Prose `MANDATORY` can be silently skipped | Deterministic nodes always run |
126
+ | Testing | No per-step regression tests | Typed nodes, per-step tests, eval seeds |
127
+ | Failure recovery | Restart the loop | Durable retries and resume |
128
+ | Human approval | Ad hoc | Explicit HITL gates that suspend and resume |
129
+
112
130
  There's third-party data for what this buys. ["Compiled AI: Deterministic
113
131
  Code Generation for LLM-Based Workflow Automation"](https://arxiv.org/abs/2604.05150)
114
132
  (Trooskens et al., Apr 2026) measured compiling LLM workflows into
115
133
  deterministic code: **57× fewer tokens** at 1,000 transactions, **450×
116
134
  lower** median latency, **100% reproducibility** (vs. 95% for direct
117
135
  inference at temperature 0), and ~**40× lower TCO** at a million
118
- transactions a month. The multiples grow with volume — once a workflow
136
+ transactions a month. The multiples grow with volume. Once a workflow
119
137
  is proven, every run through an agent loop pays LLM prices for work code
120
138
  does for free.
121
139
 
122
140
  A distinction worth being precise about: durable-execution vendors make
123
141
  fuzzy agents *durable* (wrap the loop in retries and state so it survives
124
- crashes — still fuzzy inside). `rote` *removes* the fuzzy loop. The two
142
+ crashes, still fuzzy inside). `rote` *removes* the fuzzy loop. The two
125
143
  compose: Temporal, Cloudflare Workflows, and the rest are `rote`'s
126
144
  compile targets, not its rivals.
127
145
 
128
146
  **When not to use `rote`:** exploratory and one-off work should stay an
129
- agent loop — flexibility is the whole point there, and there's nothing
147
+ agent loop. Flexibility is the whole point there, and there's nothing
130
148
  proven to compile yet. `rote` is for the skill you've run twenty times
131
149
  and want to run a thousand more, unattended.
132
150
 
@@ -134,6 +152,13 @@ and want to run a thousand more, unattended.
134
152
 
135
153
  ## How it works
136
154
 
155
+ One `rote compile` run does the whole thing. An LLM agent (itself
156
+ defined as a skill) reads the source skill, applies a structured
157
+ compilation rubric, and emits a runtime-agnostic intermediate
158
+ representation (`pipeline.yaml`), extracted Python modules for the
159
+ deterministic parts, typed signature stubs for the LLM-judge parts, and
160
+ runnable code for the durable execution engine of your choice.
161
+
137
162
  `rote` is a three-layer system; each layer has one job and contracts on
138
163
  a small interface.
139
164
 
@@ -154,18 +179,18 @@ a small interface.
154
179
  execution engine.
155
180
  ```
156
181
 
157
- 1. **The compiler agent** (`skills/rote-compile/`) — a regular
182
+ 1. **The compiler agent** (`skills/rote-compile/`): a regular
158
183
  Anthropic Skill (`SKILL.md` + four reference files). This is the
159
184
  *brain*; it runs inside any Skills-compatible surface, and you don't
160
185
  need `rote` to use it.
161
- 2. **The IR** (`src/rote/ir.py`) — Pydantic models for the five node
186
+ 2. **The IR** (`src/rote/ir.py`): Pydantic models for the five node
162
187
  kinds plus edges, retries, HITL gates, and metadata. The IR is the
163
188
  source of truth; everything downstream is template substitution.
164
- 3. **Runtime adapters** (`src/rote/adapters/`) — pluggable modules that
189
+ 3. **Runtime adapters** (`src/rote/adapters/`): pluggable modules that
165
190
  consume an IR and emit runnable code for one engine.
166
191
 
167
192
  The compiler's job ends when it has produced a valid `pipeline.yaml`.
168
- Code emission is *deterministic Python* — never agent-driven — so the
193
+ Code emission is *deterministic Python*, never agent-driven, so the
169
194
  same IR always produces byte-identical output.
170
195
 
171
196
  ---
@@ -195,10 +220,18 @@ Prefer a terminal? The same thing is one `uvx` command:
195
220
  uvx --from rote-cli rote compile ./my-skill --runtime dbos --out ./compiled
196
221
  ```
197
222
 
223
+ **Hosted platform:** [roteskills.com](https://roteskills.com) is the
224
+ project site (concepts, benchmarks methodology, worked examples).
225
+ [app.roteskills.com](https://app.roteskills.com) is Rote Cloud, a
226
+ managed path for teams that would rather not operate a runtime: run
227
+ `rote login` and `rote compile` then runs server-side, streams progress
228
+ back, auto-deploys, and downloads the artifacts locally. Everything in
229
+ this README still works logged out.
230
+
198
231
  > **Naming note:** the `rote` package on PyPI is an unrelated
199
232
  > memoization library that also installs `import rote`, so the two can't
200
233
  > share an environment. This project's distribution is `rote-cli` while
201
- > the CLI command and import name stay `rote` — hence
234
+ > the CLI command and import name stay `rote`, hence
202
235
  > `uvx --from rote-cli rote ...`. See [docs/releasing.md](docs/releasing.md).
203
236
 
204
237
  ### Run on the bundled example
@@ -213,8 +246,8 @@ rote compile examples/bdr-outreach/skill --out /tmp/bdr-compiled
213
246
 
214
247
  On that skill the compiler produces a 22-node IR that's **78.9%
215
248
  codifiable** (15 of 19 non-gate nodes), extracts 5 Python modules and 2
216
- typed judge signatures, and flags 4 mandatory nodes and 3 HITL gates —
217
- in ~13 minutes for ~$0.70 (Sonnet via Claude Code). Along the way it
249
+ typed judge signatures, and flags 4 mandatory nodes and 3 HITL gates,
250
+ all in ~13 minutes for ~$0.70 (Sonnet via Claude Code). Along the way it
218
251
  independently lifts the three MANDATORY exclusion checks out of prose,
219
252
  pulls four batch-size constants out of prompt text, and models a
220
253
  parallel entry path the hand-written baseline missed.
@@ -227,21 +260,22 @@ emitted code + a README on how to run, signal gates, and deploy).
227
260
 
228
261
  ### Other commands
229
262
 
230
- - **`rote emit <pipeline.yaml> --out <dir>`** — run just the adapter step
231
- on an existing IR (no LLM, no cost). The cheap inner loop while iterating on
232
- adapters or IR shapes. Re-emitting is safe: a `.rote-manifest.json`
263
+ - **`rote emit <pipeline.yaml> --out <dir>`**: run just the adapter step
264
+ on an existing IR. LLM-free, so no cost and no driver needed, which
265
+ makes it the cheap inner loop while iterating on adapters or IR
266
+ shapes. Re-emitting is safe: a `.rote-manifest.json`
233
267
  tracks what `rote` wrote, and files you've edited are left untouched
234
268
  (the fresh version lands as `<name>.new`).
235
- - **`rote compile --update`** — re-compile incrementally when the skill
269
+ - **`rote compile --update`**: re-compile incrementally when the skill
236
270
  changes. `rote` diffs the skill against the previous run's
237
271
  `provenance.json` and re-derives only the nodes whose source sections
238
272
  changed; unchanged nodes keep their ids (so in-flight durable workflows
239
273
  aren't orphaned) and implemented stubs are kept. No change → no agent run.
240
- - **`rote run <path>`** — one-off local execution of either side. A
274
+ - **`rote run <path>`**: one-off local execution of either side. A
241
275
  skill directory runs as an agent via `claude -p` (your registered MCP
242
276
  servers injected, read-only tool gate unless `--allow-writes`); an
243
- emitted runtime directory — or a `compile --out` directory — runs
244
- the pipeline itself — all six runtimes (`python`/`dbos`/`temporal`
277
+ emitted runtime directory, or a `compile --out` directory, runs
278
+ the pipeline itself on any of the six runtimes (`python`/`dbos`/`temporal`
245
279
  in-process or on a managed local dev server, `cloudflare` under
246
280
  `wrangler dev`, `inngest` against a managed `inngest-cli dev`,
247
281
  `dbos-ts` against your Postgres or a throwaway Docker one). HITL
@@ -250,18 +284,18 @@ emitted code + a README on how to run, signal gates, and deploy).
250
284
  Temporal Web UI URL and inngest runs print the dev-server dashboard,
251
285
  both live for the duration of the run. Output JSON on stdout, status
252
286
  on stderr, so it pipes.
253
- - **`rote deploy <path>`** — push an emitted pipeline where it runs:
287
+ - **`rote deploy <path>`**: push an emitted pipeline where it runs:
254
288
  `cloudflare` wraps `npx wrangler deploy` (with `--dry-run`), `dbos` /
255
- `dbos-ts` wrap `npx dbos-cloud app deploy` — the vendor CLI owns auth
289
+ `dbos-ts` wrap `npx dbos-cloud app deploy`, and the vendor CLI owns auth
256
290
  and output; rote adds detection and preflights (including surfacing
257
291
  *which* account your wrangler session belongs to before uploading).
258
292
  Runtimes with no push model (temporal, inngest, python) print honest
259
293
  hosting guidance with doc links instead of a fake action.
260
294
  `--target rote-cloud` bundles a cloudflare-emitted app (esbuild via
261
- npx) and uploads it to a hosted rote-cloud instance — with a stored
262
- `rote login`, no flags or env vars needed (`--url`/`--token` and
295
+ npx) and uploads it to a hosted rote-cloud instance. With a stored
296
+ `rote login`, no flags or env vars are needed (`--url`/`--token` and
263
297
  `$ROTE_CLOUD_URL`/`$ROTE_CLOUD_TOKEN` still override).
264
- - **`rote login`** — connect the CLI to a rote-cloud account via the
298
+ - **`rote login`**: connect the CLI to a rote-cloud account via the
265
299
  OAuth device flow: your browser opens with a one-time code pre-filled
266
300
  (over SSH, `--device` prints the code + URL instead), you click
267
301
  Approve, and the CLI stores a tenant API key at
@@ -278,27 +312,27 @@ emitted code + a README on how to run, signal gates, and deploy).
278
312
  even where config says otherwise. Logged out, everything works
279
313
  locally exactly as before. `rote whoami` shows the account (verified
280
314
  live); `rote logout` revokes the key server-side and clears the store.
281
- - **`rote init`** — one-time interactive onboarding: pick where
282
- compiled pipelines run (rote cloud — with login offered inline — or
315
+ - **`rote init`**: one-time interactive onboarding: pick where
316
+ compiled pipelines run (rote cloud, with login offered inline, or
283
317
  a local runtime, with a one-line pitch for each), which compiler
284
318
  driver does the work (availability probed live), and optionally a
285
319
  model. Answers are saved to `~/.config/rote/config.yaml`
286
320
  (`--project` writes a `./rote.yaml` that overrides it per-repo) and
287
321
  every later command reads them. It's the only interactive command
288
- besides login — CI never hits a prompt.
289
- - **`rote config`** — print every configurable default with its
322
+ besides login; CI never hits a prompt.
323
+ - **`rote config`**: print every configurable default with its
290
324
  effective value *and the layer that set it*. Resolution everywhere is
291
325
  `flag > ROTE_* env (ROTE_RUNTIME, ROTE_DEPLOY, ROTE_AGENT,
292
326
  ROTE_MODEL) > project rote.yaml > user config > built-in`. Config
293
327
  files are strict: a typo'd key or value is a loud error, never a
294
328
  silent fallback. `--json` for automation.
295
- - **`rote eval <compiled>`** — render the before/after scorecard (wall
329
+ - **`rote eval <compiled>`**: render the before/after scorecard (wall
296
330
  clock, cost across the current model lineup at live prices, and how
297
331
  much of the run is still LLM-decided). `rote compile` writes this to
298
332
  `compiled/scorecard.md` automatically. Add `--run` to *measure*
299
333
  instead of estimate: it executes both sides for real and appends
300
334
  measured cost, turns, and output agreement across trials.
301
- - **Per-node inference** — emitted judges read `ROTE_MODEL_<ID>` and
335
+ - **Per-node inference**: emitted judges read `ROTE_MODEL_<ID>` and
302
336
  `ROTE_BASE_URL_<ID>` at runtime, so you can swap the model or point at
303
337
  any OpenAI-compatible endpoint (Ollama, vLLM, a gateway) without
304
338
  re-emitting.
@@ -328,7 +362,7 @@ way, prefer the more deterministic kind.
328
362
  ## Runtimes
329
363
 
330
364
  Pick with `--runtime`; the same IR drives all of them. Under
331
- `--backend api`, none of the emitted code references MCP — the
365
+ `--backend api`, none of the emitted code references MCP: the
332
366
  crystallization step replaces tool calls with direct vendor API calls.
333
367
  Under the default `--backend mcp`, tool-using nodes emit a working MCP
334
368
  client call (with durable park-on-auth on every MCP-capable runtime);
@@ -336,7 +370,7 @@ see [`docs/mcp-client.md`](docs/mcp-client.md).
336
370
 
337
371
  | Runtime | `--runtime` | Language | Shape | Notes |
338
372
  | --- | --- | --- | --- | --- |
339
- | **DBOS** (default) | `dbos` | Python | `main.py` — `@DBOS.workflow` + `@DBOS.step` per node | No orchestrator to deploy; SQLite (dev) / Postgres (prod) |
373
+ | **DBOS** (default) | `dbos` | Python | `main.py` with `@DBOS.workflow` + `@DBOS.step` per node | No orchestrator to deploy; SQLite (dev) / Postgres (prod) |
340
374
  | Temporal | `temporal` | Python | `workflow.py` + `activities.py` | Signal handlers for HITL gates |
341
375
  | Plain Python | `python` | Python | single `main.py` script | Max legibility, stdlib only; refuses HITL-gate pipelines |
342
376
  | Cloudflare Workflows | `cloudflare` | TypeScript | `WorkflowEntrypoint` + `wrangler.jsonc` | `wrangler deploy`-ready |
@@ -347,7 +381,7 @@ see [`docs/mcp-client.md`](docs/mcp-client.md).
347
381
 
348
382
  ## Drivers
349
383
 
350
- `rote` ships three interchangeable compiler drivers — pick whichever
384
+ `rote` ships three interchangeable compiler drivers. Pick whichever
351
385
  matches your auth. The same `pipeline.yaml` comes out either way.
352
386
 
353
387
  | Driver | Backend | Auth | Install |
@@ -358,8 +392,8 @@ matches your auth. The same `pipeline.yaml` comes out either way.
358
392
 
359
393
  The `claude` driver scrubs `ANTHROPIC_API_KEY` from the subprocess so a
360
394
  subscription login wins, and limits the agent to read/write/glob/grep
361
- tools. The default model is **Sonnet** rather than Opus — the task is
362
- structured-rubric-following, not deep reasoning, and Sonnet brings
395
+ tools. The default model is **Sonnet** rather than Opus, because the
396
+ task is structured-rubric-following, not deep reasoning; Sonnet brings
363
397
  per-run cost from ~$3.50 to ~$0.70. Override with `--model` for skills
364
398
  where Opus earns its cost. Full design record, including the auth gotcha:
365
399
  [docs/agent-runtime.md](docs/agent-runtime.md).
@@ -400,12 +434,19 @@ plain-Python subprocess); those need a Node toolchain / Docker, so they
400
434
  run locally with `pytest tests/ -m slow`, not in CI.
401
435
 
402
436
  Known gaps: the extracted modules are `NotImplementedError` stubs
403
- you fill in with real API-client code, a Restate adapter is planned, and
404
- `fan_out` nodes currently receive the whole upstream list in one
405
- invocation (per-element dispatch is a planned enhancement). Published on
437
+ you fill in with real API-client code, and a Restate adapter is planned.
438
+ Published on
406
439
  PyPI as [`rote-cli`](https://pypi.org/project/rote-cli/) via tag-driven
407
440
  Trusted Publishing ([docs/releasing.md](docs/releasing.md)).
408
441
 
442
+ On the numbers: static scorecard estimates, observed production-agent
443
+ baselines, and independent research are three different kinds of
444
+ evidence, and mixing them produces marketing rather than benchmarks.
445
+ They're kept separate, with the assumptions written out, at
446
+ [roteskills.com/benchmarks](https://roteskills.com/benchmarks). To
447
+ measure your own workflow instead of reading someone else's, use
448
+ `rote eval --run`.
449
+
409
450
  ---
410
451
 
411
452
  ## Repository layout
@@ -423,7 +464,8 @@ rote/
423
464
  ├── examples/
424
465
  │ ├── bdr-outreach/ canonical: all 5 node kinds · IR baseline · run snapshots
425
466
  │ ├── ops-report/ 100% roteness: zero LLM nodes + a HITL gate
426
- │ └── deal-monitor/ data-heavy: parallel waves · fan-out judges · template render
467
+ │ ├── deal-monitor/ data-heavy: parallel waves · fan-out judges · template render
468
+ │ └── invoice-push/ agent-loop archetype: bounded browser loop · turn-dominated cost
427
469
  └── tests/ fast + slow suites (pytest -m slow)
428
470
  ```
429
471
 
@@ -431,30 +473,34 @@ rote/
431
473
 
432
474
  ## Documentation
433
475
 
434
- - [`AGENTS.md`](AGENTS.md) — operating manual for a coding agent *driving*
476
+ - [`AGENTS.md`](AGENTS.md): operating manual for a coding agent *driving*
435
477
  `rote` as an installed tool (invocation contract, the slow/costs-money
436
478
  `compile` flow, auth, failure recovery, the stub-filling job, `--json`)
437
- - [`docs/agent-runtime.md`](docs/agent-runtime.md) — design record for the
479
+ - [`docs/agent-runtime.md`](docs/agent-runtime.md): design record for the
438
480
  driver abstraction (the `claude -p` env gotcha; the non-use of
439
481
  `claude-agent-sdk`)
440
- - [`docs/mcp-client.md`](docs/mcp-client.md) — the OAuth MCP client
482
+ - [`docs/mcp-client.md`](docs/mcp-client.md): the OAuth MCP client
441
483
  emitted code uses under `--backend mcp`: endpoint/credential
442
484
  resolution and durable park-on-auth across every MCP-capable runtime
443
- - [`docs/mcp-trigger.md`](docs/mcp-trigger.md) — `rote register` +
485
+ - [`docs/mcp-trigger.md`](docs/mcp-trigger.md): `rote register` +
444
486
  `rote serve`: compiled pipelines as MCP tools (FastMCP 3.x)
445
- - [`docs/releasing.md`](docs/releasing.md) — tag-driven PyPI Trusted
487
+ - [`docs/releasing.md`](docs/releasing.md): tag-driven PyPI Trusted
446
488
  Publishing
447
- - [`skills/rote-compile/`](skills/rote-compile/) — the compiler's
489
+ - [`skills/rote-compile/`](skills/rote-compile/): the compiler's
448
490
  `SKILL.md` and its four rubric files (node kinds, crystallization
449
491
  heuristics, IR schema, LLM-judge extraction)
450
- - [`examples/bdr-outreach/`](examples/bdr-outreach/) — the canonical
492
+ - [`examples/bdr-outreach/`](examples/bdr-outreach/): the canonical
451
493
  skill, its ground-truth IR, and snapshotted real compiler runs
452
- - [`examples/ops-report/`](examples/ops-report/) — the 100%-roteness
494
+ - [`examples/ops-report/`](examples/ops-report/): the 100%-roteness
453
495
  archetype: every step deterministic, one durable HITL gate, zero LLM
454
496
  nodes after compilation
455
- - [`examples/deal-monitor/`](examples/deal-monitor/) — the data-heavy
497
+ - [`examples/deal-monitor/`](examples/deal-monitor/): the data-heavy
456
498
  archetype: parallel entry waves, fan-out judges, and a template render
457
499
  replacing per-run LLM-generated HTML
500
+ - [`examples/invoice-push/`](examples/invoice-push/): the `agent_loop`
501
+ archetype: a bounded browser-automation loop stays one agent node
502
+ while the date math, filtering, and reporting around it compile to
503
+ code, plus the measured runs that forced the loop-aware cost model
458
504
 
459
505
  ---
460
506
 
@@ -462,26 +508,66 @@ rote/
462
508
 
463
509
  In rough priority order:
464
510
 
465
- 1. **Re-compile BDR end-to-end with `signature_spec`** — the bundled IR
511
+ 1. **Re-compile BDR end-to-end with `signature_spec`**: the bundled IR
466
512
  was hand-extended with structured schemas; the rubric now teaches the
467
513
  field, but no real run has produced one yet.
468
- 2. **Pre-filter as a `pure_function` node** — today hard thresholds are
514
+ 2. **Pre-filter as a `pure_function` node**: today hard thresholds are
469
515
  lifted into a judge's `forward()`, which works for Temporal but not
470
516
  Cloudflare; a separate node makes the short-circuit uniform.
471
- 3. **More example skills** — BDR is one shape; research-heavy,
517
+ 3. **More example skills**: BDR is one shape; research-heavy,
472
518
  retrieval-heavy, and code-review skills stress the IR differently.
473
- 4. **`fan_out` per-element dispatch** — currently the whole upstream list
474
- arrives in one invocation.
475
- 5. **The compiler compiling itself** — `rote-compile` is a SKILL.md;
519
+ 4. **The compiler compiling itself**: `rote-compile` is a SKILL.md;
476
520
  pointing `rote compile` at it should crystallize its rubric-grade
477
521
  pieces and leave only the genuinely fuzzy judgments in the loop.
478
522
 
479
523
  ---
480
524
 
525
+ ## FAQ
526
+
527
+ ### What is rote?
528
+
529
+ `rote` is an open source CLI, Apache-2.0 licensed and published as
530
+ [`rote-cli`](https://pypi.org/project/rote-cli/) on PyPI, that compiles
531
+ a proven AI agent skill into a typed, deterministic pipeline. It reads
532
+ an Anthropic-style `SKILL.md`, classifies each step, moves fixed logic
533
+ and tool orchestration into reviewable code, and calls a model only for
534
+ the steps that genuinely require judgment.
535
+
536
+ ### How does rote reduce AI agent token costs?
537
+
538
+ It removes model calls rather than making them cheaper. A repeating
539
+ agent spends tokens re-reading instructions, tool schemas, and history
540
+ to re-derive a procedure it already established. `rote` compiles that
541
+ procedure into code, so a repeated run pays only for the steps still
542
+ classified as needing judgment.
543
+
544
+ ### When should I compile a skill instead of leaving it as an agent?
545
+
546
+ Keep one-off exploration in an agent, which is what agents are good at.
547
+ Compile a skill once the procedure is proven, repeats often, and needs
548
+ lower cost, faster execution, regression tests, explicit approvals, or
549
+ reliable retries.
550
+
551
+ ### Does rote replace my agent framework or MCP?
552
+
553
+ No. A compiled workflow can still call authenticated MCP servers and
554
+ retain bounded agent loops. `rote` decides which parts of a process
555
+ should stop being inference; your runtime and your integrations stay
556
+ where they are.
557
+
558
+ ### Where does the compiled workflow run?
559
+
560
+ Anywhere you already run durable work. `rote` emits DBOS, Temporal,
561
+ Cloudflare Workflows, plain Python, DBOS TypeScript, and Inngest.
562
+ [Rote Cloud](https://app.roteskills.com) is an optional managed path for
563
+ teams that would rather not operate the runtime themselves.
564
+
565
+ ---
566
+
481
567
  ## Contributing
482
568
 
483
569
  The most useful contribution right now is to **run `rote compile` on a
484
- real skill of your own and report what happens** — the rubric was
570
+ real skill of your own and report what happens**. The rubric was
485
571
  designed against one skill and needs more. Adding a runtime adapter or a
486
572
  compiler driver, or improving the rubric, are all good next steps. See
487
573
  [CONTRIBUTING.md](CONTRIBUTING.md) for dev setup, the test layout, and