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.