v3.3.4 Luxor Released #1700
amrmelsayed
announced in
Announcements
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
v3.3.4 Luxor
Released: 2026-09-17
Summary
3.3.4 is a hardening patch of the Luxor line, driven by what the first
production installs of 3.3.3 hit in the field. The agent messaging stack closes
its three remaining delivery holes: long messages arrive whole instead of
losing their head to a paste heuristic, mail reaches a working agent as soon as
its composer is free instead of queueing behind the whole turn, and the
delivery gate can no longer miss a human's keystrokes. The dashboard stops
burning the GitHub API quota when the forge starts failing, and Tower startup
can no longer destroy live sessions.
Around that core: the cloud tunnel stops letting large transfers starve small
requests and learns to serve a full browser IDE, agent terminals cycle from the
keyboard and the Stream Deck, agents spawned under Tower are resumable again,
consultation reviews are fenced off from editing the tree they review, and
image generation gains a MuAPI provider.
The dashboard stops burning the GitHub API quota (#1645, PR #1652)
Tower's overview cache never cached a failed forge fetch, so once
ghbeganfailing (for instance, when the API quota ran out) every dashboard poll
re-spawned all four list commands and kept the quota pinned at zero: a
self-sustaining storm measured at two
ghspawns per second on a productionTower. Failures are now cached with a doubling backoff, a rate-limited backend
suspends its calls until the quota actually resets, concurrent pollers share
one in-flight fetch, and cache invalidation is debounced and scoped so it can
no longer wipe every workspace at once. The dashboard shows a banner naming the
real state (rate limited, or forge unavailable) instead of silently emptying
its lists.
Long messages arrive whole (#1567, PR #1644)
An
afx sendbody over about 1 KB could reach its recipient as only the lastfew lines, mid-sentence, while the sender read a delivered confirmation. The
kernel splits a large terminal write at the input queue's high-water mark, and
the recipient's paste heuristic discarded the first chunk. Long frames now
travel as one explicit bracketed paste written in small UTF-8-safe pieces with
the Enter kept outside the paste. A real-TUI harness that lost the head of 14
of 20 long messages through the production write edge now loses none, and echo
verification recognizes the paste placard, so a correct long delivery is
reported verified instead of unverified.
Mail reaches a working agent without waiting out its turn (#1664, PR #1666)
The delivery gate held mail whenever the recipient was producing output, so a
message to an agent mid-turn queued behind the entire turn: over one day of
real traffic, 227 deliveries waited past two seconds, averaging 54 seconds with
a worst case over nine minutes, even though the composer was empty and safe to
write to the whole time. The gate now watches the composer region itself, which
sits unchanged for minutes while the screen above it repaints constantly, so
mail lands as soon as the composer is genuinely free. A human typing at the
line still holds mail exactly as before.
The gate can no longer miss a human's keystrokes (#1473, PR #1634)
The render gate proved a composer empty from output signals only, so a
keystroke landing between the gate's check and the write could put a message
onto a line someone had started typing on. The terminal write path now counts
input as input: every keystroke bumps a counter the gate folds into its check,
a short input-settle window covers the not-yet-echoed case, and the control
replies terminals send automatically (which arrive on the same path as typing)
are filtered from the signal so they cannot hold mail with nobody at the
keyboard. A race that happens during the write itself is reported rather than
re-written, because re-writing a message that already landed is the re-injection
failure 3.3.3 fixed.
Tower startup can no longer destroy live sessions (#1629, #1685, #1686, #1691)
A cluster of fixes from one incident: a second Tower, accidentally pointed at
the production database by an environment-variable typo, reconnected every live
session's process and then deleted 53 of 56 of them as "stale".
(PR Fix #1629: refuse a second Tower against a live global.db (owner lock) #1689). An owner lock file next to
global.dbis claimed atomicallybefore anything touches shared state; liveness is probed fail-closed, a dead
owner self-clears so normal restarts are never blocked, and the refusal
message teaches the exact misconfiguration that caused the incident.
proof of death is the process being down. A live session is never signaled
and its row is never deleted, regardless of socket-file state; unconfirmed
rows are preserved and retried on a later pass.
orphaned-shellper sweep on the boot path is now time-bounded with cooperative
cancellation and logs its entry, duration, and outcome, so it can no longer
hang Tower into the launcher's 30-second timeout without a trace.
afx tower startnow watches the daemon it spawned: when the daemon exits early, thelauncher surfaces the daemon's own error verbatim within about a second
instead of burning the full 30-second budget and printing a generic timeout.
Agents spawned under Tower are resumable again (#1219, PR #1626)
A Tower started from inside a Claude Code session inherited that session's
identity markers and handed them to every agent it spawned. Each agent then
believed it was a nested child session, disabled transcript saving, and became
silently unresumable. Every Tower-descendant spawn now routes through one
sanitizer that strips per-session identity, and
codev doctordetects daemonsthat are already contaminated.
Small requests stop queueing behind large transfers on the tunnel (#1677, PR #1678)
A tiny RPC through the cloud relay could take 39 seconds while a 1.3 MB
transfer drained, because both browser connections ride one HTTP/2 session
between the relay and the tower, and that session ran with 64 KB flow-control
windows. Tower now advertises a 1 MiB per-stream window inside a 4 MiB session
window, so a large transfer cannot exhaust the shared budget, and tunnel-level
compression is off so large frames stop stalling the event loop. The matching
change on the relay side is deployed separately; end-to-end timings are being
re-measured in the field.
The cloud tunnel can serve a browser IDE (#1668, PR #1683)
Tower gains a keyed
/ide/forward: one local IDE server (a VS Code server-web build),registered with
afx ide start|stop|status, is reachable through the existing cloudtunnel at
/t/<tower>/ide/?folder=<path>— the full workbench boots in a browser withno cloud-side changes and no new public routes. The forward rides Tower's existing
request authentication (the shared local key, stamped by the tunnel), preserves the
server's asset caching, and blocks the IDE management API from remote access. One
server serves every workspace folder; the browser picks the folder per connection.
Cycle agents from the keyboard and the Stream Deck (#1563, PR #1676)
Moving between agent terminals no longer means reaching for the sidebar. In VS Code,
ctrl+alt+n/ctrl+alt+pcycle focus through the Agents order the sidebar shows,skipping any agent whose terminal cannot open so a dead session never wedges the walk.
The Stream Deck gains matching Next/Prev Agent keys and an Agent Navigator dial (not
pre-placed, like the PR and Spawn navigators). Both surfaces share one cycle-order
source with the sidebar renderer, so what you see is what you get.
Consultation reviews cannot silently edit the tree they review (#1649, PR #1659)
A consultation lane edited the code it was reviewing (reverting guards to test
whether the tests covering them were vacuous), and nothing told it not to or
noticed that it had. The consultant role now forbids modifying the tree under
review or running state-changing commands, holding even when the prompt seems
to ask for an edit; a coverage question is answered by reading, not mutating.
And every consultation lane now runs inside a tripwire that snapshots content
hashes before and after: any difference prints a red banner naming the files
and appends the same warning below the review's verdict.
Image generation gains a MuAPI provider (PR #1624)
codev generate-imagecan now run through MuAPI with--provider muapi,supporting text-to-image and reference-image editing: local reference images
are uploaded, the job is polled on a bounded schedule, and returned media is
validated (HTTPS URLs, image signatures) before anything is written locally.
The default provider and its behavior are unchanged. Contributed by
@Anil-matcha.
VS Code polish
Other fixes (dashboard, porch, infrastructure)
afx spawnno longer refuses over merged PRs (afx spawn: open-PR collision guard counts merged PRs since #1619 widened pr-search to --state all #1637, PR Fix #1637: spawn open-PR collision guard counts merged PRs #1673). Theopen-PR collision guard consumed a PR search that 3.3.3 had widened to all
states (so consult could review merged PRs) and counted merged PRs as open.
The search now reports each PR's state and the guard counts only genuinely
open ones.
cron: deliver team-update only when the hour had events #1660). The team-update cron first gained its required message field, then a
condition so an empty update is not delivered at all.
Fix #1630: sync e2e test ports with TOWER_TEST_PORT (completes PR #1632) #1635, Fix #1630: pass the test port into page.evaluate (browser has no process) #1636). The nightly dashboard end-to-end workflow, its tests, and the
browser context now agree on the Tower port under test.
coverage of held-mail owner escalation and held-row dismissal on builder
cleanup.
Breaking changes
None.
Install
npm install -g @cluesmith/codev@3.3.4 afx tower stop && afx tower startThe VS Code extension ships separately via the Marketplace (
Codevextensionby
cluesmith.codev); the extension items above arrive with its nextMarketplace publish.
Contributors
the database owner lock (PR Fix #1629: refuse a second Tower against a live global.db (owner lock) #1689), proof-of-death reconcile (PR Fix #1686: reconcile must confirm death before deleting/SIGTERMing a shellper row #1693), the
bounded orphan sweep (PR Fix #1685: bound the orphaned-shellper sweep (pre-readiness) so a wedged process table can't stall startup #1687), the legible startup refusal (PR Fix #1691: surface tower owner-guard refusal in the CLI, not a 30s timeout #1692),
tunnel flow-control windows (PR Fix #1677: raise tunnel H2 flow-control windows and disable ws deflate #1678), the browser IDE forward (PR tower: forward /ide/ to a local web IDE server + afx ide lifecycle (#1668) #1683),
agent cycling on keyboard and Stream Deck (PR Cycle agent terminals from keyboard and Stream Deck #1676), terminal reconnect on
wake (PR Fix #1681: re-arm terminal reconnect budget on wake #1682), the spawn collision-guard fix (PR Fix #1637: spawn open-PR collision guard counts merged PRs #1673), and the dashboard
e2e port chain (PRs Fix #1630: set TOWER_TEST_PORT in the scheduled dashboard e2e workflow #1632, Fix #1630: sync e2e test ports with TOWER_TEST_PORT (completes PR #1632) #1635, Fix #1630: pass the test port into page.evaluate (browser has no process) #1636).
GitHub-quota storm fix (PR Fix #1645: stop the overview cache from burning the GitHub GraphQL quota #1652), whole-message bracketed-paste writes
(PR Fix #1567: write long frames as one bracketed paste in ≤512-byte chunks, Enter outside #1644), composer-region gating (PR Fix #1664: wait on the composer, not on the recipient's output #1666), spawn environment
sanitization (PR Fix #1219: sanitize inherited CLAUDE_CODE_* env at every Tower spawn #1626), the consultation tripwire (PR Fix #1649: tell consultants not to edit the tree, and notice when it changes #1659), and the
team-update cron fixes (PRs cron: add the required message field to team-update.yaml #1643, cron: deliver team-update only when the hour had events #1660).
gate-to-write input race and echo-lag residual (PR Render gate: close the gate→write input race and the input-echo-lag residual #1634), plus mailbox
escalation test coverage (PR Test coverage: mailbox owner-resolution wiring (escalateHeldToOwner) and cleanupBuilder() held-row dismissal (#1477) #1625).
(PR feat: add optional MuAPI image provider #1624).
above.
All reactions