Skip to content

Add credential-free Sprite base builder - #9618

Closed
lawrencecchen wants to merge 4 commits into
mainfrom
task-sprites-base-cmux-tui
Closed

lawrencecchen wants to merge 4 commits into
mainfrom
task-sprites-base-cmux-tui

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Aug 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • add a pinned Fly Sprite base-checkpoint builder for the cmux remote daemon
  • keep provider credentials, daemon identities, and enrollment secrets out of checkpoints
  • document direct Noise-authenticated enrollment and backend approval boundaries
  • let retained exited terminals adopt a reconnecting client's cell metrics

Testing

  • bash -n cmux-tui/scripts/build-sprite-base.sh
  • shellcheck cmux-tui/scripts/build-sprite-base.sh
  • real Sprite build produced clean checkpoint v1 with daemon state absent
  • enrolled an isolated device over the public WSS carrier
  • created a remote workspace and read CMUX_SPRITE_OK from its terminal
  • opened the actual cmux@0.9.11 TUI against the enrolled Sprite
  • reproduced the exited-surface convergence failure in a focused test, then passed it with the fix
  • rebuilt the daemon at dc935e5476, created clean checkpoint v3, and attached the actual TUI without the convergence error

Notes

  • Fly cross-Sprite drive forking remains beta and is not in the public REST API

@cursor

cursor Bot commented Aug 5, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a strict Bash script to create credential-free Fly Sprite cmux checkpoints. Adds documentation for Sprite setup, authentication, client enrollment, revocation, and public connections. Updates exited hosted-surface geometry handling and adds Unix regression coverage.

Changes

Fly Sprites support

Layer / File(s) Summary
Sprite build inputs and validation
cmux-tui/scripts/build-sprite-base.sh
The script parses options, validates credentials, tools, names, and cmux versions, and removes failed Sprites unless preservation is requested.
Sprite installation and checkpoint creation
cmux-tui/scripts/build-sprite-base.sh
The script creates and configures a Sprite, installs cmux, removes runtime state, creates a checkpoint, and optionally starts the service.
Sprite workflow and authentication documentation
cmux-tui/docs/sprites.md, cmux-tui/README.md, cmux-tui/docs/README.md
The documentation describes Sprite checkpoints, trust boundaries, credential handling, client enrollment, revocation, audit fields, and authenticated public connections. README indexes link to the new documentation.

Exited hosted-surface sizing

Layer / File(s) Summary
Exited hosted-surface geometry handling and regression test
cmux-tui/crates/cmux-tui-core/src/surface.rs, cmux-tui/crates/cmux-tui-core/src/mux.rs
Exited hosted surfaces now apply cell-pixel-size changes and commit geometry without a live PTY resize. A Unix-only test verifies that a 16×32 update reaches the exited host cell and surface.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Operator
  participant build-sprite-base.sh
  participant Sprite CLI
  participant Fly Sprite
  participant cmux-tui service
  Operator->>build-sprite-base.sh: provide options and SPRITE_TOKEN
  build-sprite-base.sh->>Sprite CLI: create Sprite and enable public URL
  Sprite CLI->>Fly Sprite: provision Sprite
  build-sprite-base.sh->>Fly Sprite: install pinned cmux
  build-sprite-base.sh->>cmux-tui service: register and stop service
  build-sprite-base.sh->>Fly Sprite: remove runtime state and create checkpoint
  build-sprite-base.sh->>cmux-tui service: optionally start service
  build-sprite-base.sh-->>Operator: print checkpoint metadata
Loading

Possibly related PRs

  • manaflow-ai/cmux#8717: Its mux.rs and surface.rs changes overlap with the exited hosted-surface sizing behavior tested here.
  • manaflow-ai/cmux#8769: Its surface.rs changes overlap with termination behavior for exited hosted runtimes.

Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (2 errors)

Check name Status Explanation Resolution
Cmux No Hacky Sleeps ❌ Error The new production shell script passes --duration 10s, forcing a fixed log-stream wait before stopping the service; no readiness signal controls this startup/state cleanup sequence. Remove the fixed duration and use --no-stream or a bounded, cancellation-aware readiness operation tied to the service owner’s actual completion signal before stopping and cleaning state.
Cmux User-Facing Error Privacy ❌ Error The new builder emits SPRITE_TOKEN is required, a sprites.dev install command, echoes unknown arguments, and forwards raw sprite CLI output to users. Use generic cmux errors with safe next actions; avoid echoing arbitrary arguments, capture and sanitize Sprite CLI output, and keep provider/env details in operator-only logs.
✅ Passed checks (23 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed The cumulative PR diff contains no Swift files; all changes are Rust, shell, and Markdown, so this Swift actor-isolation check is not applicable.
Cmux Swift Blocking Runtime ✅ Passed The complete PR range changes only Rust files; it introduces no production Swift code or Swift blocking/timing primitive.
Cmux Browser Automation Off-Main ✅ Passed The PR diff changes only Rust terminal geometry and regression-test code; it adds no browser.* socket command, WebKit/AppKit routing, worker command, or policy-test change.
Cmux Expensive Synchronous Load ✅ Passed The PR diff contains only Markdown, Bash, and Rust files; it adds no production Swift changes or synchronous agent-history loads covered by this check.
Cmux Cache Substitution Correctness ✅ Passed The full main-to-HEAD diff changes only Rust, Markdown, and Bash files; it contains no production Swift, TypeScript, or JavaScript changes covered by this check.
Cmux Algorithmic Complexity ✅ Passed The PR adds no nested scalable-collection scans. The shell loops parse fixed CLI/checkpoint metadata, Rust production changes add no collection traversal, and the new mux logic is test-only.
Cmux Swift Concurrency ✅ Passed The pull request changes only Markdown, shell, and Rust files; the complete commit range contains no Swift or Swift interface changes.
Cmux Swift @Concurrent ✅ Passed The PR diff contains only Rust, Bash, and Markdown files; it introduces no Swift paths or Swift concurrency annotations to assess.
Cmux Swift Package Boundaries ✅ Passed The PR range contains only Markdown, Bash, and Rust changes; it introduces no Swift source or SwiftPM package changes, so the boundary rule is not applicable.
Cmux Swiftpm Lockfiles ✅ Passed The full PR diff changes only cmux-tui docs, a Bash script, and Rust files; it contains no Package.swift, Package.resolved, Xcode project, .gitignore, workflow, or dependency changes.
Cmux Swift Logging ✅ Passed The complete PR diff changes no Swift files, so it adds or materially changes no production Swift logging.
Cmux Full Internationalization ✅ Passed The diff adds TUI Rust behavior/tests plus operational Sprite documentation and a provisioning script; it changes no Swift UI, localized web surface, catalog, or message file.
Cmux Swiftui State Layout ✅ Passed The PR changes only Markdown, Bash, and Rust files; it adds no Swift or SwiftUI code, so the SwiftUI state/layout rule is not applicable.
Cmux Architecture Rethink ✅ Passed The cumulative diff contains only Rust, shell, and Markdown files; it introduces no Swift architecture or Swift lifecycle changes covered by this rule.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed The PR diff contains no Swift, Objective-C, XIB, or storyboard changes, so it introduces no standalone Swift auxiliary window or close-shortcut violation.
Cmux Source Artifacts ✅ Passed The diff contains only docs, an executable build script, and Rust source/test changes; no logs, media, caches, temp/artifact directories, or copied binaries are added.
Cmux No Test Or Debug Seam In Production Source ✅ Passed The full PR diff contains no Swift files under a production Sources/ path; changes are limited to Rust, Markdown, and a shell script.
Cmux No Ambient Global State ✅ Passed The pull request changes only Markdown, Rust, and Bash files; it contains no Swift changes, so the Swift-only ambient-global-state check is not applicable.
Title check ✅ Passed The title clearly identifies the main change: adding a credential-free Fly Sprite base builder.
Description check ✅ Passed The description covers the changes, rationale, testing, notes, and behavior changes with specific verification details.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch task-sprites-base-cmux-tui

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmux-tui/docs/sprites.md`:
- Around line 57-63: Update the invitation-creation instructions around cmux
enroll create so the command executes inside the Sprite through authenticated
sprite exec, using the specified organization and Sprite, before returning the
invitation; preserve the existing state directory and enrollment arguments.

In `@cmux-tui/scripts/build-sprite-base.sh`:
- Around line 143-148: Update the build metadata output in the script’s
reporting block to emit the required tagged localhost report link at
http://127.0.0.1:17320/<tag>. Derive the URL from the existing build tag value,
and preserve the current metadata lines without substituting a file:// URL or
local artifact path.
- Around line 69-71: Update the missing-credential error in
build-sprite-base.sh’s SPRITE_TOKEN validation to use product-level wording
without exposing the SPRITE_TOKEN environment-variable name. Keep the stderr
output and exit status unchanged, and instruct users to source the authorized
credential file before retrying.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d3d133f0-c649-4f2e-98ab-3e1b4f1173e3

📥 Commits

Reviewing files that changed from the base of the PR and between a2b3c10 and 291a10f.

📒 Files selected for processing (4)
  • cmux-tui/README.md
  • cmux-tui/docs/README.md
  • cmux-tui/docs/sprites.md
  • cmux-tui/scripts/build-sprite-base.sh

Comment thread cmux-tui/docs/sprites.md
Comment on lines +57 to +63
cmux enroll create \
--session sprite \
--state-dir /home/sprite/.local/share/cmux-sprite/remote \
--advertise wss://<sprite-host>/v1/link \
--ttl 300 \
--json
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Run invitation creation inside the Sprite.

This block runs cmux enroll create on the reader host, but --state-dir /home/sprite/... identifies daemon state inside the Sprite. The command will target a local admin socket or fail. Wrap this command in authenticated sprite exec -o <org> -s <sprite> -- ..., or state that the backend performs that exact operation before it returns the invitation.

The later approval step already specifies authenticated Sprite exec. The creation step needs the same execution boundary.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmux-tui/docs/sprites.md` around lines 57 - 63, Update the
invitation-creation instructions around cmux enroll create so the command
executes inside the Sprite through authenticated sprite exec, using the
specified organization and Sprite, before returning the invitation; preserve the
existing state directory and enrollment arguments.

Comment on lines +69 to +71
if [[ -z "${SPRITE_TOKEN:-}" ]]; then
echo "SPRITE_TOKEN is required" >&2
exit 2

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the referenced script around the reported validation and the surrounding
# output behavior without executing repository code.
if [ -f cmux-tui/scripts/build-sprite-base.sh ]; then
  nl -ba cmux-tui/scripts/build-sprite-base.sh | sed -n '1,140p'
  printf '\n--- occurrences of SPRITE_TOKEN ---\n'
  rg -n 'SPRITE_TOKEN|sprite|echo ".*error|>&2' cmux-tui/scripts/build-sprite-base.sh || true
else
  printf 'Referenced file not found\n'
fi

printf '\n--- shell syntax safety probe ---\n'
sh -n cmux-tui/scripts/build-sprite-base.sh && echo "syntax ok" || echo "syntax error"

Repository: manaflow-ai/cmux

Length of output: 194


Information Disclosure (CWE-209): Generation of Error Message Containing Sensitive Information

Reachability: Internal

Do not expose the credential environment-variable name in the error.

The script writes SPRITE_TOKEN is required to stderr, which exposes a credential configuration name to callers who run the script without credentials. Use product-level text instead, such as “A Sprite management credential is required. Source the authorized credential file and retry.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmux-tui/scripts/build-sprite-base.sh` around lines 69 - 71, Update the
missing-credential error in build-sprite-base.sh’s SPRITE_TOKEN validation to
use product-level wording without exposing the SPRITE_TOKEN environment-variable
name. Keep the stderr output and exit status unchanged, and instruct users to
source the authorized credential file before retrying.

Source: Coding guidelines

Comment on lines +143 to +148
printf '\nSPRITE_BASE_ORG=%s\n' "$org"
printf 'SPRITE_BASE_NAME=%s\n' "$name"
printf 'SPRITE_BASE_CHECKPOINT=%s\n' "$checkpoint"
printf 'SPRITE_BASE_CMUX_VERSION=%s\n' "$cmux_version"
printf 'SPRITE_BASE_DAEMON_STATE=absent\n'
printf 'SPRITE_BASE_SERVICE=%s\n' "$([[ "$keep_running" -eq 1 ]] && echo running || echo stopped)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Report the checkpoint build with the required tagged link.

Lines 143-148 report build metadata but do not emit http://127.0.0.1:17320/<tag>. Add the required tagged build-report link. Do not replace it with a file:// URL or a local artifact path.

As per coding guidelines, shell builds must use the tagged localhost report link.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmux-tui/scripts/build-sprite-base.sh` around lines 143 - 148, Update the
build metadata output in the script’s reporting block to emit the required
tagged localhost report link at http://127.0.0.1:17320/<tag>. Derive the URL
from the existing build tag value, and preserve the current metadata lines
without substituting a file:// URL or local artifact path.

Source: Coding guidelines

@cursor

cursor Bot commented Aug 5, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmux-tui/crates/cmux-tui-core/src/mux.rs`:
- Around line 16220-16225: The test setup around
insert_terminal_identity_surface must create the “exited-cell-pixels” workspace
in the empty test_mux state before projecting the terminal. Capture the created
workspace and pass its workspace.key instead of the literal workspace
identifier, preserving the existing projection and set_cell_pixel_size flow.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 86798f76-e09d-47bd-8094-9be2b591483a

📥 Commits

Reviewing files that changed from the base of the PR and between 291a10f and 1d28748.

📒 Files selected for processing (1)
  • cmux-tui/crates/cmux-tui-core/src/mux.rs

Comment on lines +16220 to +16225
let surface = insert_terminal_identity_surface(
&mux,
"00112233445566778899aabbccddeeff",
"11111111111111111111111111111111",
"exited-cell-pixels",
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

file="cmux-tui/crates/cmux-tui-core/src/mux.rs"
rg -n -C 8 \
  'fn test_mux|insert_terminal_identity_surface|project_terminal_to_workspace_in_state|exited_host_cell_pixels_converge_without_a_live_host' \
  "$file"

Repository: manaflow-ai/cmux

Length of output: 11417


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

file="cmux-tui/crates/cmux-tui-core/src/mux.rs"

echo "project_terminal_to_workspace_in_state implementation:"
sed -n '12192,12310p' "$file" | cat -n

echo
echo "create_empty_workspace implementation:"
rg -n -C 12 'fn create_empty_workspace|pub fn create_empty_workspace|create_empty_workspace<' "$file"

echo
echo "workspace_registry field and init:"
rg -n -C 6 'workspace_registry:|workspace_registry:' "$file" | head -n 220

Repository: manaflow-ai/cmux

Length of output: 19180


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
p = Path("cmux-tui/crates/cmux-tui-core/src/mux.rs")
text = p.read_text()

checks = [
    ("unknown workspace key error in projection", 'fn project_terminal_to_workspace_in_state'),
    ("workspace lookup before allocation in projection", 'state.workspaces[destination]').count('state.workspaces[destination]'),
    ("project_terminal_to_workspace_in_state returns an error when workspace key is missing", 'state.workspaces[destination].ok_or_else(|| anyhow::anyhow!("unknown workspace key {workspace_key}"))?', 'state.workspaces[destination].ok_or_else(|| anyhow::anyhow!("unknown workspace key {workspace_key}"))?'),
]
for name, needle in [("unknown workspace key error in projection", '!state.workspaces.iter().all(|workspace| workspace.key != workspace_key)'), ("missing workspace exact error", 'state.workspaces[destination].ok_or_else(|| anyhow::anyhow!("unknown workspace key {workspace_key}"))?'), ("projection allocation before project_resource", 'project_resource')]
:
    # This is just a quick scan helper
    pass
PY

Repository: manaflow-ai/cmux

Length of output: 929


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
import re

text = Path("cmux-tui/crates/cmux-tui-core/src/mux.rs").read_text()

# Locate the exact projection body text.
start = text.index("fn project_terminal_to_workspace_in_state(")
end = text.index("/// Move an existing tab", start)
proj = text[start:end]

checks = {
    "projection exists": True,
    "early no-existing-terminal unknown workspace check": '!state.workspaces.iter().all(|workspace| workspace.key != workspace_key)' in proj,
    "main workspace exists check before allocation": 'state.workspaces[destination].ok_or_else(|| anyhow::anyhow!("unknown workspace key {workspace_key}"))?' in proj,
    "uses existing workspace's active screen/pane when available": "state.workspaces[destination].active_screen_ref().map(|screen| screen.active_pane)" in proj,
    "allocates a pane and screen only after selected existing workspace": "state.workspaces[destination].screens.push(Screen" in proj,
    "allocated destination matches projected workspace": "state.workspaces[destination].screens.push(Screen" in proj and proj.index("state.workspaces[destination].screens.push(Screen") > proj.index("return Ok((Some(current), false));"),
}

for key, result in checks.items():
    print(f"{key}: {result}")

if not all(checks.values()):
    raise SystemExit(1)

for line_no, line in enumerate(proj.splitlines(), 1):
    if "ok_or_else" in line and "unknown workspace key" in line:
        print("workspace_error_line:", line_no, line.strip())
PY

Repository: manaflow-ai/cmux

Length of output: 484


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

file="cmux-tui/crates/cmux-tui-core/src/mux.rs"

echo "Relevant error checks:"
rg -n -C 3 'unknown workspace|all\(workspace|all\(|Position' "$file"

echo
echo "Projection source:"
sed -n '12192,12245p' "$file" | cat -n

echo
echo "Project helper source around workspace selection:"
sed -n '8410,8445p' "$file" | cat -n

Repository: manaflow-ai/cmux

Length of output: 24776


Create the passed workspace before projecting into it.

project_terminal_to_workspace_in_state requires the workspace key to exist at cmux-tui/crates/cmux-tui-core/src/mux.rs:12208 and cmux-tui/crates/cmux-tui-core/src/mux.rs:12217; passing "exited-cell-pixels" into the empty test_mux() state makes projection fail before set_cell_pixel_size runs. Create the workspace and pass the returned workspace.key.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmux-tui/crates/cmux-tui-core/src/mux.rs` around lines 16220 - 16225, The
test setup around insert_terminal_identity_surface must create the
“exited-cell-pixels” workspace in the empty test_mux state before projecting the
terminal. Capture the created workspace and pass its workspace.key instead of
the literal workspace identifier, preserving the existing projection and
set_cell_pixel_size flow.

@lawrence703

Copy link
Copy Markdown
Collaborator

Closing this obsolete Sprite branch. Head dc935e547637e31812084497d8e27e1d6bedca15 adds a Fly Sprite checkpoint builder that is absent from current main, and the current cloud intent marks the snapshot path no-go.
Its exited-terminal cell-metric behavior is already present in current main (the convergence test is attributed to merged PR 9387). Related PR 9626 is an old/open Sprite workflow, not a validated successor. If Sprite support returns, open a new current-main design with authenticated in-Sprite enrollment and secret redaction. No unique safe delta is retained here.

@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Closing as obsolete. The Sprite checkpoint-builder path is no longer the accepted cloud direction. Its exited-terminal cell-metric behavior is already present via merged #9387; no unique implementation remains here.

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.

2 participants