fix(cline): enforce plan hardening before presentation - #269
Merged
Conversation
First live test of the Cline plugin showed the plan gate rejecting an un-hardened plan only after the plan had been presented and approved: in Cline, switch_to_act_mode is called post-approval by design (present plan -> end turn -> user approves -> switch), unlike Claude Code where the plan text rides inside ExitPlanMode. There is no Cline hook moment before plan presentation (verified against CLI 3.0.51's agent runtime and @cline/shared AgentRuntimeHooks), so the gate is now two-layer: - a new slow-powers/plan-presentation rule (registerRule) tells plan-mode agents to run hardening-plans before presenting a plan - the only mechanism that reaches the agent pre-presentation; - the beforeTool hook on switch_to_act_mode becomes the pre-execution backstop: an already-hardened transcript short-circuit (parity with hooks/exit-plan-mode, issue #153) lets a hardened plan through with no beat, else skip-once instructs the agent to harden, re-present, and retry. Detection matches the skills tool-input shape only, so the hook's own skip reason cannot false-positive; - skip reason and plugin comments reworded: the hook gates execution, not presentation. Tested on the Cline harness: unit tests drive the real plugin module (5 new tests; bun test 167 pass / 0 fail). Interactive TUI confirmation of the gate remains a manual check (switch_to_act_mode is not exposed headlessly).
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.
Problem
First live test of the Cline plugin: the gate rejected an un-hardened plan after the plan had been presented and approved — when the agent called
switch_to_act_modeto move into act mode. The intent is for hardening-plans to run over the plan before it's presented to the user.Root cause
The plugin was modeled on Claude Code's
ExitPlanMode, where the plan text rides inside the tool call, so a PreToolUse deny lands before the user ever sees the plan. Cline CLI works differently — its own plan-mode system prompt and theswitch_to_act_modetool description mandate the sequence: present the plan as a free-form message → end the turn → user approves in a follow-up message → only then callswitch_to_act_mode. The hook was anchored to that last step, which is by design one approval late.I also verified the full plugin hook surface (installed CLI 3.0.51 agent runtime +
@cline/sharedAgentRuntimeHooksagree):beforeRun,afterRun,beforeModel,afterModel,beforeTool,afterTool,onEvent. Plan presentation is streamed assistant text — no hook fires before or at presentation, so no re-timing of a single hook can fix this; the enforcement layers had to move.Solution
Two-layer gate:
slow-powers/plan-presentationrule (registerRule) tells plan-mode agents to run hardening-plans on a draft before presenting it. A rule is the only mechanism that reaches the agent ahead of presentation.beforeToolonswitch_to_act_modegains the already-hardened short-circuit (parity withhooks/exit-plan-mode, issue Claude hook causes issues if hardening-plans is invoked autonomously #153): it scanssnapshot.messagesfor askillstool call naming hardening-plans. When the rule was followed, approval → switch passes with zero friction; when it wasn't, execution is blocked and the agent is instructed to harden, re-present the hardened plan, and retry. Detection matches the tool-input shape only (never prose), so the hook's own skip reason in the transcript cannot false-positive. The skip-once marker remains the fail-open floor — never hard-lock.Testing
bun test: 167 pass / 0 fail; typecheck and biome clean.cline -iplan-mode confirmation, sinceswitch_to_act_modeisn't exposed in headless sessions.No associated issue.