Releases: trevhud/rote
Release list
v0.12.1
Changed
- Metadata-only release. PyPI now carries the rewritten project
description, the roteskills.com homepage and changelog URLs, the
richer keyword set,Development Status :: 4 - Beta, the
Environment :: Console, AI-topic andTyping :: Typed
classifiers, an author email, and thepy.typedmarker added in
0.12.0's README and discovery work (#72, #74). No code changes.
v0.12.0
Added
agent_loopis a real node kind on the TypeScript runtimes. It was
a stub on all three —throw new Error("requires an agent runtime — implement me"). A pipeline that hands its one genuinely agentic step
back to the user has not graduated that step, so Cloudflare, DBOS-TS
and Inngest now emit the loop: MCP tools bound through whichever MCP
helper that runtime already emits,loop_bodysub-nodes bound as
callables (they are working steps, so the agent drives them per
iteration exactly as the IR describes), and both handed to
runAgentLoopin a verbatimsignatures/_roteInference.ts. Three
inference lanes and deliberately noclaude-clione: workerd cannot
spawn a subprocess, and a lane that worked on two of three TypeScript
runtimes would be a portability trap.- The
workers-ailane (Cloudflare only). An operator can run the
loop on their own Cloudflare account with no external API key. TheAI
binding and itsrunWithToolsrunner are injected at the call site,
which keeps_roteInference.tsfree of any Cloudflare import — the
Node runtimes compile it without@cloudflare/ai-utilson their
dependency list. Offered, never forced: the binding costs nothing until
a run selects the lane. Node.tool_servers— an agent loop's tools now know their server.
toolsnames tools without a server, andrequired_mcp_servers
derives from server names, so a pipeline whose only MCP usage was a
loop reported zero required servers:analyze,emit,compile
and therote mcp loginadvisories all said there was nothing to
authenticate. BDR is exactly that shape, so the flagship example
demonstrated the bug; it reports five servers now. Additive — partial
maps are valid and an unmapped tool still resolves at run time, so no
existing pipeline changes meaning. A resolved tool also binds from its
own server and no other, because two servers exporting one tool name is
precisely what an allowlist cannot disambiguate.rote.proberesolves those servers from evidence.cross_check
gainedresolved_agent_tools: an observed tool that a loop declared
bare is the answer to the gap, not a missed requirement, so it no
longer reads as "the compiler missed this".enrich_pipelinewrites the
server back intotool_servers, leaving a tool served by two servers in
one trial unresolved rather than guessing. An authored value always
beats inference.
Fixed
- The subscription lane was dead on arrival. Both
claude -pcall
sites passed a bare--tools, but the flag is variadic — Claude Code
2.1.220 rejects it withoption '--tools <tools...>' argument missing,
exit 1, before running anything. That is every judge and every agent
loop on the lane that exists so a laptop run costs nothing extra.
--tools ""still loads no tools (167 input tokens on a one-line
prompt, so the low-overhead path is intact). Shipped in 0.11.0; no test
caught it because the assertion checked the flag's presence, not its
value, andrun_agent_loop's CLI path had no coverage at all. - Python's
--allowedToolsstopped being a cross product. It was
allowlisting every declared tool on every wired server — mostly phantom
pairs, and a real hazard when two servers export the same tool name. - Two DBOS e2e suites were spending real subscription inference to test
nothing. Their overlay mocked agent loops by writing anextracted/
module, but_extracted_layoutdeliberately skips agent loops (the
adapter inlinesrun_agent_loop), so that branch was unreachable and
BDR's two loops ran for real — about 35s of a 60s budget, orchestrating
nothing the tests asserted. Both now pass in under 9s.
Changed
- Invariant #3 now names both places the IR declares MCP: a node's
mcp:binding and anagent_loop'stools:. The Python runtimes have
behaved this way since 0.11.0, so this is the documentation catching up.
The MCP-free scan names its legitimate sites rather than skipping any
file that mentions MCP, so an unexpected reference still fails and an
expected site that stops referencing MCP fails too. - A Cloudflare agent loop is parkable, and therefore sequential. Its
tools are MCP tools, so it parks on auth like any bound step; parkable
steps stay out ofPromise.allbecausewaitForEventinside a promise
combinator is undocumented and its timeout throws, which would reject
every sibling. A real throughput cost on the slowest node kind, taken
so park-on-auth holds on the default runtime.
v0.11.0
Added
-
Park-on-auth for Cloudflare Workflows — every MCP-capable runtime
now parks. MCP-backedstep.docalls wrap auth failures in
NonRetryableError(Workflows has no should-retry predicate; a dead
credential must not burnretries.limitworth of delay) and park
the instance on arote_auth_<server>waitForEventwith an
explicit 30-day timeout — the default is 24 hours and expiry
throws, failing the instance, which after 30 unreleased days is
the intended outcome. Release has no broadcast on Workflows, but
events sent before an instance reaches its wait are buffered
per-instance, sorote mcp release <server>simply sends the
event to every non-terminal instance via the Cloudflare REST API
(CLOUDFLARE_API_TOKEN+CLOUDFLARE_ACCOUNT_ID; inwrangler dev, usenpx wrangler workflows instances send-event … --local).
The credential fix on Workers is re-provisioning (rote mcp exportwrangler secret bulk), not a local login — theROTE_MCP_TOKENS
KV cache supersedes secrets, so rotated tokens keep working. Proven
live on workerd (tests/test_mcp_park_cf_e2e.py): instance parks
with nothing provisioned, ignores a wrong-server event, wakes on the
real one, and completes — with the retried step driving the real
@modelcontextprotocol/sdkstreamable-HTTP client inside workerd
against a live MCP server, closing the long-standing "typecheck
only" gap for the Workers MCP output.
-
Park-on-auth for Inngest, released by broadcast. The Inngest
adapter emits arunParkableloop around MCP-backed steps: auth
failures are wrapped inNonRetriableErrorinside the step (so
Inngest's per-step retry budget and managed backoff never burn on a
missing credential), each attempt gets a fresh memoization-safe step
id, and the run parks onstep.waitForEventfor
<pipeline>/rote.auth.<server>. Release needs no discovery: Inngest
events fan out to every matching waiter, sorote mcp login/
rote mcp releasesend one broadcast per registered pipeline
(dev server by default, Inngest Cloud withINNGEST_EVENT_KEY,
orROTE_INNGEST_EVENT_URL). Because Inngest does not buffer events
for waits that haven't started, the park loop retries once before
waiting — a release landing in that gap fixes the credential store
the retry then reads. Proven live againstinngest-cli dev
(tests/test_mcp_park_inngest_e2e.py): run parks, a wrong-server
broadcast leaves it parked, the real broadcast wakes it, and it
completes with live MCP data. -
Park-on-auth for DBOS TypeScript, released from Python. The
dbos-ts adapter now emits the same park the Python adapter got:
MCP-backed steps throwRoteMcpAuthNeeded(typed error in the
emitted_roteMcp.ts— thrown on dead tokens, failed refresh grants,
and 401s the refresh can't fix), ashouldRetrypredicate keeps auth
failures out of the retry budget, and the workflow parks on
DBOS.recv("rote:auth:<server>")with the wait advertised via a
portably-serializedrote_auth_statusevent — the one format both
DBOS SDKs read, which is what lets the existing Python release path
serve TS apps unchanged (it now scansdbos-tsregistry entries,
derives the TS Postgres system-DB URL, and sends the release message
inWorkflowSerializationFormat.PORTABLE). Newrote mcp release <server>releases parked workflows without a login, for credentials
fixed out-of-band. The full cross-language loop — TS parks, Python
reads the event, Python releases, TS resumes against a live MCP
server — is proven on a real Docker Postgres in
tests/test_mcp_park_ts_e2e.py. Inngest and Cloudflare parks are
next. -
Park-on-auth: workflows suspend on missing MCP credentials instead
of failing (DBOS Python). OAuth is interactive; durable workflows
run unattended — so when an MCP-backed step finds its credential
missing or dead (expired with no refresh token, a 401 from the
server, or an OAuth flow demanding authorization — emitted code never
opens a browser), it raisesRoteMcpAuthNeededand the workflow
parks durably on arote:auth:<server>topic, exempt from the retry
budget and advertised via therote_auth_statusworkflow event.
rote mcp login <server>now finishes the loop: after a successful
dance it scans the new app registry (~/.local/share/rote/apps.json,
recorded byrote emit/rote compile;ROTE_APPS_PATHoverrides),
discovers workflows parked on that server, and releases them — the
run picks up exactly where it stopped, with the fresh credential.
Parallel-wave siblings retry once before parking so a stale auth
failure can't strand a workflow after its release signal was already
consumed. A workflow parked longer than 30 days times out loudly.
Proven cross-process on the real DBOS runtime against a live MCP
server (tests/test_mcp_park_e2e.py). The TS runtimes still fail
loud on dead credentials — extending the park is a known follow-up.
Changed
-
rote graduateis nowrote compile. The operation always was
compilation: read a source artifact, classify its parts, lower the
deterministic ones into typed code, keep a runtime for what genuinely
needs judgment.graduatedescribed what happened to the skill
socially rather than what the tool does mechanically, and nobody
reaching for this searches for it. Asked cold to name the operation,
both Claude and Codex produce "compile" unprompted; the experiment is
recorded in the rote-cloud repo underseo/reports/verb-experiment.json.The rename runs through the whole surface: the command, the
rote.compilerpackage (wasrote.graduator),Compiler/
CompilerError/CompilationEvent, theskills/rote-compileagent
bundle, the/rote:compileplugin skill, the<out>/compiled/
artifact directory (was<out>/graduated/), the emitted
compile-report.md(wasgraduation-report.md), and all docs.rote graduatestill works. It dispatches torote compileand
prints a one-line notice on stderr. It is deliberately absent from
--help: the alias exists so scripts written against 0.10.x keep
running, not to offer a second spelling.Breaking, without an alias: the
--jsonpayload and progress
sidecar now carrycloud.compilation_idinstead of
cloud.graduation_id, and artifacts land under<out>/compiled/.
Anything parsing that output needs a one-word edit.Not renamed: the rote cloud HTTP routes (
/v1/graduations) and
the server response keys (graduation_id,active_graduation). Those
name endpoints on a separately deployed platform; renaming them
client-side would 404 against every released server. See the module
docstring insrc/rote/cloud_compile.py.
v0.10.0
What's Changed
- Park-on-auth: MCP-backed workflows suspend on dead credentials; rote mcp login releases them by @trevhud in #34
- Park-on-auth for DBOS TypeScript, released from Python by @trevhud in #35
- Park-on-auth for Inngest, released by broadcast by @trevhud in #36
- Park-on-auth for Cloudflare Workflows — every MCP-capable runtime now parks by @trevhud in #37
- Launch-readiness: close injection blocker, doc fixes, agent DX by @trevhud in #38
- Live progress stream for graduate (agent transparency) + claude token fix by @trevhud in #39
- Add rote doctor preflight + extract MCP auth-status helper by @trevhud in #40
- Surface the MCP requirements manifest; fix keyword-property signature emission by @trevhud in #41
- Add
rote baseline: measured + observed pre-graduation skill runs by @trevhud in #42 - Baseline input derivation + graduate --baseline with measured scorecard section by @trevhud in #43
- Add rote.probe: schema inference from observed MCP traffic + cross-check by @trevhud in #44
- Node data contracts in the IR, populated from observed traffic by @trevhud in #45
- Grant the graduator web research tools on --backend api by @trevhud in #46
- First real agent-graduation runs for the three production-derived examples by @trevhud in #47
- Rubric fixes from the first real agent runs by @trevhud in #48
- Feed baseline probe artifacts into the graduator as ground truth by @trevhud in #49
- Add implementation.md: working-implementations rubric for extracted modules by @trevhud in #50
- Run agent-written tests after graduation; report, never fail by @trevhud in #51
- BDR re-graduation snapshot: canonical example now carries mcp bindings by @trevhud in #52
- Add
rote run: one-off local execution of a skill or an emitted pipeline by @trevhud in #53 - rote run: orchestrate the cloudflare runtime under wrangler dev by @trevhud in #54
- rote run: orchestrate the inngest runtime against a managed dev server by @trevhud in #55
- rote run: orchestrate the dbos-ts runtime (portable cross-language signals) by @trevhud in #56
- rote run: orchestrate the temporal runtime — all six runtimes runnable by @trevhud in #57
- Add
rote deploy: push-deploy wrappers + honest guidance per runtime by @trevhud in #58 - Add
rote deploy --target rote-cloud: bundle + authenticated upload by @trevhud in #59 - Add
rote login(OAuth device flow) + login-aware graduate default by @trevhud in #60 - Onboarding config (rote init/config) + cloud-side graduation default by @trevhud in #61
Full Changelog: v0.9.0...v0.10.0
v0.9.0
Added
-
Live compilation progress — the compiler now emits structured
CompilationEvents (rote.compiler.events): phase transitions
(driven byprogress.ndjsonmarkers the compiler skill writes at
the start of each phase), per-turn token counts, tool calls, and
artifacts.rote compilerenders them live on stderr; hosts embed
the stream viaCompiler(on_event=...). Works across the Claude
subprocess driver (stream-json) and both in-process API drivers. -
OpenAI-compatible API driver (
--agent openai-api) — the same
in-process compilation loop against any OpenAI-shaped endpoint
(GPT, GLM, Kimi, …), sharing one filesystem-tool surface with the
Anthropic driver. -
Gateway-friendly driver auth — both API drivers accept
base_urlanddefault_headers(through the new
Compiler(driver_kwargs=...)), so compilations can route through
proxies like Cloudflare AI Gateway with no provider key in the
environment. -
Compiler.compile()acceptsextra_instructions, appended to the
compiler skill prompt (e.g. pinning emitted judge calls to a
specific runtime client). -
The Cloudflare adapter emits
manifest.jsonat the runtime-dir
root — machine-readable pipeline identity (name, version, pipeline
hash, class name, node ids, entry) for deploy tooling; regex
fallback retained for older emits. -
rote.eval.build_scorecard_foris now public API (was a CLI
private). -
Cloudflare Workers call MCP tools, authenticated by provisioning
— Workers have no filesystem for the token store, so
rote mcp export <server>turns a completedrote mcp logininto
Worker secrets (dotenv form for.dev.vars,--jsonfor
npx wrangler secret bulk). MCP-bound nodes emit working calls
through a Workers helper that mints access tokens at runtime via the
OAuth refresh grant and caches them — with rotated refresh tokens —
in aROTE_MCP_TOKENSKV namespace declared in the emitted
wrangler.jsonc. The Env interface,.dev.vars.example, and
README document the per-server provisioning surface. Emitted output
typechecks against@cloudflare/workers-typesv5 + the MCP SDK. -
Node TypeScript runtimes call MCP tools, authenticated — the
DBOS-TS and Inngest adapters now emit working bodies for
mcp:-bound nodes (previously always throwing stubs): the module
calls the tool via the official@modelcontextprotocol/sdk(^1.29)
through an emittedsrc/extracted/_roteMcp.tshelper that reads the
same rote registry/token store the CLI writes, refreshes stale access
tokens with a refresh-token grant against the stored
token_endpoint, writes rotated refresh tokens back atomically, and
retries once on 401.--backend apikeeps the direct-vendor-SDK
stubs. Proven end-to-end across languages: Pythonrote mcp login
seeds the store, compiled TS authenticates, refreshes a forced-stale
token, and rotates credentials Python reads back
(tests/test_mcp_ts_e2e.py). -
A full MCP client with OAuth 2.1 (
rote mcp, design in
docs/mcp-client.md) — real streamable-HTTP MCP
servers authenticate with OAuth; without a client that can run the
flow, store tokens durably, and refresh them, MCP-backed workflows
only worked against unauthenticated servers:rote mcp add / list / remove— a user-level server registry
(~/.config/rote/mcp.json, 0600) mapping the logical server names
pipelines carry in theirmcp:bindings to endpoints, with
pre-registeredclient_id/client_secretsupport for servers
without dynamic client registration (Slack/GitHub-class) and static
headers for API-key schemes.rote mcp login— the full spec dance (protected-resource
discovery, PKCE, dynamic client registration, refresh) via
fastmcp's OAuth provider, persisting into a rote-owned token store
(one 0600 JSON file per server,~/.local/share/rote/mcp-tokens/)
whose layout is a documented cross-language contract.
--no-browserprints the authorization URL for SSH boxes.rote mcp headers— mints a currently-valid Authorization header
(auto-refreshing through the stored refresh token), the
machine-facing token API.- Emitted DBOS apps authenticate: MCP-backed steps now open the
client through an emittedextracted/_rote_mcp.pyhelper (the
verbatim source ofrote.mcp._runtime_helper— one tested
implementation) that resolves endpoints (env > registry > IR) and
credentials (OAuth store > static headers > none) at runtime, with
in-place token refresh. Emitted apps still never import rote. eval --runtrials authenticate: the generated--mcp-config
injects registry headers verbatim, or — for logged-in servers — a
headersHelperinvokingrote mcp headers, which Claude Code
re-runs per connection and on 401, so tokens refresh mid-run on
long trials.- Verified end-to-end against a real OAuth-protected server
(tests/test_mcp_oauth_e2e.py): live authorization dance with
dynamic registration, cross-process token reuse, an authenticated
tool call through the emitted helper, and a forced-stale refresh. - New optional extra:
pip install 'rote-cli[mcp]';python -m rote
now works (used by the headersHelper wiring).
Fixed
- The API drivers no longer misread per-turn output truncation
(stop_reason: max_tokens/finish_reason: length) as completion —
the per-turn cap is raised to 32k tokens and the loop continues
automatically with awarningevent. Surfaced by Claude 5 models,
which spend far more of the turn budget on thinking. - The Anthropic driver sets an explicit client timeout sized from the
per-turn token cap (the SDK otherwise refuses non-streaming requests
that may exceed 10 minutes at the new cap). - The Anthropic driver survives
content: nullassistant turns some
gateway endpoints return for all-thinking responses: content is
normalized, empty assistant turns are never replayed into history,
and an empty natural stop nudge-continues with a warning. - Emitted Cloudflare
package.jsonpinned@cloudflare/workers-types
^4, which current wrangler (4.110+) rejects with a peer-dependency
conflict on a fresh install — bumped to ^5.
v0.8.0
Added
-
examples/invoice-push/— the fourth committed example and the
agent_looparchetype, completing node-kind coverage across the
examples (adapted from a real production browser-automation skill,
fully fictionalized): a bounded per-row browser cycle (5-node
loop_body, termination cap) that cannot crystallize into code,
surrounded by 12 deterministic nodes. First example to commit its
eval.yamlsidecar — with per-rowiterations, the calibration
fixture for the loop-aware cost model below. -
eval --runauto-wires the pipeline's MCP servers into the skill
trial. The compiled pipeline'smcp:bindings name exactly the
servers the source skill uses, so the "before" measurement now runs
the agent over the same live tools (--mcp-config+
--strict-mcp-config, per-servermcp__<server>__*allowlists;
URLs resolve from the binding's expliciturl, else
ROTE_MCP_<SERVER>_URL— the adapters' rule). Verified live against
a realclaude -prun over a Streamable-HTTP MCP server. -
Reliability flags on measured skill runs. Each trial is checked
structurally (never by an LLM) before it may calibrate priors:
errored,hit_max_turns(truncated — its cost is a floor, not a
measurement),suspiciously_few_turns(fewer turns than the pipeline
has data pulls — the agent never did the work), and
missing_mcp_servers(the skill ran without its tools). Flagged runs
are excluded fromsuggested_priorsre-fits, listed in the measured
scorecard section, and recorded in the calibration corpus with their
flags. -
Loop-aware before-cost model, calibrated against a production
browser-automation skill whose two real runs measured 184 and 730
agent turns (~$8.6 and ~$32 on Sonnet) against a prior estimate of
$0.82–$2.75:- The eval sidecar's
StepEstimategainsiterations: {low, high}—
a step that repeats per row/page/item declares its per-iteration
turns and realistic repeat count, and the whole-run turn estimate
multiplies them. Loop-dominated skills were previously understated
5–20× because the schema could not express iteration at all (the
compiler's own notes described the loop economics correctly; the
form had nowhere to put the number). - New
transcript_cap_tokensprior (default 165k, the per-turn
cache-read plateau measured on both production runs): the transcript
an agent re-reads saturates at the harness's compaction ceiling
instead of growing without bound, so cached-read totals transition
from quadratic to linear on long runs. Without the cap, correcting
the turn count would have swung the error the other way (~2.5×
over). - The compiler rubric's calibration anchors are now regime-aware:
sequential tool-heavy skills anchor at 30–57 turns, per-item loop
skills at hundreds (the old universal 30–57 anchor actively pulled
loop-skill estimates down an order of magnitude).
Re-estimated with both fixes, the calibration skill's scorecard
brackets reality: $1.96–$22.68 estimated vs $8.59–$32.00 measured
(Sonnet), 98M estimated token ceiling vs 96M measured. - The eval sidecar's
Fixed
rote compilenow re-pointseval.yaml'ssource_skillalongside
pipeline.yaml's — the sidecar previously kept the agent's
temp-work-dir-relative path, a dead pointer in every kept compilation.
v0.7.0
Added
- Two production-shaped examples alongside BDR, each adapted from a
real production skill with all identifiers fictionalized:
examples/ops-report/(the 100%-roteness archetype — every step
deterministic, one durable HITL gate, zero LLM nodes; the fixture for
thepythonadapter's durable-execution refusal) and
examples/deal-monitor/(the data-heavy archetype — parallel entry
waves, fan-out judges, template render replacing LLM-generated HTML;
the calibration fixture for the payload-aware estimator).
tests/test_examples.pyguards every example's expected IR, including
that itssource_skillpointer resolves. - Payload-aware "before" cost estimator — the static scorecard now
models the data a skill pulls into context, not just its turn count.
The compiled pipeline'sexternal_callfootprint sizes the agent-side
context payload (tokens_per_external_call_result, default 6k/call,
with a per-MCP-tool override tablepayload_tokens_per_tool), folded
into C₀ of the cache-aware transcript model. Calibrated against a real
data-heavy production skill (Slack + Gmail dashboard, ~22 turns,
~1.6M cache-read tokens/run): the old flat prior underestimated the
before-cost 5–15×; the payload-aware default lands within ~3×, and one
eval --runcalibration brings it within ~10%. rote eval --run's suggested prior re-fits now include
transcript_growth_per_turn, inverted from measured cache-read tokens
under the quadratic transcript model — so every empirical run reports
the effective payload-inclusive growth rate alongside
seconds_per_turnandoutput_tokens_per_turn.CodexDriveris now implemented —rote compile --agent codex
spawnscodex exec(OpenAI Codex CLI) as a compiler backend,
completing the three-driver lineup. Runs headless under a
workspace-writesandbox (global reads so it can read the skill +
rubric in place, writes confined to the work dir, no network). The
environment is passed through untouched — a storedcodex login
session is only overridden byCODEX_API_KEY/CODEX_ACCESS_TOKEN,
notOPENAI_API_KEY, and there is no separate OpenAI-API driver, so
no auth is forced. Verified against the real CLI (codex-cli 0.142.4).rote analyzeis now implemented — theplantocompile's
apply. Runs the compiler against a skill and prints a structural
report (node-kind breakdown, roteness — matchingrote eval— plus
mandatory checks, HITL gates, agent loops, and which runtimes can
target it) without emitting runtime code.--jsonfor a
machine-readable report;--outkeeps the compiled IR for a later
rote emit. Previously a stub that printed "not yet implemented".
Changed
source_skillno longer participates in the pipeline hash — it's
provenance (a filesystem path the compiler re-points per output
location), and hashing it minted a new workflow type on every
re-compilation to a different directory, re-versioning in-flight
workflows whose behavior didn't change. Same rule asNode.source,
which was already excluded. One-time consequence: every pipeline's
hash (and therefore emitted workflow type name) changes once with this
release; in-flight workflows on the old type names continue on old
code as designed.
Fixed
- The
codexdriver no longer raisesNotImplementedErrorwhen
selected via--agent codexor chosen by auto-detect (a first-run
crash for users who had the Codex CLI but not Claude Code installed). - The BDR example's committed IR baseline carried the same dead
source_skillpointer the orchestrator fix addresses
(../../skillresolved to a nonexistentexamples/skill), so
rote evalon the canonical example silently dropped its before-side
baseline. Corrected to../skill; now regression-guarded for every
example. rote compile/rote analyze --outnow re-point the pipeline's
source_skillto resolve from the emittedpipeline.yaml's location
(relative when possible, absolute otherwise). The agent records the
path relative to its temp work dir — deleted when the run ends — so
every kept compilation carried a dead pointer and a laterrote eval
silently dropped the entire before-side baseline ("source_skill did
not resolve — emitting the after-side only"). Found by compiling a
real production skill.
v0.6.0
Added
- Workers AI signature client (
signature_spec.client: "workers-ai"): the
Cloudflare adapter emitsenv.AI.run(...)with schema-locked JSON output
(response_format: json_schema) routed through an AI Gateway — no vendor
SDK and no API key (theAIbinding is the auth).Env/wrangler.jsonc/
secrets are now client-aware: theAIbinding appears when a judge targets
workers-ai, and only the API keys actually used are emitted. - Roteness in the eval scorecard:
deterministic steps / total steps, a
purely structural code-vs-inference ratio (0% = agent loop, 100% = pure
code) that never depends on a model estimate — the honest counterweight to
the empirical determinism metric. OnSamplingSurface.roteness,
Scorecard.to_dict(), and the markdown scorecard. - MCP-backed
external_callnodes: an IRmcp:binding (server / tool /
args / url / transport) lets a compiled pipeline call the MCP tool
the source skill used, over Streamable HTTP, instead of emitting a
NotImplementedErrorstub — so the output runs out of the box. The DBOS
adapter emits a working FastMCP client call by default
(external_backend="mcp");apifalls back to the direct-SDKimpl.
Verified end-to-end against a live mock MCP server (tests/test_mcp_e2e.py). rote emit/rote compilegained--backend mcp|apito choose that
backend at emit time (adapter factories now accept forwarded options).rote evalharness: an auto-emittedscorecard.mdwith a static
before/after estimate of speed, cost, and determinism (live-fetched
model prices, no hardcoded tables), plusrote eval --runfor
empirical trials of both the source skill and the emitted pipeline.- Open-source project scaffolding: CI on every pull request and push
(Python 3.11–3.13 matrix + lint/type/sanity gates),SECURITY.md,
CODE_OF_CONDUCT.md, this changelog, issue/PR templates, Dependabot,
and a pre-commit config.
Fixed
- Corrected
pip install rote[...]→rote-cli[...]across the docs
(the barerotename is an unrelated PyPI package). - Refreshed stale version/adapter/test-count references in the README,
CONTRIBUTING.md, and the BDR example README.
v0.5.0
Added
- Inngest adapter (
inngest): emits a TypeScript Inngest app that
mounts into an existing Node/Next.js service, withwaitForEvent
HITL gates. - Raw Python adapter (
python): a maximum-legibility,
orchestrator-free plain-script target; refuseshitl_gatepipelines
at emit time. - DBOS trigger backend for
rote serve, so the default runtime can be
MCP-triggered.
v0.4.0
Added
- DBOS TypeScript adapter (
dbos-ts): a zero-infrastructure
durable target for Node shops (shares_ts_commonwith Cloudflare).
Changed
- DBOS is now the default runtime.
Security
- Hardened the IR and every emitter against code injection from crafted
pipeline.yamlinput (charset-constrained id/signal/impl fields at
the IR boundary; escaped prose at emission).