Add bb thread --plan for CLI/SDK parity with the composer's plan action - #2156
Merged
Merged
Conversation
SawyerHood
marked this pull request as ready for review
August 21, 2026 06:14
Plan mode is keyed on the structured `/plan` command mention the composer
sends, which `bb thread tell`/`spawn` never produced, so the literal
`/plan` text reached the Claude CLI ("/plan isn't available in this
environment"). Add `--plan` to both commands, a shared
`createBuiltinPlanCommandTextInput` helper (exported from @bb/sdk), and
document the surfaces in the guide and bb-cli skill.
The Claude bridge half of #2019 (switching an already-loaded session
into Plan mode when a later turn carries `/plan`) landed in #2157. This
change adds the bridge coverage #2157 left out: the `turn/steer` path
(`--plan` on a busy thread), re-entry after an approved plan, a refused
`setPermissionMode` failing the turn, and `buildClaudeTurnParams`
forwarding the flag.
Co-Authored-By: Claude <noreply@anthropic.com>
SawyerHood
force-pushed
the
bb/fix-2019-plan-mode-loaded-sessions
branch
from
August 21, 2026 16:42
88f2ed8 to
69f0366
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was wrong
Issue #2019 (report: https://get-bb.github.io/reports/issues/2019.html) had two parts.
/planwas ignored on an already-loaded Claude Code session. This half landed in Enter Plan mode when a later Claude turn carries /plan #2157 (eec134dc6):buildClaudeTurnParamsforwardsclaudeCodePermissionMode, the bridge turn schemas accept it, andenterPlanModeIfRequestedswitches the live SDK session into Plan mode before the prompt is pushed on bothturn/startandturn/steer. This PR no longer touches that code./plancommand mention the composer sends (promptInputHasCommandMention), andbb thread tell/spawnalways sentmentions: [], so a literal/plan ...reached the Claude CLI, which answered "/plan isn't available in this environment." Agents driving bb through the CLI or SDK had no parity path. This PR fixes that.What changed
packages/domain/src/shared-types.ts:createBuiltinPlanCommandTextInput(text)builds the same/plancommand mention the composer's plan action produces.@bb/sdkre-exports it (core/node/browser) so SDK callers pass it asinputtothreads.spawn/threads.send.apps/cli:--planonbb thread tellandbb thread spawnuses that helper. Plain/plan ...text is deliberately not parsed (the report's recommendation): that would silently change meaning for providers where/planis a real slash command.packages/templates/src/templates/bb-guide-threads.mdand the bb-cliSKILL.mddocument--planand the SDK helper.turn/startis unit-tested"):bridge.test.tsgains aturn/steercase (which is whatbb thread tell --planon a busy thread becomes): entering Plan mode from a steer, a plain follow-up turn and a repeated/plansteer not re-requesting it, re-entry after an approved plan restored the preset; and a case where a refusedsetPermissionMode("plan")fails the turn instead of running it in the old mode.session-params.test.tsassertsbuildClaudeTurnParamsforwards the flag and omits it otherwise. No bridge source changes.No wire change between server and host daemon, no
HOST_DAEMON_PROTOCOL_VERSIONorPROVIDER_BRIDGE_PROTOCOL_VERSIONbump, no new plugin API members.How you verified
Fail-before / pass-after on top of current
origin/main(git checkout origin/main -- <the 7 non-test source files>, run, restore):apps/cli/src/__tests__/command-output/thread-tell.test.ts"bb thread tell --plan sends the composer's /plan command mention" andthread-spawn.test.ts"bb thread spawn --plan opens the thread with the composer's /plan command mention": on mainerror: unknown option '--plan'(Tests 2 failed | 35 skipped); restored37 passed (37).packages/domain/test/shared-types.test.ts"builds plan command input the plan selector recognizes and strips": on mainTypeError: createBuiltinPlanCommandTextInput is not a function; restored11 passed (11).plugins/provider-claude-code: bridge + session-params84 passed (84)(the new bridge cases exercise code that is already on main via Enter Plan mode when a later Claude turn carries /plan #2157, so they pass on main too; they are coverage, not the proof).From the committed tree (
git status --porcelainempty):pnpm exec turbo run typecheck --filter=@bb/domain --filter=@bb/sdk --filter=@bb/cli --filter=@bb/templates --filter=bb-plugin-provider-claude-code --filter=@bb/server --filter=@bb/agent-runtime->Tasks: 11 successful, 11 totalpnpm exec turbo run test --filter=@bb/domain --filter=@bb/sdk --filter=@bb/cli --filter=@bb/templates --filter=bb-plugin-provider-claude-code->Tasks: 11 successful, 11 total(domain 151, sdk 96, cli 455, templates 41, claude plugin 326)pnpm exec turbo run test --filter=@bb/provider-parity --force->Tasks: 2 successful, 2 total(43 passed)apps/serverskill tests (builtin-skills-copy,injected-skills,install-cli-skills): 22 passed.Manual (earlier revision of this branch, before #2157 merged; the CLI path is unchanged): against my own dev instance with a real Claude Code session (
claude-haiku-4-5), spawned a claude-code thread in accept-edits, letReply only with ok.finish, thenbb thread tell <thr> --plan "Create a file named hello.txt ..."on the loaded session. The DBclient/turn/requestedevent carried the structured/plancommand mention, Claude entered Plan mode,ExitPlanModeproduced a pendingplaninteraction, no file was written;bb thread interactions approverestored accept-edits and created the file.Fixes #2019
Rebase
Rebased onto
origin/mainat75d6fc4d4(was 33 commits behind; conflicted inbridge.tsandbridge.test.ts). #2157 (eec134dc6) landed the same bridge fix this PR originally carried (enterRequestedPlanModehere,enterPlanModeIfRequestedthere; identical body, same call sites, same schema andbuildClaudeTurnParamshunks). Dropped every bridge source hunk (bridge.ts,commands.ts,session-params.ts) and this PR's copy of theturn/startregression test in favour of main's. Kept: the CLI--planflag, the domain helper and SDK export, guide/skill text, and the bridge test cases #2157 lacks (steer path, plan re-entry, refused switch, turn-params forwarding). Title, commit message, and this body were rewritten for the reduced scope; the fail-before/pass-after proof is now the CLI flag and domain helper.Independent verification (post-rebase)
Verified at
69f036642(PR head) againstorigin/main85eec4da6(one unrelated mobile-workflow commit past the rebase base75d6fc4d4;ghreports MERGEABLE).Root cause check: plan mode is keyed on a
/plancommand mention (resolvePromptMode->promptInputHasCommandMentioninapps/server/src/services/threads/thread-commands.ts); the plan composer action's command is always{trigger: "/", name: "plan"}(plugin-provider-registration.ts), so the hardcoded mention the helper builds matches both Claude Code and Codex. The loaded-session half is on main via #2157 (enterPlanModeIfRequestedinbridge.ts); this PR adds no bridge source.Fail-before / pass-after (
git checkout origin/main -- <9 non-test source files>, run,git checkout HEAD -- ...):apps/clithread-tell/thread-spawn--plantests on main sources:error: unknown option '--plan',Tests 2 failed | 35 skipped (37); restored: pass.packages/domain/test/shared-types.test.ts:TypeError: createBuiltinPlanCommandTextInput is not a function,1 failed | 10 passed; restored: pass.From the committed tree (
git status --porcelainempty), all with--force(no turbo cache):turbo run typecheck --filter=@bb/domain,@bb/sdk,@bb/cli,@bb/templates,bb-plugin-provider-claude-code,@bb/server,@bb/agent-runtime->Tasks: 11 successful, 11 totalturbo run testfor domain/sdk/cli/templates/claude plugin ->Tasks: 11 successful, 11 total(domain 151, sdk 96, cli 455, templates 41, claude plugin 326)turbo run test --filter=@bb/provider-parity --force->Tasks: 2 successful, 2 total(43 passed)apps/serverskill tests (builtin-skills-copy, injected-skills, install-cli-skills): 22 passed.Live repro on the PR branch (own dev instance, real Claude Code,
BB_CLIunset so the worktree CLI runs instead of re-execing the installed binary):bb thread spawn --provider claude-code --permission-mode accept-edits --plan --prompt ...: theclient/turn/requestedevent carries the structured/planmention, the Claude session started in Plan mode (its reasoning quotes the "Plan mode is active" reminder), the literal/planwas stripped, and there was no "/plan isn't available in this environment".bb thread stop, a plainbb thread tell ... "Reply only with ok."(session reloaded in accept-edits), thenbb thread tell <thr> "Add a LICENSE file (MIT)..." --planon that loaded session:bb thread interactions listshowsplan | pending | Plan ready for review, no file written.bb thread tell --planand--helpboth show and accept the flag.CI: all checks green on
69f036642(Checks, Package Smoke x2, Tests app-1..3/integration/packages/server).Residual notes (minor, not blocking):
--planon a provider that declares no plan composer action (pi, ACP agents) is not rejected by the server; the/plan ...text reaches the provider verbatim, same as typing it in the composer. The helper tags the mentionorigin: "builtin"while the composer's plan action usesorigin: "user"; nothing keys plan mode onorigin.