Skip to content
All releases
CHANGELOG

v0.3.0-beta.5

The Bundle surface is gone. Extensions are now the single packaging unit, and installing one is inert: it publishes no tools and no resources until you explicitly enable it. Before enabling, you can preview exactly what…

BETARefactoring · 1Features · 3Bug Fixes · 1

♻️ Refactoring

  • Modernize Go runtime packages (#293)

🎉 Features

  • Rewind sessions to durable conversation checkpoints (#310)
  • Add session-aware slash skill commands (#311)
  • Add reversible session archiving and list actions (#309)

🐛 Bug Fixes

  • Restore durable ACP session continuity (#307)

Release Notes

Breaking Changes

Extension kits replace Bundles

The Bundle surface is gone. Extensions are now the single packaging unit, and installing one is inert: it publishes no tools and no resources until you explicitly enable it. Before enabling, you can preview exactly what an extension would publish and inspect what it is publishing right now, and any extension that declares network access must have its network requirement digest confirmed by a person. (#291)

  • compozy extension preview <name> shows what enabling would publish without changing state; compozy extension inventory <name> shows the live published inventory. Agents get the same reads through compozy__extensions_preview and compozy__extensions_inventory.
  • compozy extension enable|disable|update|install accept --confirm-network-requirement <digest>, so a network-declaring extension cannot start publishing without an explicit confirmation recorded on the install.
  • compozy extension secrets set|bind|list|unset manages write-only environment bindings that are scoped per workspace and stored as secret references, never as values.
  • Marketplace kinds are now exactly extension, mcp, and skill.

Migration notes: the whole compozy bundle command group is removed (catalog, preview, activate, list, get, deactivate, network-settings), along with the compozy__bundles_* native tools, the compozy__bundles toolset, the bundle marketplace kind, and the Bundle API surfaces. There is no alias — rebuild bundle-shaped setups as extensions and enable them explicitly.

Runtime hardening and secret-safe provider login

A broad modernization pass across the Go runtime tightened lifecycle and cleanup ownership, ID allocation, task settlement, filesystem confinement, and streaming framing. Most of it is invisible, but it lands several deliberate cuts that change what operators, scripts, and agents see. (#293)

  • providers.<id>.auth_login_command is now write-only. You can still set it through config.toml, compozy config set, or compozy__config_set, but no read surface returns it. compozy config show|list|get|diff, provider status, doctor, Settings, HTTP, and UDS return a safe login descriptor instead: whether it is configured, its source, the executable basename, whether that executable is present, and a recommended action.
  • Every per-session event database carries an immutable owner and physical identity. A database that was copied between sessions or workspaces is refused before any migration or mutation — no adoption, no rebinding, no automatic repair. The operator recovery path is documented under "Session event store ownership".
  • Markdown files under <workspace>/knowledge/ are injected as a bounded workspace knowledge snapshot before each accepted turn, including task, task-creator, and Heartbeat wakes. It is prompt context for the turn, not durable memory.
  • Installing an extension from Git now requires Git 2.37 or newer and reports extension_git_version_unsupported when it is older. Git sources must be HTTPS and resolve to public addresses.

Migration notes: compozy provider auth login --print-command is removed. The config key memory.recall.signals.metrics_enabled is removed with no alias. The task-notification native tools take workspace_id instead of workspace, and the old input is not an alias. Notification cursor identity and delivery_id are now opaque values that must be echoed back byte for byte.

Features

Complete Loop node lifecycle

Loops now have a full declarative failure contract at the node level and precise repair controls at the operator level. Authors classify failures, declare retries with backoff, route errors, absorb them with allow_fail, set attempt timeouts and deadlines, emit on_* effects, and add durable wait nodes. Operators pause, resume, cancel, kill, or requeue individual nodes and list what is waiting, quarantined, retrying, or asking for attention — all from the CLI, HTTP, UDS, native tools, and MCP, without opening the web UI. (#305)

  • compozy loop cancel drains a run safely and compozy loop kill closes it immediately; compozy loop node pause|resume|cancel|kill|requeue repairs a single node, and compozy loop nodes --state waiting|quarantined|attention|retrying inventories a run.
  • Agents get the same controls through compozy__loop_cancel, compozy__loop_kill, compozy__loop_node_pause, compozy__loop_node_resume, compozy__loop_node_cancel, compozy__loop_node_kill, compozy__loop_node_requeue, and compozy__loop_nodes; compozy__loop_status now reports node lifecycle state.
  • Repeated failure on one node quarantines that node instead of terminating the run, so independent lanes keep working, and the failure cause is classified rather than matched from a magic string.
  • Long-running Loop-bound sessions are no longer killed on elapsed time. Liveness is judged from real evidence, and prolonged silence raises attention instead of ending the work.
  • Defaults are tunable through loops.defaults.delivery.*, loops.defaults.watch.*, and loops.breaker.*, and new blocking lint rules reject invalid routes, impossible timing, malformed effects and waits, and watch sources without a stable identity.

Migration notes: compozy loop stop is deleted — the CLI verb, the HTTP route, and the compozy__loop_stop native tool. Choose cancel or kill explicitly. Extension watch sources must now declare event_key; a source without a stable event identity is rejected before a run starts.

Feedback semantics for durable Loops

A rejected Loop generation no longer restarts blind. The rejection is carried into the next attempt as context, only the producers responsible for it are re-run, and an opt-in ratchet keeps the best-scoring generation instead of losing it to a later regression. Every generation now records its origin, its parent, the gate verdict, the score, and the blocking issues inside claim-fenced transactions, so the CLI, HTTP, UDS, native tools, SSE, and the web UI all read the same durable run truth. (#290)

  • Loop templates can read previous.* (including previous.generation and previous.route_causes) and best.* to steer the next attempt from what actually failed.
  • Metric gates take a direction — maximize or minimize — plus a min_delta improvement threshold, so a regression is rejected deterministically. Invalid thresholds fail authoring with metric_min_delta_invalid.
  • compozy__loop_status and compozy__loop_runs project score, best generation, gate verdict, and generation origin and parentage; run detail, catalog, and recent-runs views render the same fields.
  • compozy extension list and compozy extension status accept --workspace, so agents can inspect workspace dev overlays without dropping to raw HTTP.

Migration notes: this is a greenfield hard cut that discards existing Loop run history. The migration clears Loop runs, run events, gate decisions, generation outputs, goal turns and checkpoints, session bindings, and output blobs, along with the task and automation runs that referenced them. Export anything you need before upgrading.

Reversible session archiving and list actions

A stopped session can now be archived so it leaves the default catalog without deleting anything. History, events, ledger, and the saved runtime choice stay readable, and unarchiving puts the session back exactly as it was — still stopped, so a normal prompt restarts it. Both session lists gained a row menu with state-aware Stop, Archive, Unarchive, and Delete, a delete confirmation, and a separate section for archived sessions. (#309)

  • compozy session archive <id> and compozy session unarchive <id>, plus compozy session list --archived for archived only and --include-archived for both. Agents get compozy__session_archive and compozy__session_unarchive, and extensions get sessions/archive and sessions/unarchive under session.write.
  • The catalog contract takes archive=exclude|only|include and defaults to exclude, with exact filtered totals and cursor fingerprints. Archived sessions are excluded from normal metrics.
  • Archiving is stopped-only and idempotent. An archived session stays readable, but prompt, attach, and resume are refused until you unarchive it. Hard delete is unchanged, and archive stays catalog metadata rather than a lifecycle state.
  • Bridge providers now wait for HTTP route readiness before serving, which closes a startup race across the bundled Discord, Google Chat, GitHub, Linear, Slack, Teams, Telegram, and WhatsApp runtimes.

Migration notes: existing sessions are unarchived, so nothing changes until you archive something.

Rewind a session to an earlier checkpoint

You can now rewind an idle session back to one of your earlier messages instead of starting over. The selected message and everything after it leave the active transcript, the message text comes back as a composer draft, and the session continues under the same session ID with a fresh agent context rebuilt only from the part you kept. Rewind touches the conversation only — it does not undo file edits, tool effects, network activity, saved memory, or anything the provider already did outside Compozy — and the discarded events stay archived for audit. (#310)

  • compozy session rewind <session-id> picks the cut point with --message-id and reads the current transcript fences for you; scripts retrying a known request pass --expected-generation, --expected-epoch, and --expected-max-sequence together with the original --idempotency-key. Agents get compozy__session_rewind.
  • Retrying the same rewind with the same idempotency key returns the original result, and the response carries the draft_text that goes back into the composer.
  • A rewind is refused with a clear conflict — and without cutting the transcript — when the fence is stale, the session is busy, input is queued, an approval is pending, or the session is daemon-managed. It is serialized against clear, delete, repair, resume, and other prompt-producing operations.
  • In the web UI, the action appears on your own durable messages, requires an empty composer, confirms the side-effect boundary before it runs, and restores the draft afterward.
  • Reads take an archive selector: compozy session events and compozy session history accept --archive active|archived|all, and the same selector exists on the HTTP and UDS reads.

Migration notes: session events and session history now default to archive=active. They previously returned archived rows alongside active ones — pass --archive all to keep the old behavior.

Session-aware slash commands

Slash commands in the composer are now backed by a single daemon-owned catalog scoped to the exact session, and they work anywhere in a prompt rather than only at the start. Built-in and ACP control commands stay standalone, while a skill command can be dropped inline, repeated, and mixed with the text you already typed; the matched skill's full instructions are injected into that same turn. The same catalog is readable from the CLI, HTTP, UDS, and a native tool, so agents can discover what a session can actually run. (#311)

  • compozy session commands <session-id> lists the catalog, and agents read it with compozy__command_list in the compozy__catalog toolset. compozy__skill_view accepts a source-qualified command_id from that list.
  • The catalog groups Built-in, Agent, and Skills at the start of a prompt and shows only effective skills inline. A bare /skill resolves the effective winner across bundled, global, additional, workspace, and agent-local sources; extension skills use /extension-id:skill and marketplace skills use /registry-id:skill.
  • What is effective respects global and workspace scope, agent activation and disable lists, runtime disable overlays, enabled and disabled extension resources, workspace and session ownership, and live resource revisions. A session_commands_changed stream frame refreshes only the affected session.
  • Injection is bounded at 24 KB per skill and 64 KB per turn, and repeating the same skill activates it once. Invocations persist through admission, queueing, replay, transcript storage, and the UI, and queued ones are revalidated against the exact source before dispatch.
  • Slash activation is limited to human operator input. Agent-authored prompts and compozy__session_prompt keep slash-shaped text literal, and hooks can remove an admitted invocation but never add one.

Fixes

Restart a stopped session and keep its runtime

A stopped session used to be a dead end: the UI went read-only and the only way forward was creating a new one. Sending a normal prompt to a stopped session now restarts its agent process, reloads the retained provider history, and continues under the same session ID and transcript. The provider, model, reasoning effort, and speed you picked are stored on the session itself, so they survive a stop and a daemon restart instead of silently reverting to the default. (#307)

  • The lifecycle gained a starting state, and a normal prompt is the only operation that moves a stopped session back toward execution. session resume stays attach-only, and queue, steer, interrupt, and attach do not restart a session.
  • compozy session runtime set <id> takes --provider, --model, --reasoning-effort, and --speed, and compozy session runtime clear <id> drops the choice. Both fence on --expected-revision and report a conflict on a stale one. Agents get compozy__session_runtime_set and compozy__session_runtime_clear; extensions get sessions/runtime/set and sessions/runtime/clear under session.write.
  • Session reads expose runtime.selected, runtime.effective, and runtime.selection_revision. A prompt resolves its runtime from an explicit snapshot first, then the stored selection, then the current effective values, and an already-queued prompt keeps the snapshot it was accepted with.
  • The composer stays enabled for a stopped session, and closing a session window during a live turn no longer breaks the transcript view.

Migration notes: the Use as Goal action on settled assistant messages is removed. /goal is the single entry point for Goals.

Durable inputs for busy sessions

Queue, Steer, and Interrupt are now daemon-owned durable operations instead of client-side intent that could quietly disappear. An input is persisted before it is acknowledged, survives a refresh and a daemon restart, dispatches exactly once in FIFO order, and can be listed, edited, canceled, or promoted to steering by its entry ID from the CLI, HTTP, UDS, native tools, or the extension host. Disruptive changes are fenced against the turn you meant to change, so a stale client cannot interrupt a newer turn. (#304)

  • compozy session prompt accepts --queue, --interrupt, and --steer; compozy session input list|edit|steer|cancel manages pending input by its persisted ID.
  • The queue is readable and mutable over HTTP and UDS at /api/workspaces/{workspace_id}/sessions/{session_id}/prompt/queue, including per-entry replace, steer, and cancel.
  • Agents get compozy__session_inputs_list, compozy__session_input_replace, compozy__session_input_cancel, and compozy__session_input_promote.
  • The composer clears only after the daemon acknowledges, a failure keeps your draft, and a refresh reconstructs pending input from the daemon. Queued, steered, interrupted, canceled, accepted, and dropped markers no longer render as warnings, and an expected ACP cancellation no longer appears in the transcript as a provider failure.

Migration notes: the dedicated interrupt endpoint is removed — interrupt is now a prompt mode plus a fenced queue operation. The legacy ACP steer handler and the runtime steer source are removed, and the web client no longer mirrors the queue in local state.

Live changelog and composer fixes

The changelog on compozy.com now reads published releases directly from GitHub at request time instead of depending on a bot pushing a generated page back into main after every release. Each release gets its own page with rendered Markdown, category sections, evidence, compare links, and downloadable assets, plus an RSS feed at /changelog/feed.xml, and releases now appear in site search, the sitemap, and the text feeds that agents read. (#292)

  • Typing in the session composer no longer swallows spaces.
  • A window-manager WebSocket upgrade that fails for a missing workspace now returns a proper preflight error frame, and the web client refreshes a stale workspace list when it sees that error instead of staying stuck.

Migration notes: the release workflow no longer publishes a site changelog receipt commit, and the generator scripts behind it are removed.

Contributors
Release assets

23 files published by the GitHub release workflow.

Browse downloads