Skip to content

Releases: trevhud/rote

v0.12.1

Choose a tag to compare

@github-actions github-actions released this 30 Jul 14:36
51fcee3

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 and Typing :: Typed
    classifiers, an author email, and the py.typed marker added in
    0.12.0's README and discovery work (#72, #74). No code changes.

v0.12.0

Choose a tag to compare

@trevhud trevhud released this 30 Jul 04:18
541d0c8

Added

  • agent_loop is 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_body sub-nodes bound as
    callables (they are working steps, so the agent drives them per
    iteration exactly as the IR describes), and both handed to
    runAgentLoop in a verbatim signatures/_roteInference.ts. Three
    inference lanes and deliberately no claude-cli one: workerd cannot
    spawn a subprocess, and a lane that worked on two of three TypeScript
    runtimes would be a portability trap.
  • The workers-ai lane (Cloudflare only). An operator can run the
    loop on their own Cloudflare account with no external API key. The AI
    binding and its runWithTools runner are injected at the call site,
    which keeps _roteInference.ts free of any Cloudflare import — the
    Node runtimes compile it without @cloudflare/ai-utils on 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.
    tools names tools without a server, and required_mcp_servers
    derives from server names, so a pipeline whose only MCP usage was a
    loop reported zero required servers: analyze, emit, compile
    and the rote mcp login advisories 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.probe resolves those servers from evidence. cross_check
    gained resolved_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_pipeline writes the
    server back into tool_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 -p call
    sites passed a bare --tools, but the flag is variadic — Claude Code
    2.1.220 rejects it with option '--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, and run_agent_loop's CLI path had no coverage at all.
  • Python's --allowedTools stopped 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 an extracted/
    module, but _extracted_layout deliberately skips agent loops (the
    adapter inlines run_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 an agent_loop's tools:. 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 of Promise.all because waitForEvent inside 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

Choose a tag to compare

@trevhud trevhud released this 30 Jul 04:17
08858a5

Added

  • Park-on-auth for Cloudflare Workflows — every MCP-capable runtime
    now parks.
    MCP-backed step.do calls wrap auth failures in
    NonRetryableError (Workflows has no should-retry predicate; a dead
    credential must not burn retries.limit worth of delay) and park
    the instance on a rote_auth_<server> waitForEvent with 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
    , so rote mcp release <server> simply sends the
    event to every non-terminal instance via the Cloudflare REST API
    (CLOUDFLARE_API_TOKEN + CLOUDFLARE_ACCOUNT_ID; in wrangler dev, use npx wrangler workflows instances send-event … --local).
    The credential fix on Workers is re-provisioning (rote mcp export

    • wrangler secret bulk), not a local login — the ROTE_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/sdk streamable-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 a runParkable loop around MCP-backed steps: auth
    failures are wrapped in NonRetriableError inside 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 on step.waitForEvent for
    <pipeline>/rote.auth.<server>. Release needs no discovery: Inngest
    events fan out to every matching waiter, so rote mcp login /
    rote mcp release send one broadcast per registered pipeline
    (dev server by default, Inngest Cloud with INNGEST_EVENT_KEY,
    or ROTE_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 against inngest-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 throw RoteMcpAuthNeeded (typed error in the
    emitted _roteMcp.ts — thrown on dead tokens, failed refresh grants,
    and 401s the refresh can't fix), a shouldRetry predicate 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-serialized rote_auth_status event — the one format both
    DBOS SDKs read, which is what lets the existing Python release path
    serve TS apps unchanged (it now scans dbos-ts registry entries,
    derives the TS Postgres system-DB URL, and sends the release message
    in WorkflowSerializationFormat.PORTABLE). New rote 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 raises RoteMcpAuthNeeded and the workflow
    parks durably on a rote:auth:<server> topic, exempt from the retry
    budget and advertised via the rote_auth_status workflow 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 by rote emit/rote compile; ROTE_APPS_PATH overrides),
    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 graduate is now rote 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. graduate described 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 under seo/reports/verb-experiment.json.

    The rename runs through the whole surface: the command, the
    rote.compiler package (was rote.graduator), Compiler /
    CompilerError / CompilationEvent, the skills/rote-compile agent
    bundle, the /rote:compile plugin skill, the <out>/compiled/
    artifact directory (was <out>/graduated/), the emitted
    compile-report.md (was graduation-report.md), and all docs.

    rote graduate still works. It dispatches to rote compile and
    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 --json payload and progress
    sidecar now carry cloud.compilation_id instead 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 in src/rote/cloud_compile.py.

v0.10.0

Choose a tag to compare

@trevhud trevhud released this 30 Jul 04:18

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

Choose a tag to compare

@trevhud trevhud released this 30 Jul 04:18

Added

  • Live compilation progress — the compiler now emits structured
    CompilationEvents (rote.compiler.events): phase transitions
    (driven by progress.ndjson markers the compiler skill writes at
    the start of each phase), per-turn token counts, tool calls, and
    artifacts. rote compile renders them live on stderr; hosts embed
    the stream via Compiler(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_url and default_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() accepts extra_instructions, appended to the
    compiler skill prompt (e.g. pinning emitted judge calls to a
    specific runtime client).

  • The Cloudflare adapter emits manifest.json at 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_for is 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 completed rote mcp login into
    Worker secrets (dotenv form for .dev.vars, --json for
    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 a ROTE_MCP_TOKENS KV 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-types v5 + 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 emitted src/extracted/_roteMcp.ts helper 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 api keeps the direct-vendor-SDK
    stubs. Proven end-to-end across languages: Python rote 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 their mcp: bindings to endpoints, with
      pre-registered client_id/client_secret support 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-browser prints 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 emitted extracted/_rote_mcp.py helper (the
      verbatim source of rote.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 --run trials authenticate: the generated --mcp-config
      injects registry headers verbatim, or — for logged-in servers — a
      headersHelper invoking rote 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 a warning event. 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: null assistant 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.json pinned @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

Choose a tag to compare

@trevhud trevhud released this 30 Jul 04:18
de88e5b

Added

  • examples/invoice-push/ — the fourth committed example and the
    agent_loop archetype, 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.yaml sidecar — with per-row iterations, the calibration
    fixture for the loop-aware cost model below.

  • eval --run auto-wires the pipeline's MCP servers into the skill
    trial.
    The compiled pipeline's mcp: 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-server mcp__<server>__* allowlists;
    URLs resolve from the binding's explicit url, else
    ROTE_MCP_<SERVER>_URL — the adapters' rule). Verified live against
    a real claude -p run 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 from suggested_priors re-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 StepEstimate gains iterations: {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_tokens prior (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.

Fixed

  • rote compile now re-points eval.yaml's source_skill alongside
    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

Choose a tag to compare

@trevhud trevhud released this 30 Jul 04:18
bbe4577

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
    the python adapter'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.py guards every example's expected IR, including
    that its source_skill pointer 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's external_call footprint sizes the agent-side
    context payload (tokens_per_external_call_result, default 6k/call,
    with a per-MCP-tool override table payload_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 --run calibration 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_turn and output_tokens_per_turn.
  • CodexDriver is now implementedrote compile --agent codex
    spawns codex exec (OpenAI Codex CLI) as a compiler backend,
    completing the three-driver lineup. Runs headless under a
    workspace-write sandbox (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 stored codex login
    session is only overridden by CODEX_API_KEY/CODEX_ACCESS_TOKEN,
    not OPENAI_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 analyze is now implemented — the plan to compile's
    apply. Runs the compiler against a skill and prints a structural
    report (node-kind breakdown, roteness — matching rote eval — plus
    mandatory checks, HITL gates, agent loops, and which runtimes can
    target it) without emitting runtime code. --json for a
    machine-readable report; --out keeps the compiled IR for a later
    rote emit. Previously a stub that printed "not yet implemented".

Changed

  • source_skill no 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 as Node.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 codex driver no longer raises NotImplementedError when
    selected via --agent codex or 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_skill pointer the orchestrator fix addresses
    (../../skill resolved to a nonexistent examples/skill), so
    rote eval on the canonical example silently dropped its before-side
    baseline. Corrected to ../skill; now regression-guarded for every
    example.
  • rote compile/rote analyze --out now re-point the pipeline's
    source_skill to resolve from the emitted pipeline.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 later rote 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

Choose a tag to compare

@trevhud trevhud released this 30 Jul 04:18
0a1b045

Added

  • Workers AI signature client (signature_spec.client: "workers-ai"): the
    Cloudflare adapter emits env.AI.run(...) with schema-locked JSON output
    (response_format: json_schema) routed through an AI Gateway — no vendor
    SDK and no API key (the AI binding is the auth). Env / wrangler.jsonc /
    secrets are now client-aware: the AI binding 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. On SamplingSurface.roteness,
    Scorecard.to_dict(), and the markdown scorecard.
  • MCP-backed external_call nodes: an IR mcp: 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
    NotImplementedError stub — so the output runs out of the box. The DBOS
    adapter emits a working FastMCP client call by default
    (external_backend="mcp"); api falls back to the direct-SDK impl.
    Verified end-to-end against a live mock MCP server (tests/test_mcp_e2e.py).
  • rote emit/rote compile gained --backend mcp|api to choose that
    backend at emit time (adapter factories now accept forwarded options).
  • rote eval harness: an auto-emitted scorecard.md with a static
    before/after estimate of speed, cost, and determinism (live-fetched
    model prices, no hardcoded tables), plus rote eval --run for
    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 bare rote name 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

Choose a tag to compare

@trevhud trevhud released this 30 Jul 04:18
efdfce8

Added

  • Inngest adapter (inngest): emits a TypeScript Inngest app that
    mounts into an existing Node/Next.js service, with waitForEvent
    HITL gates.
  • Raw Python adapter (python): a maximum-legibility,
    orchestrator-free plain-script target; refuses hitl_gate pipelines
    at emit time.
  • DBOS trigger backend for rote serve, so the default runtime can be
    MCP-triggered.

v0.4.0

Choose a tag to compare

@trevhud trevhud released this 30 Jul 04:18
4275865

Added

  • DBOS TypeScript adapter (dbos-ts): a zero-infrastructure
    durable target for Node shops (shares _ts_common with Cloudflare).

Changed

  • DBOS is now the default runtime.

Security

  • Hardened the IR and every emitter against code injection from crafted
    pipeline.yaml input (charset-constrained id/signal/impl fields at
    the IR boundary; escaped prose at emission).