Skip to content

fix: focus spawned agent surfaces before launch - #353

Merged
EtanHey merged 6 commits into
mainfrom
fix/spawn-focus-pane
Aug 5, 2026
Merged

fix: focus spawned agent surfaces before launch#353
EtanHey merged 6 commits into
mainfrom
fix/spawn-focus-pane

Conversation

@EtanHey

@EtanHey EtanHey commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Summary

  • focus the exact surface returned by role-driven agent placement before launcher I/O
  • preserve the existing focus lease so normal spawns restore the exact origin and focus:true stays on the new tab
  • fail immediately with agent_id, surface_id, and workspace_id if the created tab cannot be focused
  • cover orchestrator/worker placement from both lead and worker focus origins

Verification

  • full suite: 106 files, 2,380 tests passed (baseline 2,375; +5 contracts)
  • focused lifecycle suite: 485 tests passed
  • npm run pre-pr: 63 tests passed
  • npm run typecheck
  • npm run build
  • git diff --check
  • local CodeRabbit review completed; one minor lease suggestion was checked and rejected because the current lease already spans preflight/failure and focus:true intentionally disables restoration
  • real cmux probe: worker surface:381 in right-column pane:24 spawned orchestrator Claude surface:402, reached ready, restored surface:381, and cleaned up the probe

Scope

No release or installed-runtime change; the lead owns release/reconnect.


Note

Medium Risk
Changes spawn and focus lifecycle across agent engine, MCP tools, and app-server bridge; mistakes could break boot or steal focus, but behavior is gated by leases, epochs, and extensive new tests.

Overview
Fixes agent spawn when the new tab sits in an unfocused pane by calling focusSurface on the created surface in AgentEngine.spawnAgent before launcher/readiness I/O. Focus failures surface as AgentLaunchError with agent_id, surface_id, and workspace so the tab stays recoverable.

spawn_agent documents transient focus during init and adds focus (default false): when false, the existing focus-restore lease runs; when true, focus stays on the new tab. capturePostCreationFocus now keys the lease off the created surface from on_surface_created instead of re-querying focus.

focus_surface is threaded through the engine client, app-server runtime (with beforeMutation epoch checks), and server agent_engine wrapper, and is registered as a mutating tool in manual mode.

App Server bridge startThread snapshots origin focus before spawn and restores it in finally only if focus is still on the new tab and policy/observer state unchanged (skips if the user moved, manual mode blocks, or observer reconnects).

Reviewed by Cursor Bugbot for commit 6ad53ae. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Focus spawned agent surfaces before launch and restore origin focus after initialization

  • AgentEngine.spawnAgent now explicitly focuses the newly created surface before any shell/readiness I/O; if focusing fails, it rejects with AgentLaunchError including the surface identity.
  • After a thread spawns, CmuxAppServerRuntime.startThread restores the prior focus target unless the user moved focus, the observer epoch changed, or workspace mutation policy forbids it.
  • The spawn_agent tool adds a focus boolean parameter (default false); setting it to true keeps focus on the created tab instead of restoring the origin.
  • focus_surface is added to MUTATING_TOOLS, blocking it in manual mode.
  • Behavioral Change: spawning an agent now transiently steals focus for initialization, then restores the caller's surface by default.

Macroscope summarized 6ad53ae.

Summary by CodeRabbit

  • New Features

    • Added optional focus control when creating agent surfaces.
    • Newly created surfaces are focused before initialization completes.
    • Original focus is restored automatically when appropriate.
    • Spawn responses now identify the created surface and support reliable focus behavior.
  • Bug Fixes

    • Improved handling of focus failures with actionable launch errors.
    • Prevented focus restoration when the current context has changed or manual mode blocks the operation.
  • Tests

    • Expanded coverage for focus, restoration, failure handling, and mode restrictions.

@cursor

cursor Bot commented Aug 3, 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_8462b02c-5933-44c9-a9ec-8bafc88df6d4)

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Agent creation now focuses the exact created surface before callbacks and readiness checks. Spawn tools track that surface, support a focus option, and restore the origin focus when valid. Restoration is guarded by observer state and mutation policy.

Changes

Surface Focus Lifecycle

Layer / File(s) Summary
Agent surface focus contract
src/agent-engine.ts, tests/agent-engine.test.ts, tests/agent-hierarchy.test.ts, tests/quality-tracking.test.ts
The engine client supports focusSurface. spawnAgent focuses the created surface before on_surface_created and preserves identity in focus errors.
Runtime focus capture and restoration
src/app-server-runtime.ts, src/mode-policy.ts, tests/app-server-runtime.test.ts, tests/mode-policy.test.ts
The runtime captures and restores focus when the observer epoch and current focus remain valid. focus_surface follows mutation policy.
Spawn tool focus behavior
src/server.ts, tests/server-agent-tools.test.ts, tests/server.test.ts, tests/spawn-workspace.test.ts, tests/daemon.test.ts
Spawn tools track created surfaces, expose focus, guard focus mutations, and test restoration, retention, readiness ordering, and focus failures.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant spawn_agent
  participant AgentEngine
  participant cmux
  Caller->>spawn_agent: request agent with optional focus
  spawn_agent->>AgentEngine: spawn agent
  AgentEngine->>cmux: focus created surface
  AgentEngine-->>spawn_agent: return created surface identity
  spawn_agent->>cmux: restore origin surface when focus is unchanged
  spawn_agent-->>Caller: return agent and surface result
Loading

Possibly related PRs

Poem

A rabbit watched the new tab glow,
The engine focused where agents go.
It saved the path back home again,
Unless the user moved the pen.
“Hop!” said the hare, “the focus is clear!”

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: focusing spawned agent surfaces before launch.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/spawn-focus-pane

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.

@EtanHey

EtanHey commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@EtanHey

EtanHey commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

@greptileai review

@EtanHey

EtanHey commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

@BugBot review

@cursor

cursor Bot commented Aug 3, 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_6325518a-bd90-475e-a63b-691ccf6c8ce7)

Comment thread src/app-server-runtime.ts
Comment thread src/agent-engine.ts

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0a5e14d1bf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/agent-engine.ts
Comment thread src/app-server-runtime.ts Outdated
@cursor

cursor Bot commented Aug 3, 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_1794ab8f-2680-49fc-8af2-2feb5915b72d)

@EtanHey

EtanHey commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

@codex review exact head b457af3

@EtanHey

EtanHey commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

@greptileai review exact head b457af3

@EtanHey

EtanHey commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

Review round 2: one valid manual-mode finding fixed at b457af3; the requested cleanup on focus failure is intentionally rejected because the contract requires a live created surface ID for caller recovery. Please review the exact current head.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b457af39f0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/agent-engine.ts
Comment on lines 4654 to 4657
await spawnParams.on_surface_created?.({
surface: surface.surface,
workspace: surface.actual_workspace ?? surface.workspace,
workspace: createdWorkspace,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve the lease when reporting the focused surface

When the focus RPC succeeds but the subsequent currentFocusTarget() call in spawn_agent's on_surface_created callback cannot obtain an exact surface—for example, during a transient identify/workspace-enumeration failure—capturePostCreationFocus returns null and overwrites the existing lease, so the default focus:false path never restores the origin and leaves the new tab focused. The same re-observation can capture a user's focus change made immediately after this RPC and later undo it. Use the exact surface and workspace already passed to the callback as the lease's expected target rather than discarding or re-observing it.

AGENTS.md reference: AGENTS.md:L44-L47

Useful? React with 👍 / 👎.

@cursor

cursor Bot commented Aug 3, 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_935f5743-4bdd-43e7-ab32-8ce90a1f13d2)

@EtanHey

EtanHey commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

@codex review exact head d13d943

@EtanHey

EtanHey commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

@greptileai review exact head d13d943

@EtanHey

EtanHey commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

Final review iteration (3/3): app-server exact-origin restoration and user-move/observer-reconnect guards added at d13d943; all four prior threads have dispositions and are resolved. Please review this exact head.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d13d943372

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/app-server-runtime.ts Outdated
Comment on lines +446 to +447
on_surface_created: async () => {
createdFocus = await this.currentFocusTargetBestEffort();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use the callback's exact surface for the focus lease

When identify() transiently fails after the engine has focused the new tab, this second observation leaves createdFocus null, so the finally block cannot restore the origin; if the user moves focus between the focus RPC and this observation, their target is instead recorded as the expected target and may later be pulled back to the old origin. The fresh evidence at exact head d13d943 is that the newly added app-server callback ignores the exact { surface, workspace } already supplied by on_surface_created; store those callback arguments directly rather than re-querying global focus.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in b455eda. The app-server lease now binds expected focus directly to the exact {surface, workspace} passed by on_surface_created, so it cannot lose the lease on identify failure or mistake a rapid user move for cmuxlayer-created focus. The RED regression now permits exactly two identify calls (origin + restore check) and covers both restore and user-move paths; pre-push passed 2,382/2,382.

Comment thread src/app-server-runtime.ts
Comment thread src/app-server-runtime.ts
Comment thread src/app-server-runtime.ts
@cursor

cursor Bot commented Aug 3, 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_5cd1f0f6-9b7c-4b13-88da-97b686d7f93f)

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b455eda5c9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/app-server-runtime.ts
Comment on lines +464 to +468
} finally {
await this.restoreFocusIfUnmovedBestEffort(
priorFocus,
createdFocus,
observerEpoch,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Serialize focus restoration across concurrent starts

When two thread/start requests overlap, these independent leases can restore to another newly created tab instead of the user's original surface. The async line listener in src/app-server-index.ts:39-49 does not serialize requests: if A captures origin O and focuses A, then B captures A and focuses B, A finishes first and skips restoration because B is focused, and B later restores to A, permanently losing O. Serialize the focus-changing portion of thread creation or coordinate nested leases so the outer origin is restored.

Useful? React with 👍 / 👎.

@EtanHey

EtanHey commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

PARKED at the brief's iteration cap. Final local head 48b9215 contains the exact-handle lease, observer-epoch recheck, and manual-mode restore fixes, but the mandatory pre-push hook blocks on the known cross-repo baseline: local golem-dispatch is still claude-opus-4-8[1m] while cmuxlayer canon pins claude-opus-5[1m]. This fails identically on clean main and was independently reported on PR #352. I did not bypass or weaken the gate. Remote head remains b455eda. Exact unblock: land a clean canon-compliant golems launcher pin, rerun the hook, push 48b9215, re-review exact head, then merge. Full details are reported to @cmuxlayer in FLEET-STANDING.md. Installed runtime remains 0.4.19; no release was attempted.

@cursor

cursor Bot commented Aug 3, 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_2131a861-ee2a-4779-b3a8-3a7fcb624154)

Comment thread src/app-server-runtime.ts
prompt: `App Server bridge session for ${repo}`,
...(workspace ? { workspace } : {}),
});
const priorFocus = await this.currentFocusTargetBestEffort();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium src/app-server-runtime.ts:435

startThread captures priorFocus per call, so overlapping thread starts can restore the wrong surface and leave the user's original focus lost. If start A captures the user's focus and moves focus to A's new surface, then start B captures A's surface as priorFocus and moves focus to B's surface, A's restoreFocusIfUnmovedBestEffort sees B's surface instead of A's (focus moved) and skips restoration, then B restores A's surface — the user's original focus is never restored even though the user never moved focus themselves.

The per-call priorFocus/createdFocus lease only tracks what each individual start observed, not the globally prior focus. Consider using a shared focus-restore queue or a single instance-level "original user focus" reference that only the first start captures, so later overlapping starts don't overwrite the baseline.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @src/app-server-runtime.ts around line 435:

`startThread` captures `priorFocus` per call, so overlapping thread starts can restore the wrong surface and leave the user's original focus lost. If start A captures the user's focus and moves focus to A's new surface, then start B captures A's surface as `priorFocus` and moves focus to B's surface, A's `restoreFocusIfUnmovedBestEffort` sees B's surface instead of A's (focus moved) and skips restoration, then B restores A's surface — the user's original focus is never restored even though the user never moved focus themselves.

The per-call `priorFocus`/`createdFocus` lease only tracks what each individual start observed, not the globally prior focus. Consider using a shared focus-restore queue or a single instance-level "original user focus" reference that only the first start captures, so later overlapping starts don't overwrite the baseline.

Comment thread src/app-server-runtime.ts

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 48b9215b45

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/agent-engine.ts
Comment on lines +4647 to +4649
await this.client.focusSurface(surface.surface, {
workspace: createdWorkspace,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Apply the initialization focus during crash recovery

When an errored agent is automatically respawned into a pane that is not selected, recoverCrashedAgents() creates the replacement surface at line 2922 and proceeds directly to sendLaunchCommand() at line 2984 without executing this new focus-before-I/O step. Given the terminal behavior documented immediately above this call—an unfocused tab does not initialize—the resume command can time out, consume recovery attempts, and leave the persistent agent in error. Share this focus prerequisite with the crash-recovery creation path as well.

AGENTS.md reference: AGENTS.md:L29-L34

Useful? React with 👍 / 👎.

@EtanHey
EtanHey force-pushed the fix/spawn-focus-pane branch from 48b9215 to be8b7b6 Compare August 5, 2026 04:52
@cursor

cursor Bot commented Aug 5, 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_4d15bf05-0275-422a-8960-e9e1b54e5be3)

@EtanHey

EtanHey commented Aug 5, 2026

Copy link
Copy Markdown
Owner Author

@codex review exact head be8b7b6

@EtanHey

EtanHey commented Aug 5, 2026

Copy link
Copy Markdown
Owner Author

@greptileai review exact head be8b7b6

@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: 2

🤖 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 `@src/agent-engine.ts`:
- Around line 673-676: Update AgentEngineClient.focusSurface to accept an
observer-bound pre-mutation callback and invoke it immediately before the client
mutation. In spawnAgent, pass the target surface’s observerEpoch to validate the
creation observer before focusing. Preserve existing focus behavior while
preventing a reconnect from applying the mutation to a different cmux instance.

In `@src/app-server-runtime.ts`:
- Around line 703-725: The restoration path around
assertWorkspaceMutationAllowed must revalidate focus immediately before
client.focusSurface. Call currentFocusTargetBestEffort again after the policy
lookup, and return without restoring unless it still matches expected.workspace
and expected.surface; add coverage where identify() changes focus during the
manual-mode lookup.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f289b71d-1882-412c-98b8-256f0dba7f49

📥 Commits

Reviewing files that changed from the base of the PR and between e67a556 and be8b7b6.

📒 Files selected for processing (13)
  • src/agent-engine.ts
  • src/app-server-runtime.ts
  • src/mode-policy.ts
  • src/server.ts
  • tests/agent-engine.test.ts
  • tests/agent-hierarchy.test.ts
  • tests/app-server-runtime.test.ts
  • tests/daemon.test.ts
  • tests/mode-policy.test.ts
  • tests/quality-tracking.test.ts
  • tests/server-agent-tools.test.ts
  • tests/server.test.ts
  • tests/spawn-workspace.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: test
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-03-15T10:42:35.917Z
Learnt from: EtanHey
Repo: EtanHey/cmuxlayer PR: 1
File: tests/quality-tracking.test.ts:171-200
Timestamp: 2026-03-15T10:42:35.917Z
Learning: In tests/quality-tracking.test.ts for the cmuxlayer project, ensure that at or above 80% context quality degradation, behavior depends on depth: depth-0 agents receive a /compact command; depth > 0 agents are killed and logged (kill + log). Respawn of non-root agents is out of scope for v1. Treat the design doc quality tracking section as the authoritative source for this behavior, and align test expectations accordingly.

Applied to files:

  • tests/mode-policy.test.ts
  • tests/quality-tracking.test.ts
  • tests/spawn-workspace.test.ts
  • tests/daemon.test.ts
  • tests/agent-engine.test.ts
  • tests/server.test.ts
  • tests/agent-hierarchy.test.ts
  • tests/server-agent-tools.test.ts
  • tests/app-server-runtime.test.ts
🔇 Additional comments (18)
tests/agent-engine.test.ts (1)

89-89: LGTM!

tests/agent-hierarchy.test.ts (1)

37-37: LGTM!

tests/quality-tracking.test.ts (1)

36-36: LGTM!

tests/app-server-runtime.test.ts (1)

62-63: LGTM!

Also applies to: 881-995

tests/mode-policy.test.ts (1)

64-64: LGTM!

Also applies to: 115-117

src/mode-policy.ts (1)

28-28: LGTM!

src/server.ts (5)

5138-5154: LGTM!


9173-9173: LGTM!


9270-9276: LGTM!

Also applies to: 9386-9389


9411-9414: LGTM!

Also applies to: 9802-9805, 10131-10134


8592-8598: 🔒 Security & Privacy | ⚡ Quick win

Authorization Bypass (CWE-863): Incorrect Authorization

Reachability: Internal

Reachability path
● Entry
  tests/server-agent-tools.test.ts
│
▼
● Sink
  src/server.ts

Gate the focus by surface, not only by workspace.

assertWorkspaceMutationAllowed reads the control mode only from the supplied workspace. If focusOpts?.workspace is undefined, readWorkspaceControlMode returns { control: "autonomous" } without any status lookup, and the focus proceeds even when the target workspace is in manual mode. The sibling renameTab bridge at Line 8582 avoids this by using assertSurfaceMutationAllowed, which resolves the workspace from the surface through identify.

Use the surface-scoped assertion so the gate holds when the caller omits the workspace. It also produces ManualModeMutationError with the surface identity.

🛡️ Proposed fix
           focusSurface: async (surface, focusOpts) => {
-            await assertWorkspaceMutationAllowed(
-              "agent_engine",
-              focusOpts?.workspace,
-            );
+            await assertSurfaceMutationAllowed(
+              "agent_engine",
+              surface,
+              focusOpts?.workspace,
+            );
             return client.focusSurface(surface, focusOpts);
           },

Run the following script to confirm whether the agent engine ever calls focusSurface without a workspace:

#!/bin/bash
# Description: Inspect every focusSurface call site and its options.
set -euo pipefail

fd -e ts . src | xargs rg -n -C 6 '\bfocusSurface\s*\('

# Structural view of the engine's focus call, if present.
ast-grep run --pattern 'this.$_.focusSurface($$$)' --lang typescript src || true
ast-grep run --pattern '$_.focusSurface($$$)' --lang typescript src || true
tests/server-agent-tools.test.ts (4)

1857-1857: LGTM!

Also applies to: 1965-1965, 3168-3168, 6285-6285


10093-10121: LGTM!


10138-10286: LGTM!


10392-10563: LGTM!

tests/server.test.ts (1)

1184-1184: LGTM!

tests/spawn-workspace.test.ts (1)

114-114: LGTM!

tests/daemon.test.ts (1)

258-258: LGTM!

Comment thread src/agent-engine.ts
Comment thread src/app-server-runtime.ts

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: be8b7b6d48

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/mode-policy.ts
"boot_prompt",
"send_key",
"rename_tab",
"focus_surface",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Gate MCP focus restores in manual mode

When an MCP spawn/new_worktree_split restores focus to an origin workspace that is manual, or becomes manual during the boot/readiness wait, this new policy says focus_surface is blocked, but the MCP restore path still calls client.focusSurface directly in src/server.ts:5188-5191 without assertWorkspaceMutationAllowed (unlike the app-server restore path added here). That lets default focus restoration move focus on a manual surface instead of respecting the manual-mode lock; gate restoreFocusAfterRender before focusing/selecting the prior target.

Useful? React with 👍 / 👎.

@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.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@cursor

cursor Bot commented Aug 5, 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_94bc6aa9-027b-4839-99ac-04fc7bb7c12c)

@EtanHey

EtanHey commented Aug 5, 2026

Copy link
Copy Markdown
Owner Author

@codex review exact head 6ad53ae

@EtanHey

EtanHey commented Aug 5, 2026

Copy link
Copy Markdown
Owner Author

@greptileai review exact head 6ad53ae

@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.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

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