Skip to content

Remove plan mode from daemon#140

Merged
glittercowboy merged 1 commit intomainfrom
codex/remove-plan-mode
May 2, 2026
Merged

Remove plan mode from daemon#140
glittercowboy merged 1 commit intomainfrom
codex/remove-plan-mode

Conversation

@glittercowboy
Copy link
Copy Markdown
Contributor

@glittercowboy glittercowboy commented May 2, 2026

Summary

  • remove daemon Plan Mode capability wiring, worker-key hashes, runtime env controls, and local evidence capture
  • remove the pi extension plan tools and daemon lab Plan Mode scenario/API surface
  • bump protocol-go to v0.36.0, which removes Plan Mode wire messages

Dependency

Verification

  • go test ./...
  • go build ./...

Post-merge

  • Publish the next daemon release tag so installer-delivered binaries include this runtime surface.

Summary by CodeRabbit

  • Removed Features

    • Plan capability feature removed: Plan Mode UI, plan tools, plan-related API endpoint, evidence collection/reporting, and plan-mode event tracking.
  • Behavior Changes

    • Worker identity and warm-worker reuse now keyed by browser grant/session identifiers instead of plan fields.
    • Control/runner startup is provider-aware and excludes unrelated host secrets.
    • Tool-call naming adjusted: plan-related tool calls now use task-oriented names.
  • Tests

    • Plan-capability and plan-evidence tests removed; tests updated for provider-driven behavior and renamed tool expectations.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 2, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d909712c-64f2-480c-a435-ea9751bb7a25

📥 Commits

Reviewing files that changed from the base of the PR and between c7b57ef and 5887d16.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (25)
  • cmd/pi_tui.go
  • docs/superpowers/plans/2026-04-29-warm-pi-provider-processes.md
  • go.mod
  • internal/lab/scenarios.go
  • internal/lab/server.go
  • internal/lab/static/index.html
  • internal/loop/daemon.go
  • internal/pi/control.go
  • internal/pi/control_test.go
  • internal/pi/executor.go
  • internal/pi/executor_test.go
  • internal/pi/extension/claude-prompt.test.mjs
  • internal/pi/extension/index.ts
  • internal/pi/extension/plan-tools.js
  • internal/pi/extension/plan-tools.test.mjs
  • internal/pi/extension/schema-to-zod.test.mjs
  • internal/pi/extension/tool-policy.js
  • internal/pi/extension_package_test.go
  • internal/pi/worker_key.go
  • internal/pi/worker_key_test.go
  • internal/session/actor.go
  • internal/session/actor_test.go
  • internal/session/plan_evidence.go
  • internal/session/plan_evidence_outbox.go
  • internal/session/plan_evidence_test.go
💤 Files with no reviewable changes (13)
  • internal/lab/static/index.html
  • internal/pi/extension/tool-policy.js
  • internal/pi/extension/plan-tools.test.mjs
  • cmd/pi_tui.go
  • internal/pi/executor_test.go
  • internal/lab/scenarios.go
  • internal/session/plan_evidence.go
  • internal/session/plan_evidence_outbox.go
  • internal/pi/extension_package_test.go
  • internal/lab/server.go
  • internal/pi/worker_key.go
  • internal/pi/extension/plan-tools.js
  • internal/session/plan_evidence_test.go
✅ Files skipped from review due to trivial changes (3)
  • go.mod
  • internal/pi/extension/schema-to-zod.test.mjs
  • internal/pi/executor.go
🚧 Files skipped from review as they are similar to previous changes (6)
  • internal/pi/extension/claude-prompt.test.mjs
  • internal/pi/control_test.go
  • internal/pi/control.go
  • internal/pi/worker_key_test.go
  • docs/superpowers/plans/2026-04-29-warm-pi-provider-processes.md
  • internal/session/actor_test.go

📝 Walkthrough

Walkthrough

This PR removes plan-capability support and plan-related tooling/tests/UI, shifts warm-worker identity to browser-grant fields, removes plan-evidence/outbox logic, and threads a Pi provider string through actor/control/executor wiring. go.mod updates github.com/gsd-build/protocol-go to v0.36.0.

Changes

Plan-capability removal & provider/browser-grant migration

Layer / File(s) Summary
Dependency & Imports
go.mod, cmd/pi_tui.go, internal/pi/executor.go, internal/pi/executor_test.go, internal/pi/worker_key_test.go
Bumped github.com/gsd-build/protocol-go to v0.36.0; removed protocol imports tied to PlanCapability.
Data Shape
internal/pi/executor.go, internal/pi/worker_key.go, internal/pi/worker_key_test.go, internal/session/actor.go, docs/...
Removed PlanCapability from pi Options and worker key fields (PlanAPIBaseURL, PlanTokenHash, PlanExpiresAt); added browser identity fields (BrowserGrantID, BrowserID, BrowserSessionID) and Provider string where applicable.
Process / Environment Wiring
internal/pi/executor.go, internal/pi/control.go, internal/pi/control_test.go, cmd/pi_tui.go, internal/session/actor.go
Stopped injecting GSD_PLAN_* env vars; deleted planCapabilityEnv helper and usages; RunControl/Run build env via processEnv(..., Options{Provider: ...}); ControlOptions gains Provider.
Session Runtime & Tool Hooks
internal/session/actor.go, internal/session/actor_test.go
Removed plan runtime reporter and plan-capability reporting paths; actor now seeds/stores per-task Pi provider and exposes Actor.SetProvider; tool execution hooks simplified to call capturePiToolStart/capturePiToolEnd directly.
Evidence & Outbox Removal
internal/session/plan_evidence.go, internal/session/plan_evidence_outbox.go, internal/session/plan_evidence_test.go
Deleted plan-evidence runtime reporter, file-backed outbox, flush/retry/post logic, capability revoke-on-finish, and all related tests.
Extension: Plan Tools Removed
internal/pi/extension/plan-tools.js, internal/pi/extension/plan-tools.test.mjs, internal/pi/extension/index.ts, internal/pi/extension_package_test.go
Removed plan-tools module and its tests; stopped importing/registering plan tools during extension bootstrap; updated packaged-runtime test expectations.
Tool Policy / Name Mapping
internal/pi/extension/tool-policy.js
Removed fallback mapping of plan_*"plan"; added explicit gsd_browser"browser" mapping so plan_* tools no longer resolve to a category.
Lab UI / Server / Scenarios
internal/lab/static/index.html, internal/lab/server.go, internal/lab/scenarios.go
Removed "Plan Mode" UI block and pre#planEvents; removed /api/agent-plan/ route/handler; removed "plan-mode" built-in scenario.
Tests / Minor Adjustments
internal/pi/extension/claude-prompt.test.mjs, internal/pi/extension/schema-to-zod.test.mjs, various tests
Replaced plan_donetask_done and create_plancreate_task expectations; removed multiple plan-capability tests; fake Pi tests now dump full env; worker-key tests refocused on browser-grant fields.
Docs
docs/superpowers/plans/2026-04-29-warm-pi-provider-processes.md
Documented worker identity shift to browser-grant fields, removal of plan-capability data from worker keys/env, and warm-worker stop behavior hardening.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through code with nimble feet,

Plans tucked away, the runtime neat.
Env keys cleared and outboxes gone,
Provider set, the flow moves on.
A joyous thump — clean code, well done!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.25% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Remove plan mode from daemon' directly and accurately describes the primary objective of the PR: removing Plan Mode functionality from the daemon system.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 codex/remove-plan-mode

Review rate limit: 9/10 reviews remaining, refill in 6 minutes.

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
docs/superpowers/plans/2026-04-29-warm-pi-provider-processes.md (3)

19-23: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Doc is out-of-sync with “remove plan mode” objective (plan capability references).

The plan currently says internal/pi/worker_key_test.go should verify “plan capability identity” and the WorkerKey struct includes PlanAPIBaseURL, PlanTokenHash, and PlanExpiresAt. This conflicts with the PR goal of removing plan mode wiring/capabilities. Please remove/replace those plan-capability references (tests + key fields + any “Plan*” behavior) so the implementation plan matches the new protocol/runtime surface.

Also applies to: 249-270, 298-343

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/superpowers/plans/2026-04-29-warm-pi-provider-processes.md` around lines
19 - 23, The docs and tests still reference plan-mode fields and behavior that
should be removed; update the WorkerKey-related code and tests to drop plan
capability wiring: remove the PlanAPIBaseURL, PlanTokenHash, and PlanExpiresAt
fields from the WorkerKey struct (and any usage in NewWorkerKey/WorkerSnapshot),
and update internal/pi/worker_key_test.go to stop asserting "plan capability
identity" — replace those assertions with checks relevant to the new protocol
surface (e.g., default provider behavior or other existing identity fields), and
update any doc entries in the plan file that list "plan capability" to match the
new fields/behavior.

298-343: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Embedded WorkerKey includes Plan fields but NewWorkerKey doesn’t populate them (internal inconsistency).

In the snippet, WorkerKey defines PlanAPIBaseURL/PlanTokenHash/PlanExpiresAt, but NewWorkerKey(opts Options) sets only the non-plan fields shown—leaving those plan fields at their zero values. If you keep plan-related identity (which likely shouldn’t, given the PR objective), NewWorkerKey must populate them from Options; otherwise, remove the fields and any associated test expectations so the hash/key identity logic is consistent.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/superpowers/plans/2026-04-29-warm-pi-provider-processes.md` around lines
298 - 343, WorkerKey declares PlanAPIBaseURL, PlanTokenHash and PlanExpiresAt
but NewWorkerKey(opts Options) does not set them, creating an internal
inconsistency; either populate those fields from the provided Options (e.g. set
WorkerKey.PlanAPIBaseURL = opts.PlanAPIBaseURL, PlanTokenHash =
opts.PlanTokenHash, PlanExpiresAt = opts.PlanExpiresAt) so key identity includes
plan data, or remove the three Plan* fields from the WorkerKey type (and update
any tests that expect them) so NewWorkerKey and the key/hash logic (e.g.
anywhere KeyHash is computed) remain consistent.

1748-1813: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

WarmClaudeSdkWorker.stop() can leave an in-flight turn() Promise unresolved.

In the embedded TS implementation, stop() just calls this.prompt.close(); if this.active is set (a turn() is currently waiting for a result), the pump loop may end without calling resolve or reject, leaving the pending Promise hanging. If stop() can run during warm-worker reset/teardown, this can break callers.

Suggested fix in the plan snippet: in stop(), if this.active exists, reject it (or resolve with a well-defined cancellation result) and clear this.active / this.pumpError.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/superpowers/plans/2026-04-29-warm-pi-provider-processes.md` around lines
1748 - 1813, stop() currently only calls this.prompt.close() and can leave a
pending turn Promise unresolved; update WarmClaudeSdkWorker.stop() so that after
calling this.prompt.close() it checks if this.active exists, creates a
cancellation Error (e.g. new Error("WarmClaudeSdkWorker stopped")), assigns it
to this.pumpError, calls this.active.reject(err), and then clears this.active
(and any transient state) so the in-flight Promise is deterministically rejected
and no dangling resolver remains.
internal/pi/worker_key_test.go (1)

29-49: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clear BrowserSessionID in the negative case too.

Right now this still passes if NewWorkerKey only keys on BrowserSessionID, so it no longer proves that BrowserGrantID and BrowserID participate in the key.

Suggested fix
 	withoutBrowser := base
 	withoutBrowser.BrowserGrantID = ""
 	withoutBrowser.BrowserID = ""
+	withoutBrowser.BrowserSessionID = ""
 	if a == NewWorkerKey(withoutBrowser) {
 		t.Fatal("worker key ignored browser grant")
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/pi/worker_key_test.go` around lines 29 - 49, The test
TestWorkerKeyIncludesBrowserGrant currently leaves BrowserSessionID set and thus
could pass if NewWorkerKey only uses BrowserSessionID; update the negative case
by also clearing withoutBrowser.BrowserSessionID = "" so that NewWorkerKey(base)
!= NewWorkerKey(withoutBrowser) only if BrowserGrantID and BrowserID are
considered; locate the failing test and modify the withoutBrowser struct
assignments (in TestWorkerKeyIncludesBrowserGrant) to set BrowserGrantID,
BrowserID, and BrowserSessionID to empty strings before comparing.
internal/pi/extension/index.ts (1)

60-71: ⚠️ Potential issue | 🟠 Major

Add plan-mode built-ins to the disallowed list.

With permissionMode: "bypassPermissions", the Agent SDK does not enforce allowedTools as a restriction; only disallowedTools can block specific built-ins. EnterPlanMode and ExitPlanMode are documented built-in tools in the Claude Agent SDK, and dropping them from CLAUDE_BUILTINS re-enables the exact plan-mode capabilities this PR aims to remove.

Suggested fix
const CLAUDE_BUILTINS = [
  "Bash", "BashOutput", "KillShell",
  "Read", "Write", "Edit", "MultiEdit", "NotebookEdit",
  "Glob", "Grep", "WebFetch", "WebSearch",
-  "Task", "Agent", "TodoWrite",
+  "Task", "Agent", "TodoWrite", "EnterPlanMode", "ExitPlanMode",
   "ListMcpResourcesTool", "ReadMcpResourceTool",
   "AskUserQuestion", "PushNotification", "ScheduleWakeup", "Monitor", "Skill", "ToolSearch",
   "TeamCreate", "TeamDelete", "SendMessage",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/pi/extension/index.ts` around lines 60 - 71, The CLAUDE_BUILTINS
array is missing the documented plan-mode tools so they remain allowed; update
the CLAUDE_BUILTINS constant in internal/pi/extension/index.ts to include
"EnterPlanMode" and "ExitPlanMode" so those plan-mode built-ins are treated as
disallowed by your permission logic (look for the CLAUDE_BUILTINS array
definition and add the two symbols to that list).
🧹 Nitpick comments (1)
internal/pi/extension/schema-to-zod.test.mjs (1)

72-72: ⚡ Quick win

Add a direct assertion for the new create_task discriminator branch.

Right now the test only asserts the start_next_item path; a typo in the renamed discriminator could slip through without failing this test.

Proposed test addition
 const operationResult = operationSchema.safeParse({
   type: "start_next_item",
   leaseTtlSeconds: 1800,
 });
 assert.equal(operationResult.success, false);
@@
   ["leaseTtlSeconds"],
 );
+
+const createTaskResult = operationSchema.safeParse({
+  type: "create_task",
+  title: "Wire task flow",
+  items: [{}],
+});
+assert.equal(createTaskResult.success, true);
+
+assert.equal(operationSchema.safeParse({
+  type: "create_plan",
+  title: "legacy value",
+  items: [{}],
+}).success, false);
 console.log("schema-to-zod tests passed");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/pi/extension/schema-to-zod.test.mjs` at line 72, Add an explicit
assertion that the schema-to-zod conversion produces the expected branch for the
new discriminator value "create_task": locate the test in schema-to-zod.test.mjs
that currently asserts the "start_next_item" path and add a direct expect/assert
for the discriminator branch where type: { const: "create_task" } (verify the
generated Zod union/branch or matcher for "create_task" exists and matches the
expected shape). Ensure the assertion references the same helper/subject used in
the test (e.g., the conversion function or generated Zod schema variable) so a
typo in "create_task" will cause the test to fail.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/pi/control.go`:
- Line 139: Replace the unconditional inheritance of the parent environment in
control mode (the cmd.Env = os.Environ() assignment) with the same
allowlist-based environment builder used by internal/pi/executor.go; thread any
required provider creds explicitly through ControlOptions (add fields if needed)
and use those to populate the builder so control-mode subprocesses only receive
the sanitized, allowlisted variables rather than the full parent env. Ensure you
locate and reuse the executor’s env-builder function (or extract it to a shared
helper) and replace references to os.Environ() in control.go with a call that
builds cmd.Env from ControlOptions via that allowlist.

---

Outside diff comments:
In `@docs/superpowers/plans/2026-04-29-warm-pi-provider-processes.md`:
- Around line 19-23: The docs and tests still reference plan-mode fields and
behavior that should be removed; update the WorkerKey-related code and tests to
drop plan capability wiring: remove the PlanAPIBaseURL, PlanTokenHash, and
PlanExpiresAt fields from the WorkerKey struct (and any usage in
NewWorkerKey/WorkerSnapshot), and update internal/pi/worker_key_test.go to stop
asserting "plan capability identity" — replace those assertions with checks
relevant to the new protocol surface (e.g., default provider behavior or other
existing identity fields), and update any doc entries in the plan file that list
"plan capability" to match the new fields/behavior.
- Around line 298-343: WorkerKey declares PlanAPIBaseURL, PlanTokenHash and
PlanExpiresAt but NewWorkerKey(opts Options) does not set them, creating an
internal inconsistency; either populate those fields from the provided Options
(e.g. set WorkerKey.PlanAPIBaseURL = opts.PlanAPIBaseURL, PlanTokenHash =
opts.PlanTokenHash, PlanExpiresAt = opts.PlanExpiresAt) so key identity includes
plan data, or remove the three Plan* fields from the WorkerKey type (and update
any tests that expect them) so NewWorkerKey and the key/hash logic (e.g.
anywhere KeyHash is computed) remain consistent.
- Around line 1748-1813: stop() currently only calls this.prompt.close() and can
leave a pending turn Promise unresolved; update WarmClaudeSdkWorker.stop() so
that after calling this.prompt.close() it checks if this.active exists, creates
a cancellation Error (e.g. new Error("WarmClaudeSdkWorker stopped")), assigns it
to this.pumpError, calls this.active.reject(err), and then clears this.active
(and any transient state) so the in-flight Promise is deterministically rejected
and no dangling resolver remains.

In `@internal/pi/extension/index.ts`:
- Around line 60-71: The CLAUDE_BUILTINS array is missing the documented
plan-mode tools so they remain allowed; update the CLAUDE_BUILTINS constant in
internal/pi/extension/index.ts to include "EnterPlanMode" and "ExitPlanMode" so
those plan-mode built-ins are treated as disallowed by your permission logic
(look for the CLAUDE_BUILTINS array definition and add the two symbols to that
list).

In `@internal/pi/worker_key_test.go`:
- Around line 29-49: The test TestWorkerKeyIncludesBrowserGrant currently leaves
BrowserSessionID set and thus could pass if NewWorkerKey only uses
BrowserSessionID; update the negative case by also clearing
withoutBrowser.BrowserSessionID = "" so that NewWorkerKey(base) !=
NewWorkerKey(withoutBrowser) only if BrowserGrantID and BrowserID are
considered; locate the failing test and modify the withoutBrowser struct
assignments (in TestWorkerKeyIncludesBrowserGrant) to set BrowserGrantID,
BrowserID, and BrowserSessionID to empty strings before comparing.

---

Nitpick comments:
In `@internal/pi/extension/schema-to-zod.test.mjs`:
- Line 72: Add an explicit assertion that the schema-to-zod conversion produces
the expected branch for the new discriminator value "create_task": locate the
test in schema-to-zod.test.mjs that currently asserts the "start_next_item" path
and add a direct expect/assert for the discriminator branch where type: { const:
"create_task" } (verify the generated Zod union/branch or matcher for
"create_task" exists and matches the expected shape). Ensure the assertion
references the same helper/subject used in the test (e.g., the conversion
function or generated Zod schema variable) so a typo in "create_task" will cause
the test to fail.
🪄 Autofix (Beta)

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a9d0c421-8322-47ee-b3e8-30d0bfa8daaa

📥 Commits

Reviewing files that changed from the base of the PR and between 0776444 and 8d7b64d.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (24)
  • cmd/pi_tui.go
  • docs/superpowers/plans/2026-04-29-warm-pi-provider-processes.md
  • go.mod
  • internal/lab/scenarios.go
  • internal/lab/server.go
  • internal/lab/static/index.html
  • internal/pi/control.go
  • internal/pi/control_test.go
  • internal/pi/executor.go
  • internal/pi/executor_test.go
  • internal/pi/extension/claude-prompt.test.mjs
  • internal/pi/extension/index.ts
  • internal/pi/extension/plan-tools.js
  • internal/pi/extension/plan-tools.test.mjs
  • internal/pi/extension/schema-to-zod.test.mjs
  • internal/pi/extension/tool-policy.js
  • internal/pi/extension_package_test.go
  • internal/pi/worker_key.go
  • internal/pi/worker_key_test.go
  • internal/session/actor.go
  • internal/session/actor_test.go
  • internal/session/plan_evidence.go
  • internal/session/plan_evidence_outbox.go
  • internal/session/plan_evidence_test.go
💤 Files with no reviewable changes (14)
  • internal/pi/extension_package_test.go
  • internal/lab/server.go
  • internal/pi/extension/tool-policy.js
  • cmd/pi_tui.go
  • internal/lab/static/index.html
  • internal/lab/scenarios.go
  • internal/session/plan_evidence.go
  • internal/pi/extension/plan-tools.test.mjs
  • internal/pi/extension/plan-tools.js
  • internal/pi/executor_test.go
  • internal/session/plan_evidence_outbox.go
  • internal/session/plan_evidence_test.go
  • internal/pi/control_test.go
  • internal/pi/worker_key.go

Comment thread internal/pi/control.go Outdated
@glittercowboy glittercowboy force-pushed the codex/remove-plan-mode branch from 8d7b64d to 9f99077 Compare May 2, 2026 02:07
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/session/actor.go (1)

221-227: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Seed the control provider before the first task runs.

currentPiProvider() falls back to claude-cli until runPiExecutor() has called setPiProvider(). That means a compact/context-stats request on a resumed or freshly started session will build the control subprocess env for the wrong provider and drop non-Anthropic credentials before internal/pi/control.go launches pi. For sessions using openrouter/zai/kimi-coding, control commands can fail after a daemon restart or before the first task executes.

Please thread a default provider into the actor at construction time, or restore it from persisted session state, so runPiControl has the right provider even when no task has executed yet.

Also applies to: 1310-1317

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/session/actor.go` around lines 221 - 227, The actor is seeding the
control provider too late (currentPiProvider() defaults to claude-cli until
setPiProvider() runs), causing control subprocesses to be built with wrong
credentials; fix by initializing the actor's provider at construction or
restoring it from persisted session state so runPiControl/runPiExecutor use the
correct provider before any task runs—specifically, populate the actor's
provider field used by currentPiProvider() during NewActor/constructor or
session restore paths (or load it from the persisted session record) so
pi.RunControl called in runPiControl (the call site invoking pi.RunControl with
BinaryPath/CWD/SessionFile/Model/Provider/Command) gets the right Provider even
on resumed sessions or before setPiProvider() is ever invoked.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@internal/session/actor.go`:
- Around line 221-227: The actor is seeding the control provider too late
(currentPiProvider() defaults to claude-cli until setPiProvider() runs), causing
control subprocesses to be built with wrong credentials; fix by initializing the
actor's provider at construction or restoring it from persisted session state so
runPiControl/runPiExecutor use the correct provider before any task
runs—specifically, populate the actor's provider field used by
currentPiProvider() during NewActor/constructor or session restore paths (or
load it from the persisted session record) so pi.RunControl called in
runPiControl (the call site invoking pi.RunControl with
BinaryPath/CWD/SessionFile/Model/Provider/Command) gets the right Provider even
on resumed sessions or before setPiProvider() is ever invoked.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 725f5a1b-66a2-4668-80bd-7def5c511ba4

📥 Commits

Reviewing files that changed from the base of the PR and between 8d7b64d and 9f99077.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (24)
  • cmd/pi_tui.go
  • docs/superpowers/plans/2026-04-29-warm-pi-provider-processes.md
  • go.mod
  • internal/lab/scenarios.go
  • internal/lab/server.go
  • internal/lab/static/index.html
  • internal/pi/control.go
  • internal/pi/control_test.go
  • internal/pi/executor.go
  • internal/pi/executor_test.go
  • internal/pi/extension/claude-prompt.test.mjs
  • internal/pi/extension/index.ts
  • internal/pi/extension/plan-tools.js
  • internal/pi/extension/plan-tools.test.mjs
  • internal/pi/extension/schema-to-zod.test.mjs
  • internal/pi/extension/tool-policy.js
  • internal/pi/extension_package_test.go
  • internal/pi/worker_key.go
  • internal/pi/worker_key_test.go
  • internal/session/actor.go
  • internal/session/actor_test.go
  • internal/session/plan_evidence.go
  • internal/session/plan_evidence_outbox.go
  • internal/session/plan_evidence_test.go
💤 Files with no reviewable changes (13)
  • cmd/pi_tui.go
  • internal/pi/extension/plan-tools.js
  • internal/lab/server.go
  • internal/pi/extension_package_test.go
  • internal/pi/extension/tool-policy.js
  • internal/session/plan_evidence.go
  • internal/pi/worker_key.go
  • internal/pi/extension/plan-tools.test.mjs
  • internal/pi/executor_test.go
  • internal/lab/scenarios.go
  • internal/lab/static/index.html
  • internal/session/plan_evidence_test.go
  • internal/session/plan_evidence_outbox.go
✅ Files skipped from review due to trivial changes (4)
  • go.mod
  • internal/pi/extension/claude-prompt.test.mjs
  • internal/pi/executor.go
  • docs/superpowers/plans/2026-04-29-warm-pi-provider-processes.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • internal/pi/extension/schema-to-zod.test.mjs
  • internal/pi/worker_key_test.go
  • internal/session/actor_test.go

@glittercowboy glittercowboy force-pushed the codex/remove-plan-mode branch from 9f99077 to 67013fe Compare May 2, 2026 02:16
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/session/actor.go (1)

903-910: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Move provider seeding earlier than runPiExecutor().

piProvider is only updated after the task leaves the queue. runPiControl() reads that same session-scoped field for ContextStatsRequest/CompactRequest, so a control request that lands between task acceptance and this point can still run with the previous provider's env/credentials.

Suggested fix
+func (a *Actor) SetProvider(provider string) {
+	a.taskMu.Lock()
+	a.piProvider = pi.ProviderOrDefault(provider)
+	a.taskMu.Unlock()
+}

And update the task-acceptance path in internal/loop/daemon.go before the actor becomes observable to concurrent control requests:

 if actor == nil {
 	actor, err = d.manager.Spawn(ctx, session.Options{
 		SessionID: msg.SessionID,
 		CWD:       msg.CWD,
 		Model:     msg.Model,
 		Provider:  msg.Provider,
 		// ...
 	})
 	// ...
 } else {
+	actor.SetProvider(msg.Provider)
 	actor.SetBrowserContext(browserGrantID, browserID)
 	actor.SetBrowserGrant(browserGrant, session.BrowserRuntimeSnapshot{
 		// ...
 	}, d.browserRPCSocket)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/session/actor.go` around lines 903 - 910, The provider must be
seeded before any control or executor runs: move the call to
a.setPiProvider(pi.ProviderOrDefault(tc.Provider)) to occur immediately after
determining/normalizing the model (i.e., right after model =
normalizePiModel(model) and a.setPiModel(model)), so that session-scoped
piProvider is updated prior to runPiExecutor() and runPiControl() reading it;
also ensure the task-acceptance path in internal/loop/daemon.go updates the
actor's provider (via setPiProvider) before the actor is published/made
observable to concurrent control requests so control requests cannot observe the
previous provider/credentials.
🧹 Nitpick comments (2)
docs/superpowers/plans/2026-04-29-warm-pi-provider-processes.md (2)

1782-1791: ⚡ Quick win

Align WarmClaudeSdkWorker.stop() ordering with the stated “reject before closing” intent.

The doc snippet closes the prompt queue first (this.prompt.close()), then rejects the active turn and sets pumpError. If the goal is to reliably reject an in-progress turn before the prompt pump is closed/stopped, the ordering should be swapped: set pumpError, reject the active turn, then close the prompt queue.

🛠️ Suggested doc change
 async stop() {
-  this.prompt.close();
   if (this.active) {
     const err = new Error("WarmClaudeSdkWorker stopped");
     this.pumpError = err;
     const active = this.active;
     this.active = null;
     active.reject(err);
   }
+  this.prompt.close();
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/superpowers/plans/2026-04-29-warm-pi-provider-processes.md` around lines
1782 - 1791, The stop() method in WarmClaudeSdkWorker should reject the
in-progress turn before closing the prompt pump; change the ordering in
WarmClaudeSdkWorker.stop(): if this.active is set, create and assign the Error
to this.pumpError, capture the active reference, set this.active = null, call
active.reject(err), and only after handling rejection call this.prompt.close()
so the active turn is reliably rejected before the prompt queue is shut down.

249-270: ⚡ Quick win

Minor clarity: tighten what the worker-key browser test is proving.

TestWorkerKeyIncludesBrowserGrant correctly makes the key differ by blanking browser identity fields, but it would be clearer if the snippet emphasized which field(s) are expected to drive inequality (e.g., change only BrowserSessionID vs changing all browser fields). This is a small doc quality improvement to prevent future “false confidence” in what’s actually covered.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/superpowers/plans/2026-04-29-warm-pi-provider-processes.md` around lines
249 - 270, The test TestWorkerKeyIncludesBrowserGrant is unclear because it
clears all three browser fields at once; change it to make minimal, focused
assertions: keep base as-is and create one variant that changes only the
BrowserGrantID (or only BrowserSessionID / BrowserID) and assert
NewWorkerKey(base) != NewWorkerKey(variant), and optionally add separate tiny
subtests that change each browser field individually to prove each one affects
NewWorkerKey; update references to NewWorkerKey,
TestWorkerKeyIncludesBrowserGrant, and the fields BrowserGrantID, BrowserID,
BrowserSessionID so the test explicitly documents which field caused the
inequality.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/superpowers/plans/2026-04-29-warm-pi-provider-processes.md`:
- Around line 514-515: The doc snippet calls processEnv which invokes browserEnv
using positional fields (browserEnv(base, opts.BrowserGrantID, opts.BrowserID,
opts.BrowserSessionID)) but the actual function signature is browserEnv(base
[]string, opts Options) []string; update the documentation so processEnv calls
browserEnv with the Options object (e.g., pass opts as the second argument) or
otherwise mirror the real signature, and mention the correct symbols browserEnv
and processEnv so readers use the matching call form.

---

Outside diff comments:
In `@internal/session/actor.go`:
- Around line 903-910: The provider must be seeded before any control or
executor runs: move the call to
a.setPiProvider(pi.ProviderOrDefault(tc.Provider)) to occur immediately after
determining/normalizing the model (i.e., right after model =
normalizePiModel(model) and a.setPiModel(model)), so that session-scoped
piProvider is updated prior to runPiExecutor() and runPiControl() reading it;
also ensure the task-acceptance path in internal/loop/daemon.go updates the
actor's provider (via setPiProvider) before the actor is published/made
observable to concurrent control requests so control requests cannot observe the
previous provider/credentials.

---

Nitpick comments:
In `@docs/superpowers/plans/2026-04-29-warm-pi-provider-processes.md`:
- Around line 1782-1791: The stop() method in WarmClaudeSdkWorker should reject
the in-progress turn before closing the prompt pump; change the ordering in
WarmClaudeSdkWorker.stop(): if this.active is set, create and assign the Error
to this.pumpError, capture the active reference, set this.active = null, call
active.reject(err), and only after handling rejection call this.prompt.close()
so the active turn is reliably rejected before the prompt queue is shut down.
- Around line 249-270: The test TestWorkerKeyIncludesBrowserGrant is unclear
because it clears all three browser fields at once; change it to make minimal,
focused assertions: keep base as-is and create one variant that changes only the
BrowserGrantID (or only BrowserSessionID / BrowserID) and assert
NewWorkerKey(base) != NewWorkerKey(variant), and optionally add separate tiny
subtests that change each browser field individually to prove each one affects
NewWorkerKey; update references to NewWorkerKey,
TestWorkerKeyIncludesBrowserGrant, and the fields BrowserGrantID, BrowserID,
BrowserSessionID so the test explicitly documents which field caused the
inequality.
🪄 Autofix (Beta)

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7b1f09e9-7db1-4251-ad91-82a1bac50ae5

📥 Commits

Reviewing files that changed from the base of the PR and between 9f99077 and 67013fe.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (25)
  • cmd/pi_tui.go
  • docs/superpowers/plans/2026-04-29-warm-pi-provider-processes.md
  • go.mod
  • internal/lab/scenarios.go
  • internal/lab/server.go
  • internal/lab/static/index.html
  • internal/loop/daemon.go
  • internal/pi/control.go
  • internal/pi/control_test.go
  • internal/pi/executor.go
  • internal/pi/executor_test.go
  • internal/pi/extension/claude-prompt.test.mjs
  • internal/pi/extension/index.ts
  • internal/pi/extension/plan-tools.js
  • internal/pi/extension/plan-tools.test.mjs
  • internal/pi/extension/schema-to-zod.test.mjs
  • internal/pi/extension/tool-policy.js
  • internal/pi/extension_package_test.go
  • internal/pi/worker_key.go
  • internal/pi/worker_key_test.go
  • internal/session/actor.go
  • internal/session/actor_test.go
  • internal/session/plan_evidence.go
  • internal/session/plan_evidence_outbox.go
  • internal/session/plan_evidence_test.go
💤 Files with no reviewable changes (13)
  • internal/pi/extension/tool-policy.js
  • cmd/pi_tui.go
  • internal/pi/extension_package_test.go
  • internal/pi/extension/plan-tools.js
  • internal/pi/executor_test.go
  • internal/lab/server.go
  • internal/lab/scenarios.go
  • internal/session/plan_evidence_test.go
  • internal/session/plan_evidence.go
  • internal/lab/static/index.html
  • internal/pi/extension/plan-tools.test.mjs
  • internal/pi/worker_key.go
  • internal/session/plan_evidence_outbox.go
✅ Files skipped from review due to trivial changes (2)
  • go.mod
  • internal/pi/worker_key_test.go
🚧 Files skipped from review as they are similar to previous changes (5)
  • internal/pi/extension/claude-prompt.test.mjs
  • internal/pi/executor.go
  • internal/pi/control_test.go
  • internal/pi/control.go
  • internal/session/actor_test.go

Comment thread docs/superpowers/plans/2026-04-29-warm-pi-provider-processes.md Outdated
@glittercowboy glittercowboy force-pushed the codex/remove-plan-mode branch from 67013fe to c7b57ef Compare May 2, 2026 02:27
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/loop/daemon.go (1)

1041-1048: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't update the actor provider before the task is accepted.

actor.SetProvider(msg.Provider) runs even if SendTask later fails because the session is busy. That mutates session-wide provider state for a task that never started, and it can also flip currentPiProvider() for the task that is still running.

runPiExecutor already seeds the provider when execution actually begins, so this eager update is redundant and risky.

Suggested fix
  } else {
-	actor.SetProvider(msg.Provider)
 		actor.SetBrowserContext(browserGrantID, browserID)
 		actor.SetBrowserGrant(browserGrant, session.BrowserRuntimeSnapshot{
 			ErrorCode:    runtime.ErrorCode,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/loop/daemon.go` around lines 1041 - 1048, The code currently calls
actor.SetProvider(msg.Provider) before attempting to SendTask, which can mutate
session-wide provider state even if SendTask fails; remove the eager provider
update — delete the actor.SetProvider(msg.Provider) call from this block
(leaving actor.SetBrowserContext and actor.SetBrowserGrant intact) and rely on
runPiExecutor to seed the provider when execution actually begins; ensure no
other code path reintroduces a pre-accept provider mutation and that
currentPiProvider() remains driven by the provider set during runPiExecutor.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/superpowers/plans/2026-04-29-warm-pi-provider-processes.md`:
- Around line 1792-1801: In stop(), always set this.pumpError to a new Error and
mark this.active = null even when there is no current turn so subsequent turn()
calls fail fast; if an active promise exists still call active.reject(err) as
before, then call this.prompt.close() — set pumpError before closing the prompt
so prompt.push() (in turn()) will see the error; refer to stop(), turn(),
pumpError, active, prompt.push(), and prompt.close() when making the change.

In `@internal/session/actor.go`:
- Around line 380-382: SetProvider currently forwards provider strings to
setPiProvider without normalizing empties, causing empty Provider in a new
message to leave the previous provider intact; update SetProvider (and the other
occurrences around the setPiProvider usage) to normalize empty values before
persisting—i.e., treat "" as a clear/default value and call setPiProvider with
that normalized value (or explicitly clear the provider state) so previous task
provider state cannot leak into subsequent sessions; reference the Actor type
and the SetProvider and setPiProvider methods when making the change.

---

Outside diff comments:
In `@internal/loop/daemon.go`:
- Around line 1041-1048: The code currently calls
actor.SetProvider(msg.Provider) before attempting to SendTask, which can mutate
session-wide provider state even if SendTask fails; remove the eager provider
update — delete the actor.SetProvider(msg.Provider) call from this block
(leaving actor.SetBrowserContext and actor.SetBrowserGrant intact) and rely on
runPiExecutor to seed the provider when execution actually begins; ensure no
other code path reintroduces a pre-accept provider mutation and that
currentPiProvider() remains driven by the provider set during runPiExecutor.
🪄 Autofix (Beta)

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 501810b8-d41a-47a1-8926-889e782a06ea

📥 Commits

Reviewing files that changed from the base of the PR and between 67013fe and c7b57ef.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (25)
  • cmd/pi_tui.go
  • docs/superpowers/plans/2026-04-29-warm-pi-provider-processes.md
  • go.mod
  • internal/lab/scenarios.go
  • internal/lab/server.go
  • internal/lab/static/index.html
  • internal/loop/daemon.go
  • internal/pi/control.go
  • internal/pi/control_test.go
  • internal/pi/executor.go
  • internal/pi/executor_test.go
  • internal/pi/extension/claude-prompt.test.mjs
  • internal/pi/extension/index.ts
  • internal/pi/extension/plan-tools.js
  • internal/pi/extension/plan-tools.test.mjs
  • internal/pi/extension/schema-to-zod.test.mjs
  • internal/pi/extension/tool-policy.js
  • internal/pi/extension_package_test.go
  • internal/pi/worker_key.go
  • internal/pi/worker_key_test.go
  • internal/session/actor.go
  • internal/session/actor_test.go
  • internal/session/plan_evidence.go
  • internal/session/plan_evidence_outbox.go
  • internal/session/plan_evidence_test.go
💤 Files with no reviewable changes (13)
  • internal/lab/static/index.html
  • internal/session/plan_evidence_test.go
  • internal/pi/extension/plan-tools.test.mjs
  • internal/pi/extension/tool-policy.js
  • internal/pi/worker_key.go
  • internal/pi/executor_test.go
  • internal/lab/server.go
  • internal/lab/scenarios.go
  • cmd/pi_tui.go
  • internal/session/plan_evidence_outbox.go
  • internal/pi/extension_package_test.go
  • internal/session/plan_evidence.go
  • internal/pi/extension/plan-tools.js
✅ Files skipped from review due to trivial changes (3)
  • go.mod
  • internal/pi/extension/schema-to-zod.test.mjs
  • internal/pi/control.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • internal/pi/extension/claude-prompt.test.mjs
  • internal/session/actor_test.go
  • internal/pi/control_test.go
  • internal/pi/executor.go

Comment thread docs/superpowers/plans/2026-04-29-warm-pi-provider-processes.md
Comment thread internal/session/actor.go
@glittercowboy glittercowboy force-pushed the codex/remove-plan-mode branch from c7b57ef to 5887d16 Compare May 2, 2026 02:37
@glittercowboy glittercowboy merged commit be91b28 into main May 2, 2026
3 checks passed
@glittercowboy glittercowboy deleted the codex/remove-plan-mode branch May 2, 2026 03:57
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