Repository navigation
⚠️ This release is not rolling-upgrade safe. Stop every API replica before
applying its migrations, then start only the upgraded version. Two
independent reasons, either sufficient on its own, and both fail silently:
- A pre-upgrade replica deletes workspace-removal reservations by id alone,
erasing the newer attempt-token fence.- A pre-upgrade replica writes no
instance_heartbeatsrow, so an upgraded
peer reads it as dead and may reclaim leases and Git worktrees out from
under a process that is still running.Single-container SQLite deployments are unaffected in practice — there is only
one replica — but the migrations still apply.
This is the stable cut of the v0.7.3 line, folding in everything from
v0.7.3-rc.1 and v0.7.3-rc.2 plus the entries marked new below.
Channels
- Telegram becomes a first-class channel: publish an Agent to Telegram at parity with Discord — group and private triggers, attachments both ways, artifact upload, per-conversation sessions and restart recovery. Updates arrive over outbound long polling, so no public HTTPS ingress or callback URL is needed and a private deployment works unchanged; registering a bot clears any webhook previously set on it. Triggering on every group message additionally requires Group Privacy to be disabled via @Botfather.
- QQ official bot channel (MVP): publish an Agent to a QQ official bot over the platform's WebSocket, bringing the channel count to twelve.
- The agent's Publish tab is now Channels: a more accurate name for what it manages — API, Feishu, Slack, schedules, repository triggers and the rest.
- Ask an Agent what it is doing, from any channel (new):
/statusreturns a self-check — provider and CLI health, mounted MCP and skills, live queue depth and concurrency — as a programmatic report rather than a guess. The same facts back the HTTP endpoint and the chat reply, so the two can never disagree. A new per-Agent reply-language setting controls the response language, since a command reply never reaches the LLM and cannot infer it from the conversation. - Feishu: a quoted reply no longer resurrects a stale direct-message session: quoting a days-old message reopened that whole conversation and the model kept answering from context you had moved on from. Direct messages are now capped at the two-hour window like any other; group reply chains and topics still never expire.
/newalso works in a quoted direct-message reply, where it previously reached the Agent as literal prompt text. - Feishu and Slack no longer process a message twice: deduplication keys on the message's own identity rather than the delivery envelope, so one message starts one run.
Access and credentials
- Multiple named API keys per channel (new): the API and A2A channels each held one plaintext key on the Agent row, so rotation broke every integration at once and any database read yielded live credentials. Keys are now individual rows storing only a hash and a display prefix, each with a required description, optional expiry and a last-used stamp — so you can answer "what is this key for, and is anyone still using it?" and retire one caller without touching the rest. A REST key can never authenticate an A2A request.
- Sign in on a remote or headless machine:
a2wave loginsupports the OAuth 2.0 device grant — the terminal prints a short code, you approve it from a browser wherever you already have a session, and the waiting CLI receives a token. Selected automatically over SSH; containers and CI pass--device. The approval page shows the requesting IP, client and time so you can tell your own session from a code someone phoned you. - CLI tokens for automation: named, long-lived, individually revocable credentials created from Settings → CLI access, for CI jobs and scripts. Unlike a session token, retiring one machine's credential no longer means retiring them all, and a password change no longer silently breaks every pipeline. The plaintext is shown once.
- "Keep me signed in", with sliding renewal (new): session lifetime was one deployment-wide value, wrong at both ends — no way to ask for a shorter session on a shared machine, and a sign-out mid-task on day seven while working continuously. The checkbox (off by default) now decides at sign-in: unchecked gives a real session cookie that dies with the browser, checked gives the long-lived session, and continued activity renews it rather than expiring on a fixed schedule.
- Invitation links replace admin-set passwords: administrators issue an expiring single-use link instead of typing someone else's password, and the invitee chooses their own and lands signed in. Links are copyable and revocable from the invitations drawer, and re-inviting an address supersedes the outstanding link so only one is ever live.
- Credentials survive an edit: saving a form no longer persists the masked placeholder over the real secret.
Runs and reliability
- Artifacts are no longer delivered to the wrong run (new): runs of an Agent shared one artifacts directory, and ownership was inferred from file mtime — so a file written by a concurrent run inside the window was registered as the finishing run's own and sent to its user. Observed in production: one run issued no write at all yet shipped another run's spreadsheets. Each run now gets its own directory and the collector reads only that one, so concurrency, name collisions and clock skew stop mattering.
- Opt-in job-level auto-retry (new):
maxJobRetries(0–3, default off) replays a failed job as a brand-new run — fresh workspace, fresh session, re-admitted through the queue — which is what the manual rerun button builds, and what the existing in-jobmaxRetriescannot do because it inherits the failed attempt's dirty state. Deliberately narrower than the button since it fires unattended: cancelled runs are never replayed, and permanent or hard-quota errors are skipped because a fresh job would hit the identical wall. Every attempt stays its own record in the run list. - An interrupted run that never started executing is restarted (new): a run killed before its CLI emitted a single line was settled as
failedand left there, since with no session id there was nothing to resume — leaving a human to re-trigger it by hand. This is routine, not exotic: a clone or sync on a large repository runs for minutes before the CLI starts, and a deploy landing in that window lost the whole run. Recovery now requeues such a run, gated on proof that it produced no output and therefore can have no side effects. - An interrupted run no longer loses its provider session: a run's session id is recorded while it is still executing, not only on completion — previously the one case that needed to resume was the one case that never stored it.
- A run abandoned by a dead instance is reaped and its queue restarts: a temp-workspace run whose process died took no lease, so nothing could prove it was abandoned and it stayed
runningforever — pinning the Agent's concurrency and parking the queue indefinitely. Runs now carry an owner instance, and a periodic sweep settles those whose owner is provably gone, then restarts promotion. The verdict is ownership, never age, so a long-running review is never mistaken for a dead one. - A queued repository-trigger run skips a merge request that already finished: a run whose subject was merged while it waited now re-probes and terminates as
cancelledinstead of spending tokens to conclude "already merged". Fails open on every ambiguous verdict, so a broken probe never cancels legitimate work. - Chat and run recovery fixes: restored chats accept follow-ups again, run state recovers and refreshes correctly after a server restart, and interrupted A2A remote tasks are resumable.
Storage and deployment
- Managed SCM storage for Git sources:
localPathis now optional for Git and allocated under the managed storage root; P4 still requires an explicit path covered by its clientRoot. Existing bind mounts, source paths and legacy worktree roots survive the upgrade. - Cross-replica workspace recovery: a crashed or unreachable replica no longer strands its checkouts. Processes publish a liveness heartbeat, and a surviving replica settles the abandoned workload, releases its lease, and converges the leftover worktree removal — work that previously required an operator to run SQL by hand. An instance that cannot renew its own heartbeat stops itself before peers may reclaim its workspaces.
- PostgreSQL deployment path:
a2wave setupcan provision a PostgreSQL 16 sidecar or point at an external server. Still experimental and not recommended for production; there is no SQLite → PostgreSQL data migration. - Git SCM Agents no longer share a working directory: each Agent runs in its own worktree, where previously a run of one Agent could delete files a concurrent run of another was executing against. A worktree with unmerged agent commits or local modifications stays pinned (with a warning) and resumes following the source branch once that work lands upstream.
Observability and UI
- Queue depth and end-to-end latency on the agent overview (new): the overview could not answer the two questions operators actually ask — is this Agent backed up right now, and how long does a request take from arrival to result. Every existing duration metric measured execution only; wait time is now recorded per turn and charted alongside it. Historical rows render as "no data" rather than as zero.
- Readable status colors and token chart (new): status colors are theme-correct in both light and dark, and the token chart is legible.
- Smaller fixes: Claude's multi-result output is preserved complete; OAuth metadata availability is reported as effectively resolved rather than as configured; the log panel's copy button copies the run id; URLs in chat messages are clickable;
a2wave --helplayout is repaired; the login page shows the server version; and the workspace path preview no longer strips CJK, kana and hangul, which sent anyone mounting or cleaning up a non-Latin-named Agent's directory to a path that did not exist.
Other
- GitLab triggers can watch an entire group: name a namespace instead of enumerating repositories, and newly created repositories are picked up with no config edit.
- The CLI is now an agent-first entry point: commands and output are shaped for a local Agent to drive directly, rather than for hand-typing.
- Reasoning effort and fast mode bind per provider chain entry: both sit beside the model rather than once per Agent, because the legal effort levels follow the model. Levels are discovered per model alongside model ids, not hard-coded, and
diagnosewarns when a control is bound to a CLI that has no such setting. - A2A calls preserve caller provenance across hops: run records show the full
user · calling Agent · sourcechain even after a remote multi-hop invocation. - Repository auto-review is held to a P0/P1 bar: the MR review template sends the Agent out of the diff into the surrounding code, works a checklist of what a diff-only pass reliably misses (call sites of a changed signature, old clients against a changed schema, irreversible migrations, swallowed errors, races), and keeps only findings that name the input or timing that reaches them. P2 and below stay out of the comment, and "no P0/P1 issues found" is stated as a valid result.
- Thirteen P0/P1 defects closed by an API-surface audit (new), alongside an earlier sweep in which P4 sync errors stopped leaking the connection password, a failed topic merge rolls back instead of leaving the target holding a still-active source's facts, a failed Agent import no longer commits skill rows with empty files, and API-key regeneration plus SCM sync/check write the audit entries they were missing.
- Windows fixes: Codex multiline prompts are preserved, and CLI status probes work.