[FEATURE] PrePlanMode and PostPlanMode Hook Events

Status Open
Maintainer reply None cached
Activity 15 comments · opened Dec 17, 2025

Feature Request: PrePlanMode and PostPlanMode Hook Events

Summary

Users who create plans in Claude Code cannot hook into plan mode lifecycle events. Adding PrePlanMode and PostPlanMode hook events would enable workflows like archiving existing plans before overwrite, validating prerequisites, and post-plan processing.

Problem Description

Current Behavior

  1. User enters plan mode (via /plan or plan permission mode)
  2. Claude creates/updates plan file at ~/.claude/plans/<session-name>.md
  3. If a plan already exists in that file, it gets overwritten with no backup
  4. There's no way to hook into this process

Expected Behavior

Users should be able to:

  • PrePlanMode: Run hooks before plan mode starts (archive existing plan, validate state)
  • PostPlanMode: Run hooks after plan mode exits (process completed plan, trigger workflows)

Use Cases

1. Auto-Archive Existing Plans

Before a plan is overwritten, archive it for future reference:

# PrePlanMode hook
if [[ -f "$PLAN_FILE" ]]; then
    cp "$PLAN_FILE" "$ARCHIVE_DIR/$(basename $PLAN_FILE .md)-$(date +%s).md"
fi

2. Prerequisite Validation

Ensure certain conditions are met before planning:

# PrePlanMode hook - ensure clean git state
if [[ -n "$(git status --porcelain)" ]]; then
    echo "WARNING: Uncommitted changes exist"
    exit 1  # Block plan mode
fi

3. Plan Processing

After exiting plan mode, trigger downstream workflows:

# PostPlanMode hook
# Convert plan to issue tracker tickets
./scripts/plan-to-tickets.sh "$PLAN_FILE"

4. Plan Persistence to Project

Copy finalized plan into project directory for version control:

# PostPlanMode hook
cp "$PLAN_FILE" ".plans/$(date +%Y%m%d)-plan.md"
git add ".plans/"

Proposed Solution

New Hook Events

{
  "hooks": {
    "PrePlanMode": [
      {
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/plan-archive/hook.sh"
          }
        ]
      }
    ],
    "PostPlanMode": [
      {
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/plan-complete/hook.sh"
          }
        ]
      }
    ]
  }
}

Hook Input Schema

{
  "event": "PrePlanMode",
  "plan_file": "/Users/name/.claude/plans/graceful-kindling-wombat.md",
  "plan_exists": true,
  "plan_content_size": 4096,
  "session_id": "abc123"
}

Exit Code Semantics

| Exit Code | PrePlanMode | PostPlanMode |
|-----------|-------------|--------------|
| 0 | Allow plan mode | Continue normally |
| 1 | User decision (prompt) | N/A |
| 2 | Block plan mode | N/A |

Current Workaround

Using PreToolUse with Write matcher to intercept plan file writes:

{
  "matcher": "Write",
  "hooks": [
    {
      "type": "command",
      "command": ".claude/hooks/plan-archive/hook.sh"
    }
  ]
}

Limitations of this workaround:

  • Fires on ALL Write operations (must filter by path)
  • Doesn't know if we're entering/exiting plan mode specifically
  • No access to plan mode metadata
  • Can't block plan mode entry, only individual writes

Impact

Current State

| Capability | Status |
|------------|--------|
| Archive plans before overwrite | Workaround (fragile) |
| Validate prerequisites for planning | Not possible |
| Process completed plans | Not possible |
| Track plan mode sessions | Not possible |

With Feature

| Capability | Status |
|------------|--------|
| Archive plans before overwrite | Native support |
| Validate prerequisites for planning | Enabled |
| Process completed plans | Enabled |
| Track plan mode sessions | Enabled |

Environment

  • Claude Code CLI
  • Using custom hooks for workflow automation
  • Long sessions with multiple planning cycles

Related

This complements existing hook events:

  • SessionStart / SessionEnd - session lifecycle
  • PreCompact - context management
  • PreToolUse / PostToolUse - tool lifecycle

Plan mode is a distinct operational mode that deserves first-class hook support.

View original on GitHub ↗

15 Comments

github-actions[bot] · 7 months ago

This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.

academo · 7 months ago

Please bring this hook. commenting here before this feature request goes stale

frbry · 7 months ago

We need this!

ray-amjad · 6 months ago

Need this!

RRaffay · 6 months ago

Bump!

specul8 · 6 months ago

There is an EnterPlanMode and ExitPlanMode hook - does that solve the problem? FYI, I have just dropped in a solution on a similar bug that gives you:

  1. Session plan file naming convention can be anything (I use my project folder name)
  2. Manages session plan name changes between Claude restarts, while consistently writing to a common plan location for the project
  3. Stored in Project Repo
  4. Built with Serena MCP usage (but not required, can target any folder - including team-shared folder locations)
  5. Automatically "Takes out the trash" (deletes session plan files from previous sessions)

Hope it helps someone else like it helped me

ProductOfAmerica · 6 months ago

+1 on this. My immediate use case is simple: I want a push notification (via ntfy.sh) when planning mode finishes so I can walk away and come back when it's ready for review.

Today there's no reliable way to do this — PostToolUse:ExitPlanMode doesn't fire, and the Stop hook is too broad since it fires on every response. A dedicated PostPlanMode event would solve this cleanly.

rubycell · 6 months ago

We had ExitPlanMode event in tooluse, so??? We better still have this.

alfredo-rgzm · 6 months ago

Lifecycle hooks make total sense, but they're compensating for something that should be built-in — plans don't have a lifecycle at all right now. There's no status (draft vs approved vs done), no archiving on transition, no way for a new plan to know an old one existed. If plans had native identity and state transitions, hooks like Pre/PostPlanMode become clean extension points instead of the entire persistence mechanism. Wrote up the fuller proposal in #29445 — hooks + a plan registry would be the real combo.

paralin · 5 months ago

I want to hook EnterPlanMode and cancel it and tell the agent to use a skill instead. Is this possible?

m13v · 5 months ago

would use this immediately. we have a workflow where the agent writes implementation plans to a file before starting work, and being able to hook into plan mode transitions would let us auto-archive the previous plan.

right now we work around it with a PreToolUse hook that checks if the tool is Write and the target is a plan file. it's hacky and misses cases where the agent updates a plan in-place rather than rewriting it.

the PostPlanMode hook is the more valuable one for us - it would let us snapshot the plan to a versioned file (plan-v1.md, plan-v2.md) so we have a history of how the approach evolved during a session. currently that context is lost when the plan gets overwritten.

m13v · 5 months ago

we run a bunch of automated workflows triggered by hooks already, here's an example of the kind of thing PrePlanMode/PostPlanMode would unlock - right now we work around it with custom skill entry points: https://github.com/m13v/social-autoposter/blob/main/skill/SKILL.md

yurukusa · 5 months ago

While dedicated PrePlanMode/PostPlanMode events don't exist yet, you can hook into plan mode transitions today using existing matchers:
PostToolUse + ExitPlanMode — fires when plan mode exits:

{
  "hooks": {
    "PostToolUse": [{
      "matcher": "ExitPlanMode",
      "hooks": [{"type": "command", "command": "bash .claude/hooks/post-plan.sh"}]
    }]
  }
}

PermissionRequest + ExitPlanMode — fires before exit, can block:

{
  "hooks": {
    "PermissionRequest": [{
      "matcher": "ExitPlanMode",
      "hooks": [{"type": "command", "command": "bash .claude/hooks/on-plan-exit.sh"}]
    }]
  }
}

Exit code 0 = approve, 2 = block (with reason in stdout sent back to Claude).
Example: archive plan on exit + notify

PLAN_FILE=$(ls -t "${HOME}/.claude/plans"/*.md 2>/dev/null | head -1)
if [[ -n "$PLAN_FILE" && -f "$PLAN_FILE" ]]; then
    ARCHIVE="${CLAUDE_PROJECT_DIR:-.}/.plans/archive"
    mkdir -p "$ARCHIVE"
    cp "$PLAN_FILE" "$ARCHIVE/$(basename "$PLAN_FILE" .md)-$(date +%Y%m%d-%H%M%S).md"
fi
exit 0

Limitations:

  • PreToolUse + EnterPlanMode is inconsistent across versions (#21282)
  • PostToolUse + ExitPlanMode does not fire when the user accepts the plan with "clear context" (#20397)
  • Plan content isn't in the hook input schema — read the plan file directly from ~/.claude/plans/
  • No way to distinguish plan creation vs. plan update

For EnterPlanMode interception, a UserPromptSubmit hook that checks for /plan in the prompt is a rough fallback, though it won't catch programmatic entry.

daniz-trust · 4 months ago

+1 on this

invidtiv · 3 months ago

+1 on this, this is a great improvement in productivity