From 457550e8e576530b7928babff81c96598210bda5 Mon Sep 17 00:00:00 2001 From: Ben Limmer Date: Wed, 20 May 2026 10:51:55 -0600 Subject: [PATCH 1/2] feat: add planbridge-last skill --- .../claude/skills/planbridge-last/SKILL.md | 46 +++++++++++ .../codex/skills/planbridge-last/SKILL.md | 50 ++++++++++++ packages/cli/AGENTS.md | 2 +- .../cli/src/installers/CodexInstaller.test.ts | 55 ++++++++----- packages/skills/AGENTS.md | 2 +- .../skills/sources/planbridge-last/SKILL.md | 50 ++++++++++++ packages/skills/src/codex.ts | 3 +- packages/website/src/components/Faq.astro | 2 +- .../src/components/IntegrationCards.astro | 2 +- .../src/content/docs/recipes/superpowers.mdx | 14 ++-- .../src/content/docs/usage/claude-code.mdx | 7 +- .../website/src/content/docs/usage/codex.mdx | 22 ++++- .../website/src/content/docs/usage/index.mdx | 7 +- .../website/src/content/docs/usage/open.mdx | 80 ++++++++++++++----- 14 files changed, 281 insertions(+), 61 deletions(-) create mode 100644 harnessIntegrations/claude/skills/planbridge-last/SKILL.md create mode 100644 harnessIntegrations/codex/skills/planbridge-last/SKILL.md create mode 100644 packages/skills/sources/planbridge-last/SKILL.md diff --git a/harnessIntegrations/claude/skills/planbridge-last/SKILL.md b/harnessIntegrations/claude/skills/planbridge-last/SKILL.md new file mode 100644 index 0000000..f716d63 --- /dev/null +++ b/harnessIntegrations/claude/skills/planbridge-last/SKILL.md @@ -0,0 +1,46 @@ +--- +name: planbridge-last +description: Open your most recent assistant message in the PlanBridge browser UI for human annotation. Use when the user wants to annotate or give feedback on the wall of text you just wrote. +--- + +# Annotate your most recent message in PlanBridge + +Opens your most recent assistant message in the PlanBridge browser UI, where the user can leave inline annotations and general comments. Their feedback is returned on stdout. + +## When to use + +Use this skill when the user wants to mark up something you just said. Typical triggers: + +- "Let me annotate that" +- "Open the last thing you said in PlanBridge" +- "I want to mark up what you just wrote" +- You just produced a long block of prose, such as a spec, architecture explanation, migration plan, code-review summary, draft commit message, or brainstorming section, and the user wants to give targeted feedback. + +## How to invoke + +**Do not send any commentary or status message before running the command.** The command targets your most recent rendered message, so a preamble like "Sure, opening that now" can mistakenly become the thing being annotated. Run the command first; speak after. + +Pipe your prior message verbatim into `contextbridge open` via stdin. Preserve all markdown formatting and code blocks. Do not paraphrase, summarize, or rewrite. The user wants to annotate the exact text you produced, not a cleaned-up version. + + printf %s "" | contextbridge open + +Run the command yourself rather than telling the user to invoke shell syntax manually. + +## What happens + +1. PlanBridge starts a local browser session and prints the URL. +2. The user annotates in the browser. Block on the CLI until they submit. +3. The CLI prints a markdown summary of the user's feedback to stdout. + +## What to do with the output + +Treat the comments the way you would treat a colleague's review notes: context for the next step, not a checklist to silently execute. + +- If the user left no annotations, acknowledge briefly and continue. +- If the user left annotations, respond conversationally. They may want edits, may want discussion, or may be flagging things for later. When in doubt, ask what they want to do next. + +## Limitations + +Only your most recent assistant message is opened. To annotate a file on disk, an earlier message, or a specific section that is not your prior message, use `planbridge-open` instead. + +Very long messages, around 5k+ words, may drift or truncate during verbatim reproduction. For specs and other content of that size, save the content to a file first and use `planbridge-open` against the path. diff --git a/harnessIntegrations/codex/skills/planbridge-last/SKILL.md b/harnessIntegrations/codex/skills/planbridge-last/SKILL.md new file mode 100644 index 0000000..84f8944 --- /dev/null +++ b/harnessIntegrations/codex/skills/planbridge-last/SKILL.md @@ -0,0 +1,50 @@ +--- +name: planbridge-last +description: Open your most recent assistant message in the PlanBridge browser UI for human annotation. Use when the user wants to annotate or give feedback on the wall of text you just wrote. +--- + +# Annotate your most recent message in PlanBridge + +Opens your most recent assistant message in the PlanBridge browser UI, where the user can leave inline annotations and general comments. Their feedback is returned on stdout. + +## When to use + +Use this skill when the user wants to mark up something you just said. Typical triggers: + +- "Let me annotate that" +- "Open the last thing you said in PlanBridge" +- "I want to mark up what you just wrote" +- You just produced a long block of prose, such as a spec, architecture explanation, migration plan, code-review summary, draft commit message, or brainstorming section, and the user wants to give targeted feedback. + +## How to invoke + +**Do not send any commentary or status message before running the command.** The command targets your most recent rendered message, so a preamble like "Sure, opening that now" can mistakenly become the thing being annotated. Run the command first; speak after. + +Pipe your prior message verbatim into `contextbridge open` via stdin. Preserve all markdown formatting and code blocks. Do not paraphrase, summarize, or rewrite. The user wants to annotate the exact text you produced, not a cleaned-up version. + + printf %s "" | contextbridge open + +## Running this from Codex + +This skill runs commands that require resources outside Codex's default sandbox. When invoking them, set `sandbox_permissions: "require_escalated"` and supply a brief `justification` describing what the command does. If the user runs the command regularly, suggest a matching `prefix_rule` (e.g., `["contextbridge", ""]`) so future invocations don't require re-approval. + +Run the command yourself rather than telling the user to invoke shell syntax manually. + +## What happens + +1. PlanBridge starts a local browser session and prints the URL. +2. The user annotates in the browser. Block on the CLI until they submit. +3. The CLI prints a markdown summary of the user's feedback to stdout. + +## What to do with the output + +Treat the comments the way you would treat a colleague's review notes: context for the next step, not a checklist to silently execute. + +- If the user left no annotations, acknowledge briefly and continue. +- If the user left annotations, respond conversationally. They may want edits, may want discussion, or may be flagging things for later. When in doubt, ask what they want to do next. + +## Limitations + +Only your most recent assistant message is opened. To annotate a file on disk, an earlier message, or a specific section that is not your prior message, use `planbridge-open` instead. + +Very long messages, around 5k+ words, may drift or truncate during verbatim reproduction. For specs and other content of that size, save the content to a file first and use `planbridge-open` against the path. diff --git a/packages/cli/AGENTS.md b/packages/cli/AGENTS.md index c4ffa93..a0447c1 100644 --- a/packages/cli/AGENTS.md +++ b/packages/cli/AGENTS.md @@ -48,7 +48,7 @@ stdin / [path] ─▶ contextbridge plan { status: "approved" | "changes_requested", annotations: [...] } ``` -The loop is kind-agnostic: it serves a markdown document into the annotation UI and emits a structured result on stdout. Sibling entrypoints on this same loop today: `plan` (plan-mode handoffs from Claude Code and Codex hooks) and `open` (manual annotation of a markdown file or piped content, surfaced as `/planbridge-open` or `/planbridge:planbridge-open` in Claude and `$planbridge-open` in Codex). The CLI process owns the server and the browser lifecycle. When the user submits in the browser, the server shuts down and the CLI emits its structured result to stdout. That stdout contract is what harness hooks (Claude `exitPlanMode`, Codex Stop hook, etc.) consume. +The loop is kind-agnostic: it serves a markdown document into the annotation UI and emits a structured result on stdout. Sibling entrypoints on this same loop today: `plan` (plan-mode handoffs from Claude Code and Codex hooks) and `open` (manual annotation of a markdown file or piped content, surfaced through `planbridge-open` and `planbridge-last` skills in Claude and Codex). The CLI process owns the server and the browser lifecycle. When the user submits in the browser, the server shuts down and the CLI emits its structured result to stdout. That stdout contract is what harness hooks (Claude `exitPlanMode`, Codex Stop hook, etc.) consume. ## Build: embedded annotation UI diff --git a/packages/cli/src/installers/CodexInstaller.test.ts b/packages/cli/src/installers/CodexInstaller.test.ts index 6e1a724..8f5f29e 100644 --- a/packages/cli/src/installers/CodexInstaller.test.ts +++ b/packages/cli/src/installers/CodexInstaller.test.ts @@ -11,7 +11,6 @@ import { createStubContext, readErrorLogs } from '#src/testHelpers/index.ts'; import { CodexInstaller } from './CodexInstaller.ts'; const CODEX_BINARY = getHarness('codex').binaryName; -const bundledOpenSkill = bundledSkills.find((skill) => skill.installId === 'planbridge-open')?.body ?? ''; describe('CodexInstaller', () => { let tmp: string; @@ -149,25 +148,21 @@ describe('CodexInstaller', () => { expect(installPromise).rejects.toThrow(/^nope$/); }); - it('writes the skill to ~/.agents/skills/planbridge-open/SKILL.md on user-scope install', async () => { + it('writes bundled skills to ~/.agents/skills on user-scope install', async () => { const { installer, context } = createCodexInstallerContext(tmp); await installer.install(context, { yes: true }); - const skillPath = join(tmp, '.agents', 'skills', 'planbridge-open', 'SKILL.md'); - expect(existsSync(skillPath)).toBe(true); - expect(readFileSync(skillPath, 'utf8')).toBe(bundledOpenSkill); + expectBundledSkillsInstalled(tmp); }); - it('writes the skill at user level even on project-scope install', async () => { + it('writes bundled skills at user level even on project-scope install', async () => { const project = join(tmp, 'project'); const { installer, context } = createCodexInstallerContext(tmp, { projectRoot: project }); await installer.install(context, { yes: true, scope: 'project' }); - const skillPath = join(tmp, '.agents', 'skills', 'planbridge-open', 'SKILL.md'); - expect(existsSync(skillPath)).toBe(true); - expect(readFileSync(skillPath, 'utf8')).toBe(bundledOpenSkill); + expectBundledSkillsInstalled(tmp); }); it('skill install is idempotent', async () => { @@ -176,8 +171,7 @@ describe('CodexInstaller', () => { await installer.install(context, { yes: true }); await installer.install(context, { yes: true }); - const skillPath = join(tmp, '.agents', 'skills', 'planbridge-open', 'SKILL.md'); - expect(readFileSync(skillPath, 'utf8')).toBe(bundledOpenSkill); + expectBundledSkillsInstalled(tmp); }); }); @@ -219,7 +213,7 @@ describe('CodexInstaller', () => { expect(readFileSync(hooksPath, 'utf8')).toBe('{"hooks":[]}'); }); - it('user-scope uninstall removes planbridge-open/ but leaves sibling skill dirs intact', async () => { + it('user-scope uninstall removes bundled skills but leaves sibling skill dirs intact', async () => { const skillsDir = join(tmp, '.agents', 'skills'); await mkdir(join(skillsDir, 'some-other-tool'), { recursive: true }); await writeFile(join(skillsDir, 'some-other-tool', 'SKILL.md'), 'other tool skill'); @@ -228,7 +222,7 @@ describe('CodexInstaller', () => { await installer.uninstall(context, { yes: true }); - expect(existsSync(join(skillsDir, 'planbridge-open'))).toBe(false); + expectBundledSkillsAbsent(tmp); expect(readFileSync(join(skillsDir, 'some-other-tool', 'SKILL.md'), 'utf8')).toBe('other tool skill'); }); @@ -239,8 +233,7 @@ describe('CodexInstaller', () => { await installer.uninstall(context, { yes: true, scope: 'project' }); - const skillPath = join(tmp, '.agents', 'skills', 'planbridge-open', 'SKILL.md'); - expect(existsSync(skillPath)).toBe(true); + expectBundledSkillsInstalled(tmp); }); it('user-scope uninstall is idempotent when skill is already gone', async () => { @@ -265,7 +258,7 @@ describe('CodexInstaller', () => { }); }); - it('reports an installed hook and skill when both are present', async () => { + it('reports an installed hook and bundled skills when both are present', async () => { const { installer, context } = createCodexInstallerContext(tmp); await installer.install(context, { yes: true }); @@ -274,11 +267,9 @@ describe('CodexInstaller', () => { descriptor: { id: 'codex' }, detected: true, installed: true, - managed: [ - { kind: 'hook', identifier: 'contextbridge hook codex', scope: 'user' }, - { kind: 'skill', identifier: 'planbridge-open', scope: 'user' }, - ], }); + expect(status.managed).toContainEqual({ kind: 'hook', identifier: 'contextbridge hook codex', scope: 'user' }); + expectManagedBundledSkills(status.managed); }); it('reports hook-only state as installed because install owns feature setup', async () => { @@ -330,13 +321,13 @@ describe('CodexInstaller', () => { expect(installer.status(context)).rejects.toBeInstanceOf(CommanderError); }); - it('reports the skill as a ManagedEntry when installed', async () => { + it('reports bundled skills as ManagedEntries when installed', async () => { const { installer, context } = createCodexInstallerContext(tmp); await installer.install(context, { yes: true }); const status = await installer.status(context); - expect(status.managed).toContainEqual({ kind: 'skill', identifier: 'planbridge-open', scope: 'user' }); + expectManagedBundledSkills(status.managed); expect(status.installed).toBe(true); }); @@ -396,6 +387,26 @@ function writeHooksJson(path: string, value: unknown): void { writeFileSync(path, JSON.stringify(value)); } +function expectBundledSkillsInstalled(home: string): void { + for (const { installId, body } of bundledSkills) { + const skillPath = join(home, '.agents', 'skills', installId, 'SKILL.md'); + expect(existsSync(skillPath)).toBe(true); + expect(readFileSync(skillPath, 'utf8')).toBe(body); + } +} + +function expectBundledSkillsAbsent(home: string): void { + for (const { installId } of bundledSkills) { + expect(existsSync(join(home, '.agents', 'skills', installId))).toBe(false); + } +} + +function expectManagedBundledSkills(managed: readonly unknown[]): void { + for (const { installId } of bundledSkills) { + expect(managed).toContainEqual({ kind: 'skill', identifier: installId, scope: 'user' }); + } +} + function commandRunnerCalls(context: ReturnType['context'], args: readonly string[]) { const commandRunner = context.commandRunner as unknown as { callsTo(cmd: string, args: readonly string[]): readonly unknown[]; diff --git a/packages/skills/AGENTS.md b/packages/skills/AGENTS.md index 18d99d8..c4640b3 100644 --- a/packages/skills/AGENTS.md +++ b/packages/skills/AGENTS.md @@ -47,7 +47,7 @@ Partials emit content directly. Wrap them in a `{{#if (eq harness.id "…")}}` b 4. `bun run skills:check && bun run --cwd packages/cli test`. 5. Commit `sources/`, every `harnessIntegrations//skills/...`, and the `codex.ts` change together. -For the manual open skill, Claude may expose `/planbridge-open` or `/planbridge:planbridge-open`; Codex exposes `$planbridge-open`. +For manual skills, Claude may expose `/planbridge-open` or `/planbridge:planbridge-open` (and similarly for `/planbridge-last`); Codex exposes `$planbridge-open` and `$planbridge-last`. ## Adding a new harness diff --git a/packages/skills/sources/planbridge-last/SKILL.md b/packages/skills/sources/planbridge-last/SKILL.md new file mode 100644 index 0000000..8d84955 --- /dev/null +++ b/packages/skills/sources/planbridge-last/SKILL.md @@ -0,0 +1,50 @@ +--- +name: planbridge-last +description: Open your most recent assistant message in the PlanBridge browser UI for human annotation. Use when the user wants to annotate or give feedback on the wall of text you just wrote. +--- + +# Annotate your most recent message in PlanBridge + +Opens your most recent assistant message in the PlanBridge browser UI, where the user can leave inline annotations and general comments. Their feedback is returned on stdout. + +## When to use + +Use this skill when the user wants to mark up something you just said. Typical triggers: + +- "Let me annotate that" +- "Open the last thing you said in PlanBridge" +- "I want to mark up what you just wrote" +- You just produced a long block of prose, such as a spec, architecture explanation, migration plan, code-review summary, draft commit message, or brainstorming section, and the user wants to give targeted feedback. + +## How to invoke + +**Do not send any commentary or status message before running the command.** The command targets your most recent rendered message, so a preamble like "Sure, opening that now" can mistakenly become the thing being annotated. Run the command first; speak after. + +Pipe your prior message verbatim into `contextbridge open` via stdin. Preserve all markdown formatting and code blocks. Do not paraphrase, summarize, or rewrite. The user wants to annotate the exact text you produced, not a cleaned-up version. + + printf %s "" | contextbridge open + +{{#if (eq harness.id "codex")}} +{{> codex/sandbox-escalation}} +{{/if}} + +Run the command yourself rather than telling the user to invoke shell syntax manually. + +## What happens + +1. PlanBridge starts a local browser session and prints the URL. +2. The user annotates in the browser. Block on the CLI until they submit. +3. The CLI prints a markdown summary of the user's feedback to stdout. + +## What to do with the output + +Treat the comments the way you would treat a colleague's review notes: context for the next step, not a checklist to silently execute. + +- If the user left no annotations, acknowledge briefly and continue. +- If the user left annotations, respond conversationally. They may want edits, may want discussion, or may be flagging things for later. When in doubt, ask what they want to do next. + +## Limitations + +Only your most recent assistant message is opened. To annotate a file on disk, an earlier message, or a specific section that is not your prior message, use `planbridge-open` instead. + +Very long messages, around 5k+ words, may drift or truncate during verbatim reproduction. For specs and other content of that size, save the content to a file first and use `planbridge-open` against the path. diff --git a/packages/skills/src/codex.ts b/packages/skills/src/codex.ts index 7d684d3..cd79e82 100644 --- a/packages/skills/src/codex.ts +++ b/packages/skills/src/codex.ts @@ -1,3 +1,4 @@ +import planbridgeLastSkill from '../../../harnessIntegrations/codex/skills/planbridge-last/SKILL.md' with { type: 'text' }; import planbridgeOpenSkill from '../../../harnessIntegrations/codex/skills/planbridge-open/SKILL.md' with { type: 'text' }; import { parseSkill } from './skills.ts'; @@ -8,7 +9,7 @@ export interface BundledSkill { readonly body: string; } -export const bundledSkills: readonly BundledSkill[] = [planbridgeOpenSkill].map((body) => ({ +export const bundledSkills: readonly BundledSkill[] = [planbridgeOpenSkill, planbridgeLastSkill].map((body) => ({ installId: parseSkill(body).frontmatter.name, body, })); diff --git a/packages/website/src/components/Faq.astro b/packages/website/src/components/Faq.astro index 817087c..e1d4390 100644 --- a/packages/website/src/components/Faq.astro +++ b/packages/website/src/components/Faq.astro @@ -14,7 +14,7 @@ const faqs = [ { question: 'Can I open a file in PlanBridge without going through plan mode?', answer: - 'Yes. The /planbridge-open skill (Claude Code) and $planbridge-open skill (Codex CLI) open any markdown file in the PlanBridge UI on demand. See Open arbitrary content.', + 'Yes. The planbridge-open skill opens any markdown file in the PlanBridge UI on demand. Use planbridge-last to annotate the agent's previous message. See Open arbitrary content.', }, { question: 'Does PlanBridge take over my agent workflow?', diff --git a/packages/website/src/components/IntegrationCards.astro b/packages/website/src/components/IntegrationCards.astro index 439b12b..73c5eb2 100644 --- a/packages/website/src/components/IntegrationCards.astro +++ b/packages/website/src/components/IntegrationCards.astro @@ -63,7 +63,7 @@ import InstallActions from './InstallActions.astro';

- Open any file manually with the /planbridge-open skill → + Open files or the agent's last message manually →

diff --git a/packages/website/src/content/docs/recipes/superpowers.mdx b/packages/website/src/content/docs/recipes/superpowers.mdx index c991608..2bf9bad 100644 --- a/packages/website/src/content/docs/recipes/superpowers.mdx +++ b/packages/website/src/content/docs/recipes/superpowers.mdx @@ -12,7 +12,7 @@ There are two pause points in the Superpowers workflow where PlanBridge fits wel ## Manual -Trigger PlanBridge yourself with the `planbridge-open` slash command. This allows you to respond to some superpowers sections (like short brainstorming sections) in the terminal UI, while opening larger sections in PlanBridge to provide more precise feedback. +Trigger PlanBridge yourself with the `planbridge-last` or `planbridge-open` slash command. Use `planbridge-last` for the section the agent just wrote, and `planbridge-open` for saved spec files. ### During brainstorming @@ -22,10 +22,10 @@ Pull the most recent section into PlanBridge: - + - + @@ -57,9 +57,9 @@ If you want PlanBridge to fire at both pause points without you asking, append a code={`echo ' ## Superpowers + PlanBridge -When using the Superpowers \`brainstorming\` skill, use the \`/planbridge-open\` slash command at these pause points: +When using the Superpowers \`brainstorming\` skill, use PlanBridge at these pause points: -- When presenting design sections for approval (the "Present design" step, covering architecture, components, data flow, error handling, testing), run \`/planbridge-open the section you just wrote\` instead of asking for text approval. +- When presenting design sections for approval (the "Present design" step, covering architecture, components, data flow, error handling, testing), run \`/planbridge-last\` instead of asking for text approval. - When writing a spec file under \`docs/superpowers/specs/\`, run \`/planbridge-open the spec you just wrote\` instead of asking me to review it as text. Treat the returned annotations as my review feedback. Clarifying questions and approach proposals stay in the terminal. @@ -73,9 +73,9 @@ Treat the returned annotations as my review feedback. Clarifying questions and a code={`echo ' ## Superpowers + PlanBridge -When using the Superpowers \`brainstorming\` skill, use the \`$planbridge-open\` slash command at these pause points: +When using the Superpowers \`brainstorming\` skill, use PlanBridge at these pause points: -- When presenting design sections for approval (the "Present design" step, covering architecture, components, data flow, error handling, testing), run \`$planbridge-open the section you just wrote\` instead of asking for text approval. +- When presenting design sections for approval (the "Present design" step, covering architecture, components, data flow, error handling, testing), run \`$planbridge-last\` instead of asking for text approval. - When writing a spec file under \`docs/superpowers/specs/\`, run \`$planbridge-open the spec you just wrote\` instead of asking me to review it as text. Treat the returned annotations as my review feedback. Clarifying questions and approach proposals stay in the terminal. diff --git a/packages/website/src/content/docs/usage/claude-code.mdx b/packages/website/src/content/docs/usage/claude-code.mdx index 5f207da..c6b44a6 100644 --- a/packages/website/src/content/docs/usage/claude-code.mdx +++ b/packages/website/src/content/docs/usage/claude-code.mdx @@ -58,9 +58,12 @@ If you installed Claude Code _after_ the install script ran, or if `install stat Or `contextbridge uninstall` to remove PlanBridge plugin and hook entries from every harness it was installed into. -## Open a file manually +## Open content manually -The plan-mode hook fires automatically. If you want to pull an arbitrary markdown file into the PlanBridge UI on demand (a design doc, an RFC, a plan written outside of plan mode), use the `/planbridge-open` skill that ships with the plugin. Claude Code may show it as `/planbridge:planbridge-open` in the slash-command picker. See [Open arbitrary content](/usage/open/). +The plan-mode hook fires automatically. + +- To pull an arbitrary markdown file into the PlanBridge UI on demand, use `/planbridge-open`. +- To annotate the agent's last message, use `/planbridge-last`. See [Open arbitrary content](/usage/open/). ## Reference diff --git a/packages/website/src/content/docs/usage/codex.mdx b/packages/website/src/content/docs/usage/codex.mdx index 1be36b4..0f393e2 100644 --- a/packages/website/src/content/docs/usage/codex.mdx +++ b/packages/website/src/content/docs/usage/codex.mdx @@ -132,12 +132,30 @@ You should see Codex CLI listed as installed. Or `contextbridge uninstall` to remove PlanBridge plugin and hook entries from every harness it was installed into. -## Open a file manually +## Open content manually -The `Stop` hook fires automatically. To pull an arbitrary markdown file into the PlanBridge UI on demand, use the `$planbridge-open` skill that `contextbridge install codex` writes to `~/.agents/skills/planbridge-open/`. See [Open arbitrary content](/usage/open/). +The `Stop` hook fires automatically and opens plans for review (if you're in Codex's plan mode). + +- To pull an arbitrary markdown file into the PlanBridge UI on demand, use `$planbridge-open`. +- To annotate the agent's previous message, use `$planbridge-last`. + +`contextbridge install codex` writes both skills to `~/.agents/skills/`. See [Open arbitrary content](/usage/open/). ## Troubleshooting +### PlanBridge not opening plans automatically + +Our hook fires automatically when Codex stops and presents a plan from _within their native Plan mode_. You can enter Plan mode via "Shift + Tab". +It'll look like this when you're in Plan Mode: + +```shell +› + + gpt-5.5 xhigh · ~/code/my-repo Plan mode (shift+tab to cycle) +``` + +If you don't like Codex's Plan mode, you can use `$planbridge-open` or `$planbridge-last` to open arbitrary content. + ### `[features].codex_hooks` deprecation warning If you installed PlanBridge against an older Codex CLI (before `0.129.0`), you may see this warning every time Codex starts: diff --git a/packages/website/src/content/docs/usage/index.mdx b/packages/website/src/content/docs/usage/index.mdx index 0cb6cc2..784cb14 100644 --- a/packages/website/src/content/docs/usage/index.mdx +++ b/packages/website/src/content/docs/usage/index.mdx @@ -7,7 +7,12 @@ PlanBridge has two paths into the browser review UI. **As a harness hook.** Your AI coding agent calls `contextbridge` through its standard plugin or hook system at decision points, a human annotates in the browser, and the decision flows back to the agent. The [install script](/install/) adds those entries for any supported harness it detects. -**As a manual skill.** You invoke `/planbridge-open ` in Claude Code or `$planbridge-open ` in Codex CLI and your agent opens any markdown file in the browser for review. See [Open arbitrary content](/usage/open/). +**As a manual skill.** You ask your agent to open content in the browser outside the automatic hook flow: + +- Use `/planbridge-open ` in Claude Code or `$planbridge-open ` in Codex CLI for markdown files. +- Use `/planbridge-last` in Claude Code or `$planbridge-last` in Codex CLI for the agent's last message. + +See [Open arbitrary content](/usage/open/). ## Supported harnesses diff --git a/packages/website/src/content/docs/usage/open.mdx b/packages/website/src/content/docs/usage/open.mdx index 67de00f..ab96cab 100644 --- a/packages/website/src/content/docs/usage/open.mdx +++ b/packages/website/src/content/docs/usage/open.mdx @@ -3,39 +3,75 @@ title: Open arbitrary content description: Ask your coding agent to open any markdown file in the PlanBridge browser UI for human annotation. --- +import { Tabs, TabItem } from '@astrojs/starlight/components'; import { Code } from 'astro-expressive-code/components'; - - - + + + + + + + + The file opens in your browser for inline annotation. Your comments come back to the agent on stdout. -This is the manual sibling to the automatic hook flow. Hooks fire when your agent finishes planning. The `open` skill fires whenever you ask for it. +This is the manual sibling to the automatic hook flow. Hooks fire when your agent finishes planning. The `open` and `last` skills fire whenever you ask for them. ## When to use it - You want inline comments on a design doc, RFC, or spec. -- Your agent uses a workflow that bypasses plan mode. For example, the [obra/superpowers](https://github.com/obra/superpowers) plugin never enters Claude Code's plan mode. However, you can still use PlanBridge with it! See the [Superpowers recipe](/recipes/superpowers/) page for details. +- You want to mark up the long answer your agent just wrote. +- Your agent uses a workflow that bypasses plan mode. For example, the [obra/superpowers](https://github.com/obra/superpowers) plugin never enters Claude Code's plan mode. However, you can still use PlanBridge with it. See the [Superpowers recipe](/recipes/superpowers/) page for details. - You want to redirect the agent before it starts work, and the relevant context lives in a file rather than in plan mode. -## Claude Code - -The `planbridge-open` skill ships with the `planbridge@contextbridge` Claude plugin. Invoke it inside Claude Code with: - - - -Claude Code may display the same plugin skill as `/planbridge:planbridge-open`. Use that form if it appears in your slash-command picker. - -You can also describe the file in plain language and Claude resolves it: - - - -## Codex CLI - -`contextbridge install codex` writes the skill to `~/.agents/skills/planbridge-open/SKILL.md`. Invoke it inside Codex with: - - +## Agent skills + +Use `planbridge-open` for files: + + + + + + + + + + +Use `planbridge-last` for the agent's previous message: + + + + + + + + + + +You can also describe the file in plain language and your agent resolves it: + + + + + + + + + + + + + The `planbridge-open` and `planbridge-last` skills ship with the `planbridge@contextbridge` Claude plugin. + + Claude Code may display plugin skills as `/planbridge:planbridge-open` and `/planbridge:planbridge-last`. Use those forms if they appear in your slash-command picker. + + + + `contextbridge install codex` writes both skills to `~/.agents/skills/`. + + ## What you see From 82efd7c1c296ffc71a5f0630881749a79f8d1d90 Mon Sep 17 00:00:00 2001 From: Ben Limmer Date: Wed, 20 May 2026 11:01:08 -0600 Subject: [PATCH 2/2] fix: improve message --- .../claude/skills/planbridge-last/SKILL.md | 14 +++++++++++--- .../codex/skills/planbridge-last/SKILL.md | 16 ++++++++++++---- .../codex/skills/planbridge-open/SKILL.md | 2 +- .../_partials/codex/sandbox-escalation.md | 2 +- packages/skills/sources/planbridge-last/SKILL.md | 14 +++++++++++--- 5 files changed, 36 insertions(+), 12 deletions(-) diff --git a/harnessIntegrations/claude/skills/planbridge-last/SKILL.md b/harnessIntegrations/claude/skills/planbridge-last/SKILL.md index f716d63..2c7a7c7 100644 --- a/harnessIntegrations/claude/skills/planbridge-last/SKILL.md +++ b/harnessIntegrations/claude/skills/planbridge-last/SKILL.md @@ -20,12 +20,20 @@ Use this skill when the user wants to mark up something you just said. Typical t **Do not send any commentary or status message before running the command.** The command targets your most recent rendered message, so a preamble like "Sure, opening that now" can mistakenly become the thing being annotated. Run the command first; speak after. -Pipe your prior message verbatim into `contextbridge open` via stdin. Preserve all markdown formatting and code blocks. Do not paraphrase, summarize, or rewrite. The user wants to annotate the exact text you produced, not a cleaned-up version. +Copy the immediately previous assistant response from the conversation context and pipe it verbatim into `contextbridge open` via stdin. Preserve all markdown formatting and code blocks. Do not paraphrase, summarize, or rewrite. The user wants to annotate the exact text you produced, not a cleaned-up version. - printf %s "" | contextbridge open +```sh +contextbridge open <<'PLANBRIDGE_LAST_MESSAGE' + +PLANBRIDGE_LAST_MESSAGE +``` Run the command yourself rather than telling the user to invoke shell syntax manually. +If the previous assistant response is no longer available in conversation context, say so and ask the user to provide the content or use `planbridge-open` for a file or specific document. + +If `contextbridge` is not available on PATH, report that the PlanBridge CLI is unavailable in the current user environment. + ## What happens 1. PlanBridge starts a local browser session and prints the URL. @@ -41,6 +49,6 @@ Treat the comments the way you would treat a colleague's review notes: context f ## Limitations -Only your most recent assistant message is opened. To annotate a file on disk, an earlier message, or a specific section that is not your prior message, use `planbridge-open` instead. +Only your immediately previous assistant response is opened. To annotate a file on disk, an earlier message, or a specific section that is not your prior message, use `planbridge-open` instead. Very long messages, around 5k+ words, may drift or truncate during verbatim reproduction. For specs and other content of that size, save the content to a file first and use `planbridge-open` against the path. diff --git a/harnessIntegrations/codex/skills/planbridge-last/SKILL.md b/harnessIntegrations/codex/skills/planbridge-last/SKILL.md index 84f8944..644fbc4 100644 --- a/harnessIntegrations/codex/skills/planbridge-last/SKILL.md +++ b/harnessIntegrations/codex/skills/planbridge-last/SKILL.md @@ -20,16 +20,24 @@ Use this skill when the user wants to mark up something you just said. Typical t **Do not send any commentary or status message before running the command.** The command targets your most recent rendered message, so a preamble like "Sure, opening that now" can mistakenly become the thing being annotated. Run the command first; speak after. -Pipe your prior message verbatim into `contextbridge open` via stdin. Preserve all markdown formatting and code blocks. Do not paraphrase, summarize, or rewrite. The user wants to annotate the exact text you produced, not a cleaned-up version. +Copy the immediately previous assistant response from the conversation context and pipe it verbatim into `contextbridge open` via stdin. Preserve all markdown formatting and code blocks. Do not paraphrase, summarize, or rewrite. The user wants to annotate the exact text you produced, not a cleaned-up version. - printf %s "" | contextbridge open +```sh +contextbridge open <<'PLANBRIDGE_LAST_MESSAGE' + +PLANBRIDGE_LAST_MESSAGE +``` ## Running this from Codex -This skill runs commands that require resources outside Codex's default sandbox. When invoking them, set `sandbox_permissions: "require_escalated"` and supply a brief `justification` describing what the command does. If the user runs the command regularly, suggest a matching `prefix_rule` (e.g., `["contextbridge", ""]`) so future invocations don't require re-approval. +In sandboxed Codex environments, this skill usually requires resources outside the default sandbox. When invoking the command, set `sandbox_permissions: "require_escalated"` and supply a brief `justification` describing what the command does. If the user runs the command regularly, suggest a matching `prefix_rule` (e.g., `["contextbridge", "open"]`) so future invocations don't require re-approval. Run the command yourself rather than telling the user to invoke shell syntax manually. +If the previous assistant response is no longer available in conversation context, say so and ask the user to provide the content or use `planbridge-open` for a file or specific document. + +If `contextbridge` is not available on PATH, report that the PlanBridge CLI is unavailable in the current user environment. + ## What happens 1. PlanBridge starts a local browser session and prints the URL. @@ -45,6 +53,6 @@ Treat the comments the way you would treat a colleague's review notes: context f ## Limitations -Only your most recent assistant message is opened. To annotate a file on disk, an earlier message, or a specific section that is not your prior message, use `planbridge-open` instead. +Only your immediately previous assistant response is opened. To annotate a file on disk, an earlier message, or a specific section that is not your prior message, use `planbridge-open` instead. Very long messages, around 5k+ words, may drift or truncate during verbatim reproduction. For specs and other content of that size, save the content to a file first and use `planbridge-open` against the path. diff --git a/harnessIntegrations/codex/skills/planbridge-open/SKILL.md b/harnessIntegrations/codex/skills/planbridge-open/SKILL.md index 90cb476..e269f16 100644 --- a/harnessIntegrations/codex/skills/planbridge-open/SKILL.md +++ b/harnessIntegrations/codex/skills/planbridge-open/SKILL.md @@ -28,7 +28,7 @@ The CLI takes a file path or stdin content: ## Running this from Codex -This skill runs commands that require resources outside Codex's default sandbox. When invoking them, set `sandbox_permissions: "require_escalated"` and supply a brief `justification` describing what the command does. If the user runs the command regularly, suggest a matching `prefix_rule` (e.g., `["contextbridge", ""]`) so future invocations don't require re-approval. +In sandboxed Codex environments, this skill usually requires resources outside the default sandbox. When invoking the command, set `sandbox_permissions: "require_escalated"` and supply a brief `justification` describing what the command does. If the user runs the command regularly, suggest a matching `prefix_rule` (e.g., `["contextbridge", "open"]`) so future invocations don't require re-approval. ### Resolving the argument diff --git a/packages/skills/sources/_partials/codex/sandbox-escalation.md b/packages/skills/sources/_partials/codex/sandbox-escalation.md index e1795de..5acf104 100644 --- a/packages/skills/sources/_partials/codex/sandbox-escalation.md +++ b/packages/skills/sources/_partials/codex/sandbox-escalation.md @@ -1,3 +1,3 @@ ## Running this from Codex -This skill runs commands that require resources outside Codex's default sandbox. When invoking them, set `sandbox_permissions: "require_escalated"` and supply a brief `justification` describing what the command does. If the user runs the command regularly, suggest a matching `prefix_rule` (e.g., `["contextbridge", ""]`) so future invocations don't require re-approval. +In sandboxed Codex environments, this skill usually requires resources outside the default sandbox. When invoking the command, set `sandbox_permissions: "require_escalated"` and supply a brief `justification` describing what the command does. If the user runs the command regularly, suggest a matching `prefix_rule` (e.g., `["contextbridge", "open"]`) so future invocations don't require re-approval. diff --git a/packages/skills/sources/planbridge-last/SKILL.md b/packages/skills/sources/planbridge-last/SKILL.md index 8d84955..3ced28d 100644 --- a/packages/skills/sources/planbridge-last/SKILL.md +++ b/packages/skills/sources/planbridge-last/SKILL.md @@ -20,9 +20,13 @@ Use this skill when the user wants to mark up something you just said. Typical t **Do not send any commentary or status message before running the command.** The command targets your most recent rendered message, so a preamble like "Sure, opening that now" can mistakenly become the thing being annotated. Run the command first; speak after. -Pipe your prior message verbatim into `contextbridge open` via stdin. Preserve all markdown formatting and code blocks. Do not paraphrase, summarize, or rewrite. The user wants to annotate the exact text you produced, not a cleaned-up version. +Copy the immediately previous assistant response from the conversation context and pipe it verbatim into `contextbridge open` via stdin. Preserve all markdown formatting and code blocks. Do not paraphrase, summarize, or rewrite. The user wants to annotate the exact text you produced, not a cleaned-up version. - printf %s "" | contextbridge open +```sh +contextbridge open <<'PLANBRIDGE_LAST_MESSAGE' + +PLANBRIDGE_LAST_MESSAGE +``` {{#if (eq harness.id "codex")}} {{> codex/sandbox-escalation}} @@ -30,6 +34,10 @@ Pipe your prior message verbatim into `contextbridge open` via stdin. Preserve a Run the command yourself rather than telling the user to invoke shell syntax manually. +If the previous assistant response is no longer available in conversation context, say so and ask the user to provide the content or use `planbridge-open` for a file or specific document. + +If `contextbridge` is not available on PATH, report that the PlanBridge CLI is unavailable in the current user environment. + ## What happens 1. PlanBridge starts a local browser session and prints the URL. @@ -45,6 +53,6 @@ Treat the comments the way you would treat a colleague's review notes: context f ## Limitations -Only your most recent assistant message is opened. To annotate a file on disk, an earlier message, or a specific section that is not your prior message, use `planbridge-open` instead. +Only your immediately previous assistant response is opened. To annotate a file on disk, an earlier message, or a specific section that is not your prior message, use `planbridge-open` instead. Very long messages, around 5k+ words, may drift or truncate during verbatim reproduction. For specs and other content of that size, save the content to a file first and use `planbridge-open` against the path.