Skip to content

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

Description

@ppf

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet
  • This is a single bug report (please file separate reports for different bugs)
  • 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:
    {
      "plansDirectory": "./.claude/plans"
    }
  3. Open project in subdirectory (e.g., /Users/storm/PhpstormProjects/CodexMonitor)
  4. Create and work on a plan in the project
  5. Exit plan mode → triggers hook (e.g., plan-review plugin)
  6. Hook resolves relative path using Path.cwd() and gets ~ instead of project directory
  7. 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:

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    duplicateThis issue or pull request already exists

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions