Skip to content

feat(runtime): fail-closed confine, optional boxlite, PTY, trajectory - #85

Merged
undivisible merged 13 commits into
mainfrom
cursor/feat-harness-steals-64f4
Sep 4, 2026
Merged

feat(runtime): fail-closed confine, optional boxlite, PTY, trajectory#85
undivisible merged 13 commits into
mainfrom
cursor/feat-harness-steals-64f4

Conversation

@undivisible

@undivisible undivisible commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Apollo-side harvest of harness isolation and exec session hooks. rx4 is pinned to rotary 3aab31e794a49f9d2ae399232441439ae3f35823 (default-features = false, features providers, skills, graph-memory). No second engine.

What landed

  • Fail-closed confine(argv) around shell/exec, with explicit runner vs denial dialects. Empty argv, catastrophic commands, and a missing isolator are denials. There is no silent pass-through of an unconfined argv.
  • Optional isolation behind the empty boxlite cargo feature (off by default; not a crate). Default runtime stays host bash -c. When isolation is required and the isolator is missing (APOLLO_BOXLITE / configured path / boxlite on PATH), confine denies.
  • PTY worker for exec process_id / write_stdin, wired through ShellTool and RotaryAgentBridge.
  • Trajectory subscription in rotary_bridge: tool start/end, guardrail warning/stop, errors, budget, RetryReason, ProcessStdin, RequestPermissions, PatchHunk, SelfHealing (recovery), and spill (locator parsed from rotary's truncated ToolExecutionEnd preview). tests/rx4_engine.rs covers a real turn, escalate fail-closed, and spill.

Review fixes

  • Confine once on the PTY/stdin path. PtyWorker::spawn accepts an already-confined ConfineOutcome and does not call confine again, so Isolation::Required wraps the isolator exactly once. Covered by unit tests with a fake isolator binary.
  • Production bridge PTY. run_via_rotary / RotaryAgentBridge::new attach the shell PtyWorker via runtime_pty_worker. bridge.write_stdin hits that worker. rx4_bridge_write_stdin_uses_the_pty_worker now drives bridge.write_stdin on the rotary construction path.

CI / deps

  • rs_ai* stays on published 0.2.31. Local catalog env-key lookup replaces rs_ai_providers::catalog.
  • Packed vector decode uses as_chunks for clippy 1.98 -D warnings.
  • Branch is merged with current main. No remaining conflict.

Validation

cargo fmt --all -- --check
cargo check -p apollo-agent --offline --locked
cargo test -p apollo-agent --test rx4_engine
cargo test -p apollo-agent --lib tools::confine tools::pty_worker tools::shell

MPL-2.0. No secrets.

Device-first

This stays on the local bot path: apollo still owns everything around the rx4 loop.

Open in Web Open in Cursor 

cursoragent and others added 2 commits September 2, 2026 14:14
Add confine(argv) around exec with explicit runner vs denial dialects
and no silent pass-through. Optional boxlite isolation stays off by
default and denies when required isolation cannot find an isolator.
Give exec a PTY worker for process_id / write_stdin, and subscribe
rx4 ToolExecution and guardrail events into existing trajectory
recording through rotary_bridge.

Co-authored-by: Max Carter 祁明思 <max@tsc.hk>
Restore the main-branch rs_ai pin so this change does not mix a
dependency downgrade into the runtime work.

Co-authored-by: Max Carter 祁明思 <max@tsc.hk>
@undivisible
undivisible marked this pull request as ready for review September 2, 2026 14:16
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@cursor

cursor Bot commented Sep 2, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_27f119c2-7a36-4fe4-a3a3-e4973778c07e)

@mergify

mergify Bot commented Sep 2, 2026

Copy link
Copy Markdown

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

cursoragent and others added 6 commits September 2, 2026 14:23
crates.io has no 0.2.32, so clippy (unlocked) failed to resolve
^0.2.32. Keep the lockfile pin and replace catalog::find/env_key
with a local lookup for the providers apollo actually constructs.

Co-authored-by: Max Carter 祁明思 <max@tsc.hk>
clippy 1.98 denies chunks_exact with a constant size under
-D warnings, which is the CI gates command.

Co-authored-by: Max Carter 祁明思 <max@tsc.hk>
Keep published rs_ai 0.2.31 and as_chunks decode. Take main's
MCP dead-code and scheduler cycle-detection fixes.

Co-authored-by: Max Carter 祁明思 <max@tsc.hk>
Keep default-features = false with providers, skills, and
graph-memory. Leave rs_ai_providers on published 0.2.31.

Co-authored-by: Max Carter 祁明思 <max@tsc.hk>
Subscribe RetryReason, ProcessStdin, RequestPermissions, PatchHunk,
and SelfHealing into the existing trajectory recorder. Escalate
denies stay fail-closed at GitReadOnly.

Co-authored-by: Max Carter 祁明思 <max@tsc.hk>
Rotary has no Spill event; it rewrites ToolExecutionEnd content
with a locator footer. Parse that footer and record action spill.

Co-authored-by: Max Carter 祁明思 <max@tsc.hk>
@cursor

cursor Bot commented Sep 2, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_61a5b13d-3a78-4137-b20c-2814aba3e499)

cursoragent and others added 4 commits September 2, 2026 15:22
Keep default-features = false with providers, skills, and
graph-memory. Trajectory already records RetryReason,
ProcessStdin, and RequestPermissions on this Event shape.

Co-authored-by: Max Carter 祁明思 <max@tsc.hk>
Keep default-features = false with providers, skills, and
graph-memory. Trajectory event recording is unchanged.

Co-authored-by: Max Carter 祁明思 <max@tsc.hk>
Keep default-features = false with providers, skills, and
graph-memory. Trajectory event recording is unchanged.

Co-authored-by: Max Carter 祁明思 <max@tsc.hk>
PtyWorker now accepts an already-confined ConfineOutcome::Runner and
does not wrap isolation again. run_via_rotary attaches the shell
PtyWorker so bridge.write_stdin reaches the live exec session.

Co-authored-by: Max Carter 祁明思 <max@tsc.hk>
@cursor

cursor Bot commented Sep 4, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_86d11142-6925-4bb2-96db-6fd92a863129)

Keep default-features = false with providers, skills, and
graph-memory. Trajectory event recording is unchanged.

Co-authored-by: Max Carter 祁明思 <max@tsc.hk>
@undivisible
undivisible merged commit a46909c into main Sep 4, 2026
3 checks passed
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