Skip to content

fix: prefer project-scoped env vars over CLAUDE_FLOW_CWD fallback#1618

Open
shaun0927 wants to merge 2 commits intoruvnet:mainfrom
shaun0927:fix/project-cwd-over-flow-cwd
Open

fix: prefer project-scoped env vars over CLAUDE_FLOW_CWD fallback#1618
shaun0927 wants to merge 2 commits intoruvnet:mainfrom
shaun0927:fix/project-cwd-over-flow-cwd

Conversation

@shaun0927
Copy link
Copy Markdown

Summary

Fixes the project-boundary bug described in #1617.

getProjectCwd() currently prefers the installer fallback CLAUDE_FLOW_CWD before project-scoped runtime env vars. On global MCP installs, that means the fallback can mask richer host context and send session/task/agent state into one shared home-scoped .claude-flow/ tree.

This PR keeps the scope intentionally narrow: it only changes the resolver priority order and adds a regression test for that order.

Changes

File Purpose
v3/@claude-flow/cli/src/mcp-tools/types.ts Prefer project-scoped env vars (CLAUDE_FLOW_PROJECT_DIR, CLAUDE_PROJECT_DIR, INIT_CWD) before the installer fallback CLAUDE_FLOW_CWD
v3/@claude-flow/cli/__tests__/mcp-tools-project-cwd.test.ts Regression tests covering env-var priority and fallback behavior

Why this scope

Recent cwd fixes addressed bootstrap failures when MCP servers start at / or System32. This PR targets the narrower follow-up problem: once the host does provide a project directory, the installer fallback should no longer win.

That keeps the patch small, reviewable, and low-risk.

Test plan

  • bunx vitest run v3/@claude-flow/cli/__tests__/mcp-tools-project-cwd.test.ts
  • Manual local repro before the patch: with CLAUDE_FLOW_CWD pinned to a fake home dir, session_save from two different projects wrote into the same shared .claude-flow/sessions directory
  • Manual local repro after the patch: with CLAUDE_PROJECT_DIR set per project and CLAUDE_FLOW_CWD still pinned to the fake home dir, session_save writes into each project's local .claude-flow/sessions directory instead

Notes

Closes #1617

The installer-level CLAUDE_FLOW_CWD fallback is useful for bootstrapping
away from / and System32, but it should not outrank project-specific
runtime env vars once the host can provide them. This change makes the
resolver prefer project-scoped env vars first and adds a regression test
covering that priority order.

Constraint: Global MCP installs still need a safe fallback when process.cwd() is unusable
Rejected: Remove CLAUDE_FLOW_CWD entirely | would reintroduce the bootstrap failures tracked in earlier cwd bugs
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep getProjectCwd project-scoped; installer fallbacks must never mask richer runtime context
Tested: bun import reproduction before/after for session_save path resolution; bunx vitest run v3/@claude-flow/cli/__tests__/mcp-tools-project-cwd.test.ts
Not-tested: Real Claude Code/Codex MCP host behavior on Windows/macOS with upstream binaries
Related: ruvnet#1617
The PR code already prefers project-scoped env vars over the installer
fallback, but the initial regression test only exercised part of that
priority chain. This follow-up locks down the highest-priority
`CLAUDE_FLOW_PROJECT_DIR` case so future refactors cannot accidentally
reintroduce fallback masking.

Constraint: Keep the PR scope narrow and avoid touching runtime logic beyond test coverage
Rejected: Expand this into broader resolver hardening | would dilute the focused fix under review
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: If getProjectCwd precedence changes, update tests for every supported env tier together
Tested: bunx vitest run v3/@claude-flow/cli/__tests__/mcp-tools-project-cwd.test.ts
Not-tested: End-to-end MCP host launches on real Claude Code/Codex clients
Related: ruvnet#1617
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP getProjectCwd() prefers installer fallback over project env vars, collapsing state into $HOME

1 participant