ExitPlanMode hooks execute with wrong working directory (cwd = ~ instead of project directory)
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
cwdis~(user home) instead of project directory - Relative path
./.claude/plansresolves 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
cwdshould be project directory (e.g.,/Users/storm/PhpstormProjects/CodexMonitor) - Relative path
./.claude/plansshould 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
- Set up multi-project workflow with per-project
.claude/plans/directories - Configure
~/.claude/settings.jsonwith relative path:
``json``
{
"plansDirectory": "./.claude/plans"
}
- Open project in subdirectory (e.g.,
/Users/storm/PhpstormProjects/CodexMonitor) - Create and work on a plan in the project
- Exit plan mode → triggers hook (e.g.,
plan-reviewplugin) - Hook resolves relative path using
Path.cwd()and gets~instead of project directory - 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
cwdset 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
cwdfor 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
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗