Skip to content
CI/CD & Automation Advanced

Plan Mode in CI

Generate a plan in CI, post for human review, then execute on approval

Command

"color:#9CA3AF;font-style:italic"># Step 1: Generate plan
$ PLAN_RESULT=$("color:#7C5CFC">claude -p "Fix all lint errors in src/" \
    "color:#d97757">--permission-mode plan "color:#d97757">--output-format json "color:#d97757">--max-budget-usd 0.50)
  
"color:#9CA3AF;font-style:italic"># Step 2: Post plan as PR comment
$ PLAN=$("color:#7C5CFC">echo "$PLAN_RESULT" | "color:#7C5CFC">jq -r '.permission_denials[] | select(.tool_name=="ExitPlanMode") | .tool_input.plan')
  "color:#7C5CFC">gh pr comment "$PR" "color:#d97757">--body "$PLAN"
  
"color:#9CA3AF;font-style:italic"># Step 3: Execute on approval
$ SESSION=$("color:#7C5CFC">echo "$PLAN_RESULT" | "color:#7C5CFC">jq -r '.session_id')
  "color:#7C5CFC">claude -p "yes, proceed" "color:#d97757">--resume "$SESSION" "color:#d97757">--permission-mode bypassPermissions

Response

{
  "permission_denials": [
    {
      "tool_name": "ExitPlanMode",
      "tool_input": { "plan": "# Fix Lint Errors\n## Step 1: ..." }
    }
  ]
}

Parsing Code

059669">">const plan = data.permission_denials
  .find(d => d.tool_name === 059669059669">">'ExitPlanMode')?.tool_input.plan;

059669">">// Post to GitHub PR
await octokit.issues.createComment({
  issue_number: prNumber,
  body: 059669">`## Claude's Plan\n${plan}`
});

Gotchas

! Plan text location: permission_denials[].tool_input.plan where tool_name == 'ExitPlanMode'
! Resume with --permission-mode bypassPermissions to execute the approved plan

Related Recipes