Codex Plan Mode CI/CD Implementation | Building Auto Plan Review with GitHub Actions¶
This is a follow-up to the morning article
Morning article: Codex CLI Plan Mode Practical Guide
Goals¶
- Auto-generate Codex plan mode execution plans driven by PR comments
- Build safe automation flow that only executes approved plans
- Implement automatic rollback and detailed logging on errors
Architecture Overview¶
PR Comment → Workflow Trigger → Plan Generation → Plan Review (Human) → Approval → Execute → Commit
↓ ↓ ↓
/codex [prompt] codex --plan /approve label codex (normal)
Flow Details: 1. Post /codex [prompt] in PR comment 2. GitHub Actions generates execution plan in plan mode 3. Auto-post generated plan to PR comment 4. Reviewer checks plan content and adds approved-plan label 5. Label triggers normal mode execution 6. Auto-commit & push changes
Implementation Steps¶
Step 1: Plan Generation Workflow¶
.github/workflows/codex-plan-generator.yml:
name: Codex Plan Generator
on:
issue_comment:
types: [created]
jobs:
generate-plan:
if: startsWith(github.event.comment.body, '/codex ')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Extract prompt
id: prompt
env:
COMMENT_BODY: "${{ github.event.comment.body }}"
run: |
PROMPT="${COMMENT_BODY#/codex }"
echo "text=$PROMPT" >> $GITHUB_OUTPUT
- name: Generate execution plan
id: plan
env:
PLAN_PROMPT: "${{ steps.prompt.outputs.text }}"
run: |
codex --plan "$PLAN_PROMPT" > plan.txt 2>&1
EXIT_CODE=$?
if [ $EXIT_CODE -ne 0 ]; then
echo "error=true" >> $GITHUB_OUTPUT
fi
continue-on-error: true
- name: Post plan as comment
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const plan = fs.readFileSync('plan.txt', 'utf8');
const isError = '${{ steps.plan.outputs.error }}' === 'true';
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: isError
? `❌ Plan generation failed\n\`\`\`\n${plan}\n\`\`\``
: `## 📋 Execution Plan\n\`\`\`\n${plan}\n\`\`\`\n\n✅ Review and add \`approved-plan\` label to execute.`
});
Step 2: Post-Approval Execution Workflow¶
.github/workflows/codex-executor.yml:
name: Codex Executor
on:
pull_request:
types: [labeled]
jobs:
execute-plan:
if: github.event.label.name == 'approved-plan'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get approved prompt
id: prompt
uses: actions/github-script@v7
with:
script: |
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number
});
const codexComment = comments.data
.reverse()
.find(c => c.body.startsWith('/codex '));
if (!codexComment) {
core.setFailed('No /codex command found');
return;
}
const prompt = codexComment.body.replace(/^\/codex /, '');
core.setOutput('text', prompt);
- name: Execute with Codex
env:
PLAN_PROMPT: "${{ steps.prompt.outputs.text }}"
run: |
codex "$PLAN_PROMPT"
- name: Commit changes
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add .
git commit -m "chore: apply codex changes [codex]" || exit 0
git push
Step 3: Error Handling and Rollback¶
Failure Detection:
- name: Execute with validation
id: execute
env:
PLAN_PROMPT: "${{ steps.prompt.outputs.text }}"
run: |
codex "$PLAN_PROMPT" 2>&1 | tee execution.log
EXIT_CODE=${PIPESTATUS[0]}
if [ $EXIT_CODE -ne 0 ]; then
echo "failed=true" >> $GITHUB_OUTPUT
fi
continue-on-error: true
- name: Rollback on failure
if: steps.execute.outputs.failed == 'true'
run: |
git reset --hard HEAD
git clean -fd
Detailed Log Posting:
- name: Post execution result
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const log = fs.readFileSync('execution.log', 'utf8');
const failed = '${{ steps.execute.outputs.failed }}' === 'true';
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: failed
? `❌ Execution failed\n\`\`\`\n${log}\n\`\`\``
: `✅ Changes applied successfully\n<details><summary>Execution log</summary>\n\n\`\`\`\n${log}\n\`\`\`\n</details>`
});
Benchmark / Comparison¶
| Condition | Manual | Plan Mode Manual | CI/CD Integration | Notes |
|---|---|---|---|---|
| Plan review time | 0min (none) | 1-2min | Auto (in PR) | Async review possible with CI |
| Approval process | None | Verbal | Label-based | Audit log auto-recorded |
| Error handling | Manual fix | Manual fix | Auto rollback | Production safety improved |
| Multi-person collaboration | Difficult | Difficult | Smooth | Transparency via PR comments |
Actual measurement: For 5-file change task, entire flow (plan review → approval → execution) completed in average 3.2 minutes (8-10 minutes manually).
Failure Patterns and Solutions¶
| Symptom | Cause | Solution |
|---|---|---|
| Empty plan generation | Prompt extraction failed | Add debug output for steps.prompt.outputs.text |
| Prompt mismatch at execution | Comment history retrieval order error | Use .reverse() to search from latest |
| Execution before approval | Label condition error | Strictly specify if: github.event.label.name == 'approved-plan' |
| Commit permission error | GITHUB_TOKEN scope insufficient | Add permissions: contents: write to job |
Automation / Extension Ideas¶
- Multi-plan comparison: Generate plan 3 times with same prompt and visualize differences
- Semantic versioning integration: Auto-infer version number from change content
- Slack notification integration: Auto-post pending plans to Slack channel
- Plan approval deadline: Auto-close if not approved within 24 hours
- Diff highlighting: Generate HTML report showing plan.txt and git diff side-by-side
Next Steps¶
- Codex CLI Auto Approval Mode Complete Guide - Further automation with
--approval-policy - Advanced GitHub Actions Conditional Patterns - Workflow optimization applications