Repository navigation
feat(cli): hgs watch --json event stream (event data plane M3) - #368
Merged
Merged
Conversation
Owner direction 2026-10-27: data parsing and similar processing run outside the GUI thread. First milestone of the event data plane (zerus-604d.1). - ProcessRunner passes every result through one serial preparation thread, hgs-prepare, keeping completion order. run(request, owner, prepare, apply) and post(owner, prepare, apply) shape values there; the owner's thread only applies them. - Every HgsClient reply, the connector panels, the speech client, the update feed and startup fleet discovery are parsed in prepare steps. The task parse pool and the 8 MiB worktree snapshot re-parse per lookup are gone. - JsonParse is the tray's only JSON parser and reports a parse on the GUI thread; every Qt suite runs with ZERUS_GUI_THREAD_CHECKS=fatal. check-source.py rejects QJsonDocument::fromJson elsewhere and limits JsonParse::local() to a listed, shrink-only set of small local values (owner: "согласен, оставляем исключения до M2"). - SettingsJson parses QSettings JSON values once per change, warms the large keys at startup and records what writers stored, so per-poll read-mark reads no longer re-parse settings. - IdentityHash remembers per-row SHA-256 identities, 3.9 % of the Mac GUI thread in a 2026-10-27 sample. Design: docs/superpowers/specs/2026-10-27-event-data-plane-design.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Event data plane M3 (zerus-604d.3). `hgs [@host] watch --json` is a long-lived NDJSON stream: hello, a bounded catalog snapshot of the live listing (rows exactly as ls --json --local --no-archives, keyed run:<run_id>), deltas with removal reasons, catalog.meta, and Activity subscriptions over stdin whose cursor is the events.sqlite3 seq that inspect --after takes. Heartbeats, gap/snapshot resync, a 4 MiB coalescing writer queue and 1 MiB frames bound it; EOF on stdin ends it. `hgs -h` prints the marker `Event stream ABI: watch-v1`; @host runs it over one SSH connection with keepalives, guarded so an older peer never reads it as a launch. Change detection uses no new dependency: a 250 ms pulse stats the listing's inputs and polls PRAGMA data_version on a held journal connection, with a 5 s safety listing for changes no file shows. Volatile observation fields are masked, so deltas carry real changes only. The serde frame types live in crates/watch-protocol (no Loro or Qt) for the desktop, the Tauri client and later the connector. The inspection's journal query is shared, not forked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
Author
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.
Event data plane M3 (epic zerus-604d, task zerus-604d.3). Stacked on #367 (M1). Until that merges, this PR also shows its two commits; the M3 change is the last commit.
What changes
hgs [@host] watch --json: a long-lived NDJSON stream of one computer's live sessions, plus the Activity of the sessions a client subscribes to. It is additive; no existing command output changes.hello,snapshot(pages ≤ 512 KiB),delta(whole-row upserts, removals withended|archived|forgotten|replaced),events(cursor = theevents.sqlite3seq thatinspect --aftertakes),state(inspect summary without events/processes),heartbeat(10 s),gap,error,pong. Frames are at most 1 MiB; a 4 MiB writer queue coalesces per key and falls back togap+ snapshot on overflow. EOF on stdin ends the stream.hgs -hprintsEvent stream ABI: watch-v1.@hostruns the stream over one SSH connection withServerAliveInterval=10/ServerAliveCountMax=3, guarded by that marker, so an older peer answers with an error and never launches an agent.PRAGMA data_versionon a held read-only journal connection. A 5 s safety listing catches changes no file shows.goal_observed_atandprocess_work.sampled_atare masked, so deltas carry real changes only.crates/watch-protocol: serde frame types without Loro or Qt, for the desktop (M4), the Tauri client and later the connector. It is wired into checks.yml, dependabot and mac-install.timeline_rows/timeline_event), not forked.inspectoutput is unchanged.docs/reference.md→ JSON and external clients → Event stream.Verification (arch)
cargo +1.99.1 test --locked: 1243 passed, 3 ignored. Watch subset rerun by the reviewer: 14 passed.crates/watch-protocol: 7 passed; fmt and clippy-D warningsclean.PYTHONPATH=tests python3 -m unittest test_watch: 9/9 (reviewer rerun). The subagent also ran 178 focused integration tests (1 skipped), the Windows target check and check-source (0 privacy findings).Known limits, tracked for M4/M5
event(open-event replace) frames are defined but not sent yet. Text between tools arrives through 2 sstatere-reads while an agent is busy.hgs.exe @host watchfrom Windows over piped ssh is untested.🤖 Generated with Claude Code