Skip to content

cmux-tui: status indicators (loading fields, owned auto-clear, terminal busy, cmux status) - #16819

Closed
lawrencecchen wants to merge 4 commits into
feat-cmux-nextfrom
feat-cmux-next-status-rust
Closed

lawrencecchen wants to merge 4 commits into
feat-cmux-nextfrom
feat-cmux-next-status-rust

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Status indicators, daemon and CLI side (plans/cmux-next/status-indicators.md section 5; spec decisions U5-U9). The app only renders; these are the facts it renders.

What changes

  • workspace_status.set takes optional state (busy|success|error|waiting|info), progress, style, ttl_ms, owner {pid, terminal, agent_session}, target_terminal, exit_code, duration_ms. Stored in the additive table workspace_status_meta (state/status_meta.rs). Callers that send only text, icon and color are unchanged, and their request fingerprint is the same as before.

  • The daemon removes an owned entry in its own commit (workspace_status.auto_clear, a state_upsert of the workspace status) when:

    • its TTL passes: one expiry thread sleeps until the earliest deadline, with backoff after a failed commit;
    • its owner terminal exits: the session host's exit subscription;
    • its owner process exits: kqueue NOTE_EXIT or pidfd.

    A process owner must be running, is accepted only from a trusted local connection (server.rs), and is recorded with the machine id and the kernel start time, so a reused pid never stands in for it. Watches resume at daemon start (state/status_owners.rs).

  • terminal-activity-v1: terminal records carry extra.busy {since_ms} while a shell command runs between OSC 133 C and D. A new prompt clears stale OSC 9;4 progress. An exited terminal publishes neither (terminal_activity.rs). The client applies the "show after N s" setting.

  • CLI (cli/status.rs, cli/command/state/status_flags.rs):

    • workspace status set takes --state, --progress 0.4|40%, --style, --ttl 30s, --pid, --owner terminal|none, --target-terminal, --exit-code and --duration-ms.
    • New shorthand cmux status set [KEY] --label T | clear [KEY] [--all] | list | run [--label] [--badge-ttl 8s] -- CMD.
    • run marks the entry busy, owned by its own pid, and runs CMD with the terminal's stdio. It forwards signals that another process sent, then records success or error with the exit code and duration. It exits with CMD's status, and re-raises CMD's terminating signal so a shell loop around it stops too.
    • The CLI never sends a notification. The app decides, from the duration and the terminal's visibility.
  • Catalog fields and binding descriptors are updated. The transport coverage test exercises every new field.

The owner's three changes from #16174 are applied:

  • the daemon validates owners;
  • the owner decides auto-clear in the same commit, with its own transaction;
  • terminal facts sit on the terminal record, and waits go under the terminal noun.

Not in this PR

  • cmux status wait KEY, and cmux terminal <term> wait --until idle|prompt. Both need a new connection-owned wait op. exit and output already exist as terminal <t> process wait and terminal <t> screen wait --pattern.
  • Agent-session-end auto-clear.
  • busy is not restored after a daemon restart: it shows idle until the next OSC 133 mark.
  • A terminal-owner watch holds the daemon while it blocks.

Verification (Blacksmith Testbox, Linux)

  • cargo test --locked for the whole workspace: all pass except session_shutdown_exits_an_interactive_detached_owner_client. That test flakes on the base commit too (1 of 6 failed there).
  • cargo clippy -p cmux-tui-core -p cmux-tui --all-targets -D warnings is clean.
  • cargo fmt --check is clean for this diff. The remaining diffs are in cmux-tasks from the base branch.
  • End to end with a built daemon:
    • cmux status run --label Tests --badge-ttl 2s -- sh -c 'sleep 2; exit 3' shows busy with a pid owner while it runs, then error with exit code 3 and duration 2001 ms. The CLI exits 3, and the entry is gone after 2 s.
    • printf '\e]9;4;1;40\a\e]133;C\a' in a terminal shows extra {busy: {since_ms}, progress: {state: normal, value: 40}}.
  • A review subagent checked correctness against OWNERSHIP-PRINCIPLES. Its findings are fixed in 152e55e.
  • macOS kqueue code is not run on the box (UNVERIFIED there).

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Adds loading-indicator metadata to workspace status entries with daemon-side auto-clear, plus a cmux status CLI and terminal busy facts from OSC 133 marks. Entries written by older clients (text/icon/color only) are unaffected, and the new data is stored in an additive table that older binaries ignore.

Status entries and auto-clear

  • workspace_status.set accepts optional state, progress, style, ttl_ms, owner (pid, terminal, agent session), target_terminal, exit_code, and duration_ms, persisted in a new workspace_status_meta table.
  • The daemon removes owned entries itself when the TTL passes (one expiry thread), the owner terminal exits, or the owner process exits, using kqueue/pidfd; process owners are recorded with their kernel start time and accepted only from trusted local connections.
  • Busy state is not restored after a daemon restart – the terminal shows idle until the next OSC 133 mark.

CLI and terminal facts

  • New cmux status set | clear | list | run: run marks the entry busy and owned by its own pid, runs the command with the terminal's stdio, records success or error with exit code and duration, propagates the child's exit status and signals, and keeps the entry for a configurable badge TTL (default 8s).
  • workspace status set gains matching flags (--state, --progress, --style, --ttl, --pid, --owner, --target-terminal, --exit-code, --duration-ms).
  • Terminal records publish extra.busy {since_ms} between OSC 133 C and D; exited terminals publish neither busy nor progress. A new prompt clears stale OSC 9;4 progress.

Written for commit 896d36f. Summary will update on new commits.

Review in cubic

lawrencecchen and others added 4 commits October 2, 2026 04:52
…ear; terminal busy facts

Loading indicators (plans/cmux-next/status-indicators.md section 5):
- workspace_status.set takes optional state (busy|success|error|waiting|info),
  progress, style, ttl_ms, owner {pid, terminal, agent_session},
  target_terminal, exit_code, duration_ms, stored in the additive table
  workspace_status_meta (state::status_meta); old callers stay plain lines.
- The daemon removes an owned entry in its own commit when the TTL passes
  (one expiry thread sleeping until the earliest deadline), the owner
  terminal exits (session host exit subscription) or the owner process exits
  (kqueue NOTE_EXIT / pidfd); watches resume at daemon start
  (state::status_owners). A process owner must be running, is accepted only
  from a trusted local connection (server) and is scoped to the machine id.
- terminal-activity-v1: terminal records carry extra.busy {since_ms} while a
  shell command runs between OSC 133 C and D; a new prompt clears stale OSC
  9;4 progress; an exited terminal publishes neither (terminal_activity).
- advertised_capabilities moved to server/capabilities.rs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ce status set

- workspace status set takes --state, --progress (0.4 or 40%), --style,
  --ttl (30s, 5m, 1500ms), --pid, --owner terminal|none, --target-terminal,
  --exit-code, --duration-ms (cli/command/state/status_flags.rs). Inside a
  cmux terminal the entry is owned by and about that terminal unless
  --owner none.
- cmux status set [KEY] --label T | clear [KEY] [--all] | list | run -- CMD
  (cli/status.rs): KEY defaults to cli:<terminal>; run marks the entry busy
  and owned by its own pid, runs CMD with the terminal's stdio, ignores
  SIGINT/SIGQUIT itself, forwards SIGTERM/SIGHUP, then records success or
  error with exit code and duration for --badge-ttl (default 8s) and exits
  with CMD's status (128 + signal). The app decides about notifications.
- Parity: the transport coverage test exercises every new catalog field;
  binding descriptors carry the new catalog sha.
- run_coderouter moved into cli/coderouter.rs (run_args); godfile baseline
  lowered for server.rs and cli.rs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…signals, routing)

From the review subagent:
- A process owner is recorded with its kernel start time
  (unix_process_scope::process_identity) and checked at resume, so a reused
  pid never stands in for the owner; process_is_running needs kill(pid,0)
  to succeed (no EPERM processes we cannot watch).
- A watch that cannot be armed or fails (kqueue EV_ERROR via EV_RECEIPT,
  pidfd ENOSYS, unsupported platform) keeps the entry instead of clearing
  it; terminal watches retry transient registry errors with backoff and
  clear only when the session host no longer knows the terminal. Process
  watches hold a Weak<Mux>.
- The expiry thread backs off after a failed commit instead of spinning on
  a past deadline.
- The owner-process check runs inside the commit, after the replay check:
  a retry of a committed set returns its stored result. A plain set keeps
  its old request fingerprint (meta skipped when plain).
- Activity facts are hidden only for exited and tombstoned terminals.
- Catalog: ttl_ms maximum 604800000.
- CLI: a plain status line from inside a terminal stays plain (no caller
  terminal); a set routed with --socket/--session drops the caller
  terminal; status run keys each write, forwards SIGINT/SIGQUIT only when
  another process sent them (si_pid) and SIGTERM/SIGHUP always, installs
  handlers before spawn, re-raises the child's terminating signal after
  the final write, clamps durations to uint32; status run rejects set
  flags with a clear message.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…at-cmux-next-acpmux

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: fac11ff7-29c9-4642-9d94-f03036d03e10

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@blacksmith-sh

blacksmith-sh Bot commented Oct 2, 2026

Copy link
Copy Markdown

Found 3 test failures on Blacksmith runners:

Failures

Test View Logs
test_wrong_event_stream_is_rejected (main.LiveSchemaTests.test_wrong_event_stream_i
s_rejected)/
test_wrong_event_stream_is_rejected (main.LiveSchemaTests.test_wrong_event_stream_i
s_rejected)
View Logs
test_wrong_request_field_presence_is_rejected (main.LiveSchemaTests.test_wrong_requ
est_field_presence_is_rejected)/
test_wrong_request_field_presence_is_rejected (main.LiveSchemaTests.test_wrong_requ
est_field_presence_is_rejected)
View Logs
test_wrong_request_field_type_is_rejected (main.LiveSchemaTests.test_wrong_request_
field_type_is_rejected)/
test_wrong_request_field_type_is_rejected (main.LiveSchemaTests.test_wrong_request_
field_type_is_rejected)
View Logs

Fix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

CI fast guards failed on 896d36f7db (https://github.com/manaflow-ai/cmux/actions/runs/37005001699). It does not block the merge; a red guard merged into main breaks it for every open PR.

Validate fleet compiler-cache wiring

Test: bash tests/test_ci_fleet_compilation_cache.sh

/home/runner/work/cmux/cmux/scripts/ci/compile-app-host-test-product.sh must pass COMPILATION_CACHE_ENABLE_DIAGNOSTIC_REMARKS=YES

Fix: the assertion above names what the guard expects; change the tree to match it.
Reproduce in seconds, no build: scripts/ci/guards-local.sh --step 'Validate fleet compiler-cache wiring'

Check that push and pull_request path filters agree

Test: python3 tests/test_ci_workflow_path_filter_parity.py

Traceback (most recent call last):
  File "/home/runner/work/cmux/cmux/tests/test_ci_workflow_path_filter_parity.py", line 152, in <module>
    test_push_and_pull_request_filter_the_same_files()
  File "/home/runner/work/cmux/cmux/tests/test_ci_workflow_path_filter_parity.py", line 110, in test_push_and_pull_request_filter_the_same_files
    assert not drifted, (
           ^^^^^^^^^^^
AssertionError: Every workflow that filters both events must filter them identically, or declare the difference in EXEMPTIONS with a reason.
backend.yml: push and pull_request filter different files
  paths: guarded on pull requests, not on push: .github/workflows/backend-migrations.yml

Fix: the assertion above names what the guard expects; change the tree to match it.
Reproduce in seconds, no build: scripts/ci/guards-local.sh --step 'Check that push and pull_request path filters agree'

Validate fork runner routing

Test: python3 tests/test_ci_fork_runner_routing.py

  • ForkRunnerRoutingTests.test_every_fork_exercised_runner_has_a_hosted_path (workflow='backend.yml', line=122)
AssertionError: False is not true : backend.yml:122 has no GitHub-hosted Linux fork branch
  • ForkRunnerRoutingTests.test_every_fork_exercised_runner_has_a_hosted_path (workflow='backend.yml', line=194)
AssertionError: False is not true : backend.yml:194 has no GitHub-hosted Linux fork branch
  • ForkRunnerRoutingTests.test_every_fork_exercised_runner_has_a_hosted_path (workflow='backend.yml', line=244)
AssertionError: False is not true : backend.yml:244 has no GitHub-hosted Linux fork branch
  • ForkRunnerRoutingTests.test_fork_pull_requests_into_manaflow_ai_never_reach_an_owned_runner_label
AssertionError: Lists differ: ["backend.yml:49 checks vars.LINUX_RUNNER [1243 chars] }}"] != []

First list contains 7 additional elements.
First extra element 0:
"backend.yml:49 checks vars.LINUX_RUNNER before the fork pull-request branch: runs-on: ${{ github.repository_owner != 'manaflow-ai' && 'ubuntu-24.04' || vars.LINUX_RUNNER || 'blacksmith-4vcpu-ubuntu-2404' }}"

Diff is 1382 characters long. Set self.maxDiff to None to see it.

... and 1 more failing tests in the run log.
Fix: the assertion above names what the guard expects; change the tree to match it.
Reproduce in seconds, no build: scripts/ci/guards-local.sh --step 'Validate fork runner routing'

Validate reusable guard workflow structure

  • Wiring.test_main_full_suite_admission_compiles_on_the_seed_pool_and_xcode
AssertionError: 'blacksmith-6vcpu-macos-15' != 'pool-pr'
- blacksmith-6vcpu-macos-15
+ pool-pr

Fix: the assertion above names what the guard expects; change the tree to match it.
Reproduce in seconds, no build: scripts/ci/guards-local.sh --step 'Validate reusable guard workflow structure'

Agents: python3 scripts/ci/guard_attribution.py fix applies the mechanical fixes locally. This comment is updated in place on each push.

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

CI failure attribution

CI failed on 896d36f7db (run 37005002055 attempt 1): 1 code, 3 unknown.

Job Verdict Why
Fast static checks code a static check failed
guards / workflow-guard-tests / preflight unknown no known signature; failed step: Validate Python test execution registry
guards / workflow-guard-tests / ci unknown no known signature; failed step: Propagate failed independent fast guard
guards / workflow-guard-tests / quality-determinism unknown no known signature; failed step: Validate test determinism gate
Matched log lines
Fast static checks: FAILED localization (0.32s)

Not re-run automatically: Fast static checks, guards / workflow-guard-tests / preflight, guards / workflow-guard-tests / ci, guards / workflow-guard-tests / quality-determinism are not machine failures.

Written by scripts/ci/classify_failures.py (ci-failure-attribution.yml); signatures are its SIGNATURES table. A machine verdict is the runner's fault, not this PR's.

Base automatically changed from feat-cmux-next-acpmux to feat-cmux-next October 3, 2026 01:21
@lawrencecchen

Copy link
Copy Markdown
Contributor Author

landed directly as cd79855 (merged into feat-cmux-next as dcd6621) (new feat-cmux-next rule)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant