Skip to content
All releases
CHANGELOG

v0.3.0-beta.6

The bundled dev-cycle Loop now does one job clearly: implement authored task files in dependency order. software-delivery is gone and implement-tasks takes its place, with a five-node graph — sluginput → loadtasks →…

BETAFeatures · 3Bug Fixes · 6Testing · 1

🎉 Features

  • Replace software-delivery with implement-tasks (#325)
  • BREAKING: remove software-delivery; use implement-tasks without gate inputs.
  • Parent and child sessions (#327)

🐛 Bug Fixes

  • Preserve Loop template manifests across hydration (#317)
  • Preserve ACP stream disconnect recovery (#319)
  • Discover Cursor model catalog before sessions (#320)
  • Keep managed skill loading on native seam (#323)
  • Loop run bugs (#324)
  • Enforce bundled agent and Loop ownership (#326)

🧪 Testing

  • Guard ACP initialize protocol version (#318)

Release Notes

Breaking Changes

implement-tasks replaces the software-delivery Loop

The bundled dev-cycle Loop now does one job clearly: implement authored task files in dependency order. software-delivery is gone and implement-tasks takes its place, with a five-node graph — slug_input → load_tasks → implement → execute_task → collect — and only three inputs. The old second control layer for review, command verification, and human approval is removed from the bundled Loop; task-level validation, self-review, tracking updates, and optional per-task commits stay inside the implementation agent's own prompt. (#325)

  • Inputs are now slug, implementer, and auto_commit. The review, verify, and approve nodes and their edges are deleted, along with the verification contract, stale hash fields, and target-branch handling.
  • The separate bundled review-and-fix Loop is unchanged, and custom Loops can still declare their own command gates — verify_command remains part of the generic Loop DSL.
  • The catalog, Loop overview, configuration examples, migration guide, web routes, and the official Compozy skill all name implement-tasks.

Migration notes: this is a hard cut with no alias. Any config, CLI or API call, automation binding, or documentation link that says software-delivery must say implement-tasks, and the target_branch and verify_command inputs must be dropped from [loops.inputs.*].

# before
[loops.inputs.software-delivery]
target_branch = "main"
verify_command = "make gate"
auto_commit = false

# after
[loops.inputs.implement-tasks]
auto_commit = false

Features

Cursor models come from your account

Cursor used to look curated in Compozy but was not truthful to the account that was signed in: a small hand-written list stood in for the real catalog and, worse, acted as an allowlist that rejected valid model ids before Cursor ever saw them. Compozy now reads the account catalog from cursor-agent models before a session exists, and exact provider model ids are forwarded unchanged. (#320)

  • The first catalog read bootstraps Cursor discovery once and persists the outcome; later reads serve the cache, and explicit refresh is the refresh boundary. In the QA account this surfaced 193 real models, including composer-2.5.
  • Only id - display name rows are parsed. Headings, tips, duplicates, and empty output can never become invented models.
  • Curated data is metadata again, not membership policy. Sessions and Loops accept ids like cursor/composer-2.5, and an unknown provider still fails with a structured unknown_provider error.
  • providers.<id>.models.discovery applies live — no daemon restart. A provider outage records the failure and keeps the rows you already have; disabling discovery clears them and records disabled.
  • In the web runtime selector, "Use an exact custom model ID…" now opens a dedicated field: empty input cannot be committed, typing turns the action into Use "<id>", Enter and click both commit, and closing returns to normal catalog search.
  • Cursor keeps the operator HOME its native_cli login contract expects.

Migration notes: the curated Cursor allowlist and its session preflight are deleted with no compatibility bridge. If a provider rejects an id, that provider's error is now the authority.

Fixes

A crashed agent no longer looks like a finished one

When an agent process disconnected mid-answer, the stream simply ended — and everything downstream read that silence as success. A CLI consumer reached end of file and exited zero, compozy__session_prompt returned a result, and the only evidence left behind was stderr with no exit code. Streams are now fail-closed: success requires an explicit completion event, and disconnect, terminal error, and process exit stay three distinct outcomes. (#315, #319)

  • Chunks already received stay persisted and visible. Compozy never synthesizes a completion for them.
  • A stream that ends after partial output without a completion event fails the CLI with a clear non-zero exit, and terminal error frames are forwarded before the error is returned so machine-readable diagnostics survive.
  • compozy__session_prompt classifies a subprocess exit as tool_backend_failed with backend_dead instead of reporting success; the partial events remain readable in the session transcript.
  • Crash evidence now carries the subprocess exit code and, where the operating system exposes it, the terminating signal.
  • Fatal cleanup gives the process a bounded grace period to exit on its own before being stopped, so the real exit result is no longer lost to a race with forced teardown.
  • Compozy does not replay a prompt automatically, because a prompt may already have caused external side effects. Sending the next prompt restarts the agent process and continues the same session and transcript.

Migration notes: crash bundles move to compozy.session_crash_bundle.v2 with structured exit_code and signal, with no v1 branch. Any consumer that treated a closed stream as success will now correctly see a failure unless a completion event was sent.

Dry-run proves the run you are about to submit

A Loop could validate, dry-run cleanly, and then fail at submission with executed definition template manifest changed. The compiler folded default values into the definition it stored, but compiled templates from the definition before those defaults — so a persisted run carried more template keys than its own snapshot, and hydration rightly refused it. Compilation now uses one canonical definition throughout, and dry-run exercises the exact snapshot boundary a real submission uses. (#313, #317)

  • Defaults are folded once at the start of compilation and used for linting, contracts, nodes, watch events, graph metadata, and child Loops alike — so omitted child mode values no longer appear out of nowhere during hydration.
  • A snapshot must load through the production loader before its bytes or digest are returned; one that cannot round-trip can no longer reach storage.
  • compozy loop run --dry-run and compozy__loop_run with dry: true run that same check, so a preview can no longer approve a definition that submission would reject.
  • A mismatch now names the manifest kind, the exact key, and its source instead of reporting a generic failure.

Migration notes: no storage, API, CLI, or configuration contract changed. Integrity checks were not relaxed — inconsistent definitions are still rejected, just earlier and with a readable reason.

Loop runs you can debug from the run page

A Loop run that failed used to be a dead end: every attempt died with "The agent output did not satisfy the action output schema", the node was quarantined, "Open quarantine entry" opened an empty sheet, "Open session" returned 404, the cell task sat in "Queued · attempt 1 of 10" forever, and Usage confidently reported 0 / ~$0.00. The agent had actually answered correctly every time — the daemon joined streamed text fragments with a newline, which landed inside a JSON string and corrupted a valid reply. That joiner is fixed, and so is every surface that made the failure impossible to read. (#324)

  • The agent now sees the authored output_schema in its prompt instead of prose that never said "JSON", extraction validates every candidate object newest-first (a quoted package.json no longer shadows the real answer), and the failure cause carries the underlying detail instead of one generic sentence.
  • Quarantine is routed to the node that actually failed. Parked consumers collapse into a single row — "execute task is quarantined — collect, review, verify and approve are parked behind it until it is requeued" — with one button that opens the producer's entry, and node_attention_flagged is finally emitted when a run parks.
  • Loop cells no longer stall in ready after a failed run: quarantine parks them as needs-attention and requeueing clears the park. The misleading of 10 attempt ceiling is gone, since the Loop owns the retry budget.
  • Daemon-claimed runs stop writing placeholder session ids, the real ACP session is bound to the lease under a claim token, and run detail exposes generations[].outputs[].session_id — so "Open session" works from the hero and from every node row that has one.
  • The task list nests Loop cells under their coordinator with an escalation-first summary ("9 subtasks · 1 needs attention · 2 running") and readable identities like g2.execute_task instead of loop.lo.
  • When a provider reports no tokens, Usage now reads "not reported" and "—" instead of a confident zero; the cost estimate returns only when tokens exist.

Migration notes: adds the attention_producer_node_id column to loop_node_controls through migration 00055; run-detail payloads gain node_controls[].attention_producer_node_id and generations[].outputs[].session_id.

Skills load through the native seam inside managed sessions

Managed sessions load installed skills through the native compozy__skill_view tool only — including skills that are not listed in the prompt catalog. The earlier attempt to give managed agents a private CLI socket is removed rather than kept as a fallback: provider code runs as the daemon user, so environment values, headers, process ancestry, and file modes cannot tell those requests apart from an operator's. (#314, #323)

  • If session policy denies the native tool, the agent reports the skill unavailable instead of shelling out or reading skill files directly.
  • Every compozy skill verb detects managed-session markers before doing any client, socket, registry, or filesystem work and points the caller at compozy__skill_list, compozy__skill_search, and compozy__skill_view. This is documented as a support guard, not an authorization boundary — same-user code can still clear those markers.
  • Hosted-MCP bind windows now start after ACP initialization and immediately before session negotiation. A cold provider launch that takes longer than the bind window no longer expires the tool seam before the agent can use it; a bind attempted before activation still fails closed.

Migration notes: the managed CLI transport is deleted — the socket, COMPOZY_AGENT_TRANSPORT_SOCKET, the managed identity headers, and the managed skill API scope. Operator CLI behavior from a normal shell is unchanged.

One owner per Loop run, and cancellation that sticks

Loop action runs now have exactly one daemon-owned worker, cancellation survives a restart, and a session that needs Compozy tools fails before the provider starts instead of running without them. Fresh Compozy homes also start with the bundled dev-cycle extension already enabled, while a home that has been booted before keeps whatever you chose. (#321, #322, #326)

  • Coordinators and ordinary task-role sessions can no longer activate or bootstrap a run that the dedicated loop-action executor already owns.
  • When the effective agent or lineage policy requires concrete tools and hosted MCP cannot provide them, session startup fails closed with ErrHostedMCPUnavailable before the provider process is launched.
  • Loop cancellation is durable: delivery state is persisted, delivery is idempotent, the run advances to draining once acknowledged, and anything still pending is retried from daemon boot and from scheduler sweeps — no restart required to converge.
  • Resuming a stopped session discards the stopped ledger projection first and restores it if provider startup or the clear rolls back, so forensic projections stop conflicting and the full history is rematerialized on the next stop.
  • Enablement of a bundled extension is a fresh-home default, not an override: generic local and marketplace installs stay disabled by default, and stored state survives restart and update.