Repository navigation
feat(tui): reveal matrix-rain words from real codex/claude PTY output - #47
Merged
Merged
Conversation
PTY-only adapters (codex/claude interactive, shell) emit
SessionEvent::Pty bursts while the agent is working but no
ToolUse/Status — so the matrix rain stayed silent for them while
zarvis (which emits structured tool events) revealed words.
Add a per-session, ~3.5s rate-limited heartbeat on PTY events that
queues a rotating activity word ("working" / "thinking" / "running"
/ "writing" / "reading" / "typing"). Throttle state is cleared on
Reset and session removal so the map stays bounded.
Internally, route reveal queuing through queue_at/queue_random_at so
the throttle and the reveal share a single timestamp — without it,
tests that inject a deterministic `now` were racing the implicit
Instant::now() inside queue.
The first pass cycled a hard-coded list of generic activity words
("working", "thinking", ...) on a per-session timer. That signaled
"something is happening" but not *what* — codex's "Editing
src/main.rs" and claude's "Reading" looked identical to the matrix.
Now `observe_pty_activity` takes the PTY byte stream:
- Skip ANSI escape sequences (CSI + OSC), then harvest ASCII-alpha
runs of 4–12 chars into a per-session FIFO pool (cap 32). Words
longer than the cap poison their entire run so we don't surface
trailing sub-words.
- Drop exact consecutive duplicates so a spinner that re-prints
"Thinking" every frame doesn't dominate the pool.
- On each throttled reveal tick (≤ 1 / 3.5s per session), pop the
newest pooled word and queue it as the matrix reveal text. Drain
the rest so the next reveal reflects fresh activity.
- Fall back to the rotating generic words only when the pool is
empty (very first chunk, or a quiet stretch with only escapes).
Throttle + pool both clear on `Reset` and session removal.
edwin-zvs
added a commit
that referenced
this pull request
May 19, 2026
Resolved conflicts:
- crates/cli/src/ui.rs: took upstream's reveal-pin-on-real-drops algorithm
(#47, #49) and reapplied the SessionEvent::ContextCompacted arms in
format_event_body + short_event_label. Conflicts were only there
because cargo fmt churn from this branch touched lines near the
upstream rewrite.
- crates/adapter-zarvis/src/provider/codex_oauth.rs: new provider
introduced by #46 needed a Content::Summary arm matching the other
providers — emits the SUMMARY_WIRE_PREFIX'd text as a user input
message in the Responses-API shape.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Codex / claude in interactive mode (and shell) only emit
SessionEvent::Ptywhile the agent is working — noToolUse/Statusformatrix_rain::word_for_eventto map. Result before this PR: the rain stayed silent for them while zarvis revealed words.Now
MatrixRain::observe_pty_activity(session_id, bytes, now)harvests words from the live byte stream:working / thinking / running / writing / reading / typing) only when the pool is empty (first chunk, or a quiet stretch with only escapes).SessionEvent::Resetand session removal so the maps stay bounded.Test plan
cargo test -p agentd-cli --release— 107 unit + 1 integration pass; includes 11 new matrix-rain tests covering extraction (CSI/OSC strip, dedupe, length cap), pool cap, harvested-vs-fallback selection, throttle, cross-session independence, and session forget.agentwith a codex session and watch the matrix-rain pane reveal words pulled from codex's output (tool names, file stems, action verbs) every few seconds.Editing/Reading/Runningwords fromword_for_eventstill appear (PTY harvesting only fires for PTY events; zarvis doesn't emit those).M-x reset) and confirm the next PTY chunk seeds a fresh reveal without delay.