Repository navigation
v0.14.0
Added
-
rote compile --no-mcpskips live MCP discovery and calls for local
apiandopenai-apicompilation.rote analyzeaccepts the same
opt-out. Emitted MCP bindings and default discovery behavior stay
unchanged; cloud compilation, subprocess drivers, and--baseline
reject the flag with an actionable error. -
Invalid agent-authored pipelines are repaired, not failed one-shot.
When the driver's produced pipeline.yaml fails IR validation, the
Compiler resumes the same agent conversation with one user turn
carrying the verbatim pydantic errors and a change-only-what-the-
errors-name instruction, then re-validates — up to two repair attempts
(each surfaced as a warning event) before failing with the last error
exactly as before. Drivers that can resume their conversation take an
optionalrepaircallback (api and openai-api do); subprocess drivers
keep the one-shot behavior. Seen twice in real compiles:.tsmodule
refs inimpl:and dict-typed node input/output entries — both
trivially fixable by the model that wrote them. -
Heartbeat events while awaiting a model request. The api and
openai-api drivers emit alogevent every 120 seconds while an LLM
request is pending, so a hosted hang detector can tell a slow or
retrying request from a wedged job. -
The api and openai-api compiler drivers can call MCP tools live.
A new driver kwargmcp_servers(each entry{"name", "url", "headers"}, streamable HTTP only) lists each server's tools at agent
start and exposes them to the compiler agent asmcp__<server>__<tool>—
gated to tools whose server declaresreadOnlyHint, the same
predicaterote baselinealready applies, now shared in
rote.mcp.live_toolsso the two gates cannot drift. Every tool call
opens a fresh connection — long-lived streamable-HTTP sessions
combined with the vendor SDK deterministically froze the asyncio loop
under the hosted container runtime. Credentials are resolved once
before compilation and reused for every call. A server that cannot be
reached is a warning event, never a failed compile, and a tool failure
returns to the model as an error tool result. Whenrote compileruns one of
these drivers and no servers were passed, the local registry's
authenticated servers are wired in automatically (static headers
verbatim, logged-in servers via a freshly refreshed token;
unauthenticated servers are skipped with a printed reason). -
A wedged MCP server can no longer freeze a compile. The 180s bound
wrapped onlycall_tool, leaving the initialize handshake unbounded,
and since every call opens a fresh connection that handshake runs on
every call. Startup tool-listing had no bound at all. A server that
accepts the socket and never answers raises nothing, so the
"unavailable, continuing without it" path could not fire and the
compile hung with no warning. Both connects are now inside the bound. -
Binding-backed Workers MCP helper.
get_adapter("cloudflare").emit(pipeline, out_dir, mcp_client="binding")
(also available as a factory option,get_adapter("cloudflare", mcp_client="binding")) emits a_roteMcp.tsvariant with the same
exported surface as the direct helper, implemented over a
platform-provisionedROTE_MCPRPC service binding: no per-server
secrets, noROTE_MCP_TOKENSKV namespace, no OAuth refresh, and no
MCP SDK dependency. Every proxy call carries a signed caller-auth
object ({tenant_id, pipeline, run_id?, sig}) built from the
dispatcher-injectedROTE_TENANT_ID/ROTE_PIPELINE/ROTE_RUN_ID
/ROTE_MCP_SIGvariables, so tenant isolates cannot impersonate each
other; a missingROTE_MCP_SIGis a config error naming it. The
generated Env interface declares the oneROTE_MCPbinding plus those
four variables instead of the per-server secret surface. An error
whose message starts withROTE_MCP_AUTH_NEEDED:— the platform
proxy's contract — is rethrown asRoteMcpAuthNeeded, so the
park-on-auth loop, therote_auth_<server>event names, and agent
loops are unchanged. The default ("direct") emission is untouched. -
manifest.jsoncarries the pipeline's required MCP servers. A new
mcp_serverskey (server name → sorted bound node ids, from
Pipeline.required_mcp_servers) is always present in the Cloudflare
manifest —{}when the pipeline makes no MCP calls — so the cloud
runner can provision connections without re-deriving them from the IR.
Fixed
- The
dbosanddevextras now capdbos<3. DBOS 3.0 (2026-09-16)
madeQueue(...)construction raise in favor of
DBOS.register_queueand removed the admin server, so a fresh
pip install 'rote-cli[dbos]'resolved 3.x and every emitted DBOS
app died on import. The lock moves to 2.31.1, the newest 2.x. This is
a stopgap until the emitter targets DBOS 3. - Python runtime emission keeps input and output signature definitions in
separate namespaces. Schemas may reuse a$defsname with different
definitions; generated model names remain unique without changing the
output schema sent to the model. This fixes emission of the preserved
core-skill compilation on Python, DBOS, and Temporal. - Final compiler metrics now survive runtime-emission failures in
compiled/compile-metrics.json. The atomic sidecar contains allowlisted
numeric/identifier fields, preserves incomplete usage, labels cost as an
estimate, and excludes prompts, credentials, and driver error prose. - Claude compiler progress counts each response ID once, retaining every
tool event without multiplying cached input across content blocks.
Live output reads "pending" and live USD is omitted until final usage
arrives. Final token totals use the CLI's modelUsage/usage fields;
interrupted streams retain input/cache totals with output null and
usage_complete false. The CLI's total_cost_usd remains a cost estimate,
not a billing record. - CLI cloud uploads preserve required MCP servers.
rote deploy
now forwards the emitted manifest's server map, so the platform can
authorize the pipeline's MCP calls. Binding-mode run IDs are optional
attribution data; generated types and comments match the proxy's
tenant-and-pipeline signature contract. - Cloud uploads can bundle packages with a legacy entry point.
esbuild's neutral platform has no default package entry fields.
Explicitmodule,mainresolution lets generated agent loops bundle
@cloudflare/ai-utilswhile preserving Worker export conditions. - The readOnlyHint gate no longer trips fastmcp 4's deprecation
warning. MCP SDK v2 renamedToolAnnotations.readOnlyHintto
read_only_hint, and reading the camelCase alias fires
FastMCPDeprecationWarning (it surfaced as stderr noise in prod error
mail). The shared predicate now reads snake_case first and falls back
to camelCase, clean under both fastmcp 3.4 and 4.x. - Long compiler turns no longer die on silent connections. The api
and openai-api drivers stream every model request (messages.stream()
/stream=Truewith usage included) and assemble the final message
into the exact shape the loop already handled. A multi-minute
non-streaming generation sends no bytes until it finishes, so
intermediaries timed the connection out and the SDK's retries hit the
same wall — a real compile's pipeline-authoring turn sat 720 seconds
and failed with APIConnectionError; the 32k thinking-friendly turn cap
is what made single turns long enough to die. The client timeout now
bounds the gap between streamed chunks (httpx read-timeout semantics),
not the total generation, and the 120s heartbeat fires only when a
stream actually stalls. - Pinned
fastmcpbelow 4. The declaration wasfastmcp>=3.4.2with
no upper bound, so CI resolved tofastmcp4.0.2 (published
2026-09-02) andmcp2.x on every fresh install while local
environments stayed on 3.x. Five tests across three CI jobs began
failing on an unchangedmain: theserveclient stops receiving
tool-list-changed notifications, two OAuth e2e tests fail, and the TS
runtime e2e reportsMethod not found. The pin restores a trustworthy
signal; migrating to the 4.x / 2.x line is separate work, and MCP SDK
v2 also renamesTool.inputSchematoTool.input_schema. - A compilation's reported tokens and cost ignored prompt caching.
claude -palways runs prompt-cached, soinput_tokensholds only the
handful of tokens that were neither written to nor read from the cache.
The driver summed that field alone, and the CLI priced the result: a
22-minute, 62-turn compilation was reported astokens in=113 out=1919; cost $0.029. All four token buckets are now counted, and every display
adds cache writes and reads into the input figure it shows. - The agent runtime's own estimated cost was discarded. The driver read
result["cost_usd"], a key theclaude -presult envelope does not
have. The field istotal_cost_usd, so the read returnedNoneon
every run while the estimate sat one key away. It is now read and
preferred to rote's single-model estimate because it includes the
per-model usage split. Neither estimate is a billing record. - Cache rates are carried for every fetched model, not just the three
tier representatives. models.dev publishes them per model and the
parser already read them;build_catalogthen discarded all but the
representatives'. The compiler's own default model is not one, so a
default compilation had no priceable cache rate at all. New
PricingCatalog.rates_forspans the whole fetch; an on-disk cache
written before this still loads, degrading to "no published rate". - A run that still cannot be priced honestly reports no cost. When a
run touched the cache and its cache rates are genuinely unknown, the
cost field is omitted rather than filled with a figure that would
overstate cache reads roughly tenfold.
Changed
- The README roadmap dropped two items that had already shipped: real
compiler runs have producedsignature_specsince April, and the
ops-report, deal-monitor, and invoice-push archetypes have existed
alongside BDR for some time.