ExitPlanMode hooks execute with wrong working directory (cwd = ~ instead of project directory)

Resolved 💬 3 comments Opened Feb 1, 2026 by ppf Closed Feb 5, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

When ExitPlanMode triggers hooks, it executes them with current working directory set to user home (~) rather than the project directory where the plan was created. This causes plugins using relative paths from settings to resolve paths incorrectly.

Impact: Plugins using ExitPlanMode hooks with relative paths fail silently. Multi-project workflows break when each project has its own .claude/plans/ directory.

Evidence:

  • Hook cwd is ~ (user home) instead of project directory
  • Relative path ./.claude/plans resolves to ~/.claude/plans/ instead of project's .claude/plans/
  • Hook opens wrong plan file from global directory

Affected: plan-review plugin and likely any plugin hooking ExitPlanMode that uses relative paths from settings

What Should Happen?

ExitPlanMode should preserve project context when executing hooks:

  • Hook cwd should be project directory (e.g., /Users/storm/PhpstormProjects/CodexMonitor)
  • Relative path ./.claude/plans should resolve to project's .claude/plans/ directory
  • Hook should operate on correct project-specific plan file
  • Similar to how other hooks (PreToolUse, PostToolUse) work with $CLAUDE_PROJECT_DIR

Error Messages/Logs

No explicit error messages - hook executes successfully but with wrong working directory.

**Evidence from hook execution**:

cwd = Path.cwd()  # Returns ~ instead of /Users/storm/PhpstormProjects/CodexMonitor
settings_plans_dir = settings.get("plansDirectory", "./.claude/plans")
plans_dir = cwd / settings_plans_dir[2:]  # Wrong resolution due to incorrect cwd


**File locations**:
- Correct plan: `/Users/storm/PhpstormProjects/CodexMonitor/.claude/plans/streamed-gliding-sonnet.md`
- Hook found: `~/.claude/plans/elegant-hopping-book.md` (stale plan from different project)

Steps to Reproduce

  1. Set up multi-project workflow with per-project .claude/plans/ directories
  2. Configure ~/.claude/settings.json with relative path:

``json
{
"plansDirectory": "./.claude/plans"
}
``

  1. Open project in subdirectory (e.g., /Users/storm/PhpstormProjects/CodexMonitor)
  2. Create and work on a plan in the project
  3. Exit plan mode → triggers hook (e.g., plan-review plugin)
  4. Hook resolves relative path using Path.cwd() and gets ~ instead of project directory
  5. Observe that hook opens plan from ~/.claude/plans/ instead of project's .claude/plans/

Claude Model

Sonnet (default)

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.29 (Claude Code)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Terminal.app (macOS)

Additional Information

Related Issues

This appears distinct from existing cwd-related hook issues:

  • #16541 - PostToolUse hook missing cwd field in hook data
  • #10367 - Hooks non-functional in subdirectories
  • #3583 - Relative hook paths not resolved to absolute
  • #12499 - ExitPlanMode not triggered (different issue)

This issue is specifically about ExitPlanMode hook subprocess executing with incorrect working directory context.

Proposed Solutions

Option 1 (Preferred): Preserve project directory context

  • Execute ExitPlanMode hooks with cwd set to project directory
  • Or: Pass project directory as environment variable ($CLAUDE_PROJECT_DIR) to hook subprocess
  • Similar to how other hooks work with $CLAUDE_PROJECT_DIR

Option 2: Document workaround and best practices

  • Update hook documentation to warn against relying on cwd for ExitPlanMode hooks
  • Provide API or environment variable for hooks to reliably get project directory
  • Recommend using absolute paths in settings for multi-project workflows

Context

Discovered during plan-review plugin testing across multiple projects. The plugin correctly reads settings with relative paths but fails because ExitPlanMode hook execution context doesn't match the project where planning occurred.

Settings file: ~/.claude/settings.json line 193

"plansDirectory": "./.claude/plans"

Affected plugin: plan-review from storm-plugins marketplace

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗