Probe, Parse, And Track Pipeline¶
One live tracking cycle in houmao-server is implemented by HoumaoServerService.poll_known_session() in ../../../../src/houmao/server/service.py. The service does not ask the child CAO for terminal status. It probes tmux directly, inspects the pane process tree, parses captured output, and records the result into the in-memory tracker.
Poll Cycle Overview¶
For one tracked_session_id, the service runs this sequence:
- Load the current tracker and its
HoumaoTrackedSessionIdentity. - Check
tmux_session_exists(identity.tmux_session_name). - Resolve the pane target through
TmuxTransportResolver.resolve_target(...). - Inspect the pane process tree with
PaneProcessInspector.inspect(tool=identity.tool, pane_pid=target.pane.pane_pid). - If the supported TUI is up, capture the pane text from tmux.
- If the tool is parser-supported, capture or reuse the parser baseline.
- Parse the captured text through
OfficialTuiParserAdapter. - Commit the cycle into
LiveSessionTracker.record_cycle(...).
The worker keeps running for most outcomes. The only normal case that returns False and ends the worker loop is tmux_missing.
Transport Resolution¶
TmuxTransportResolver in ../../../../src/houmao/server/tui/transport.py resolves one tmux pane target.
Current selection rules are:
- if no panes exist for the tmux session, raise
TmuxCommandError - if
tmux_window_nameis provided, keep only panes whosepane.window_namematches it - if that filtered set is empty, raise
TmuxCommandError - when multiple panes remain, prefer the active pane
- when no window name is provided, choose from all panes, again preferring the active pane
The hardening change matters here: specifying a window name no longer falls back silently to any active pane in the session. A wrong or stale window name is treated as a probe failure instead of selecting an arbitrary pane.
Process Inspection¶
PaneProcessInspector in ../../../../src/houmao/server/tui/process.py determines whether the supported TUI process is actually running inside the tracked pane.
It works by:
- reading the live process table from
ps -ax - walking descendants from the tmux pane root pid
- matching descendants against a tool-specific expected process-name list
This yields one of four important process states:
tui_up: a supported tool process is present in the pane treetui_down: tmux is live but the supported tool process is absentunsupported_tool: the server has no configured process matcher for that toolprobe_error: the pane pid is invalid orpsinspection failed
This is the boundary that keeps stale tmux scrollback from being mistaken for a live tool process.
Probe Snapshot¶
Every cycle can record a HoumaoProbeSnapshot.
Before capture, it contains:
observed_at_utcpane_idpane_pidmatched_process_names
After a successful tmux capture, the service updates the snapshot with:
captured_text_hashcaptured_text_lengthcaptured_text_excerpt
The excerpt is intentionally bounded to the last 4000 characters so the live state contains useful evidence without turning the route payload into a full pane dump.
Official Parsing¶
OfficialTuiParserAdapter in ../../../../src/houmao/server/tui/parser.py is a thin adapter over the shared ShadowParserStack.
The server-side naming is intentionally different from the lower-level implementation:
- inside
houmao-server, this is the official parser boundary - under the hood, it still reuses the shared parser stack and parser presets already present in the repo
The parsing sequence is:
supports_tool(tool)checks whether the shared parser stack supports the tool.- On the first successful parse attempt for a tracker,
capture_baseline(tool, output_text)stores the parser baseline offset into the tracker. parse(tool, output_text, baseline_pos)runsShadowParserStack.parse_snapshot(...).- Parse failures are normalized through
as_shadow_parser_error(...)and exposed asHoumaoErrorDetail(kind="parse_error", ...). - Parse success is converted into
HoumaoParsedSurface.
HoumaoParsedSurface includes parser family and preset metadata, plus the parsed TUI surface fields that matter to live tracking:
availabilitybusiness_stateinput_modeui_contextnormalized_projection_textdialog_text,dialog_head, anddialog_tailanomaly_codesbaseline_invalidatedoperator_blocked_excerpt
Turn-Signal Detection¶
After tmux capture, LiveSessionTracker feeds the current raw output_text directly into the standalone shared tracker session. Parsed surface metadata remains server-owned and is not required by the tracker boundary, so parser success and tracker input are intentionally decoupled.
The detector layer now resolves inside the shared tracker modules, primarily ../../../../src/houmao/shared_tui_tracking/session.py, ../../../../src/houmao/shared_tui_tracking/registry.py, and the profile implementations under ../../../../src/houmao/shared_tui_tracking/apps/. It is responsible for:
- foundational surface observables such as
accepting_input,editing_input, andready_posture - current active-turn evidence that can come from more than visible spinner rows
- recognized interruption and narrow known-failure signatures
- success-candidate and success-blocker hints used by the shared settle logic
The shared tracker now selects detectors through a tracker-local app/profile registry:
- Claude uses closest-compatible semver-floor resolution across raw-text profiles
- Codex uses a raw-text Codex profile under the same tracker contract
- unsupported tools fall back to a conservative raw-text detector
This keeps tool/version selection inside the shared tracker module while still letting the public tracked-state contract expose one common surface / turn / last_turn model.
Observed tool version reaches that registry through tracked-session identity metadata. The live server reconstructs it primarily from manifest launch_policy_provenance.detected_tool_version, falls back to launch_plan.launch_policy_provenance.detected_tool_version when needed, and finally tolerates registration-only fallback metadata when manifest provenance is absent.
Recorded Outcomes¶
The poll loop distinguishes failures and partial successes explicitly instead of compressing them into one status.
Important cycle outcomes are:
- tmux missing:
transport_state="tmux_missing",process_state="unknown",parse_status="transport_unavailable", then stop the worker - tmux resolution failure:
probe_error.kind="tmux_probe_error", continue the worker - process inspection failure:
probe_error.kind="process_probe_error", continue the worker - unsupported tool:
process_state="unsupported_tool"andparse_status="unsupported_tool", continue the worker - TUI down:
process_state="tui_down"andparse_status="skipped_tui_down", continue the worker - tmux capture failure:
probe_error.kind="tmux_capture_error", continue the worker - baseline capture failure:
parse_error.kind="parse_baseline_error", continue the worker - parser failure:
parse_status="parse_error"with structuredparse_error, continue the worker - parse success:
parse_status="parsed"with a populatedparsed_surface
All of these outcomes still flow through LiveSessionTracker.record_cycle(...), so the server updates:
- low-level diagnostics
- parsed-surface evidence
- foundational
surfaceobservables - simplified
turnandlast_turn - generic stability
- recent transitions
This remains true even when the cycle ended in a probe or parse error. Parser failure stays explicit in diagnostics while the shared tracker still reduces from whatever raw tmux text was captured for that cycle.
Related Sources¶
../../../../src/houmao/server/service.py../../../../src/houmao/server/tui/transport.py../../../../src/houmao/server/tui/process.py../../../../src/houmao/server/tui/parser.py../../../../src/houmao/server/tui/tracking.py../../../../src/houmao/shared_tui_tracking/registry.py../../../../src/houmao/shared_tui_tracking/session.py