Claude Media
Claude Codeが作業ディレクトリを見失う問題の原因と対処法

Claude Codeが作業ディレクトリを見失う問題の原因と対処法

cdやworktree移動の後もClaude Codeが古い作業ディレクトリを引きずる現象を、Bashツールの引き継ぎ仕様とGitHub issueの報告から見て、環境変数とフックでの対処を示します。

Claude Codeが作業ディレクトリを見失うとは何が起きるのか

Claude Codeが、実際にいるディレクトリとは違う場所にいると思い込んで動くことがあります。コマンドが失敗し、cdとlsを何度も繰り返してからようやく正しい場所にたどり着く、という報告がGitHub issue #1669に集まっています。issueは2025年6月5日に起票され、bug・area:core・oncallという3つのラベルが付いています。クローズはされていません。ディレクトリが消えて起動すらできない場合は、current directoryが消えて終了する問題を見てください。

起票者は、この現象によってgitの強制リセット(git reset --hard)を誤ったディレクトリで実行してしまい、60時間分の作業を失ったと書いています。コメント欄には同様の被害報告が続きます。あるユーザーは、ビルド用のサブディレクトリを掃除するつもりが、Claude Codeがいる場所を取り違えてファイルを一括削除したと報告しました。直前のコミットから変更が無かったため実害はなかったものの、破壊的な操作と組み合わさったときの危うさを示す例です。

別のユーザーは、存在しないパスへのcdと、存在しないファイルへのReadを20回前後も繰り返す様子を記録しています。同じファイルへのアクセスを別のディレクトリから試み続け、ユーザーが手動で止めるまで収束しませんでした。もう一人のユーザーは、git mvでスクリプトをscripts/ディレクトリへ移したつもりが、Claudeが実はすでにscripts/の中で作業していたために直下に留まってしまった例を報告しています。pwdを実行するまで、本人もClaudeもこのズレに気づいていませんでした。

影響の大きさを訴える声も複数あります。あるユーザーはこの現象を「venvのsource忘れ、todoの検証不足と並ぶ上位3つの時間浪費」と表現し、別のユーザーは「ユーザーの時間だけでなく、支払っているトークンも無駄にする」と指摘しました。

なぜ起きるのか — Bashツールはcdをどこまで引き継ぐか

報告されているズレの土台には、Bashツールの設計があります。Bashツールはコマンドごとに別のプロセスを起動するため、環境変数は次のコマンドに残りません。一方でcdだけは、条件付きで次のコマンドに引き継がれます。

くらべる

メインセッションで cd した後の動き

プロジェクト内

引き継がれる

cdの行き先がプロジェクトディレクトリの中、または--add-dir・/add-dir・設定のadditionalDirectoriesで足したディレクトリの中なら、次のBashコマンドもそこから始まります。ユーザーが後から送ったメッセージへの応答で走るコマンドにも続きます。

範囲の外

戻される

cdの行き先がその範囲の外に出ると、Claude Codeはプロジェクトディレクトリへリセットし、ツール結果にShell cwd was reset to <dir>という一文を付けます。

つまり、プロジェクトの中でcd buildをすれば、その後のコマンドはずっとbuild/の中で動きます。Claudeが「プロジェクト直下にいる」つもりでrm -rf *を書けば、実際にはbuild/の中身が消えます。issue #1669のコメントにあった「ビルド用サブディレクトリを掃除するつもりが直下を消した」報告とは向きが逆ですが、認識と実体のズレが破壊的な操作を誤爆させる点は同じです。

サブエージェントはこの引き継ぎの対象外です。サブエージェントはメインの会話の現在のディレクトリで起動し、中でのcdはBashやPowerShellの呼び出しをまたいで残らず、メインの会話のディレクトリにも影響しません。メインでは引き継がれるのにサブエージェントでは引き継がれないという差があるため、同じ指示でも動くセッションによってコマンドの出発点が変わります。

起動スクリプトとの関係

一部のユーザーはシェルの設定ファイルに原因を見つけています。あるコメントは、~/.profileからcd $HOMEの行を削除したところ問題が解消したと報告しました。別のユーザーはこの説明に反論し、「この問題は一般的にそれとは無関係で、Claudeは数秒前にした操作すら本当に忘れる」とコメントしています。原因は1つに絞り込めておらず、複数の要因が絡んでいる可能性があります。

Bashツールの仕様ページによると、セッション開始時に~/.zshrc・~/.bashrc・~/.profileのいずれかが読み込まれ、そこで得られたエイリアス・関数・シェルオプションが全コマンドに適用されます。引き継ぎ対象として挙がっているのはこの3種類で、起動スクリプト中のcdの扱いには触れられていません。

食い違いは公式にも想定されている

ステータスラインのリファレンスは、workspace.project_dir(起動時のディレクトリ)がworkspace.current_dir(現在のディレクトリ)と、セッション中に作業ディレクトリが変われば異なることがあると書いています。フックの入力に含まれるcwdも同じ考え方で、公式は「Claudeに追従し、cd実行後は新しいディレクトリになる」と説明しています。ディレクトリの移動は、セッションの中で状態が変わる出来事として最初から扱われています。

CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIRで元のディレクトリに戻す

環境変数のリファレンスには、先ほどの引き継ぎを止める設定が載っています。CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIRを有効にすると、メインセッションでBashまたはPowerShellのコマンドを実行するたびに、元の作業ディレクトリへ戻ります。

export CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIR=1
claude

このexportはターミナルのセッション内でのみ有効で、シェルを閉じれば設定は消えます。毎回のセッションで有効にしたい場合は、設定ファイルのenvブロックに書いておく方法もあります。書き込み先は用途によって異なり、~/.claude/settings.jsonなら自分の全プロジェクトに、プロジェクト直下の.claude/settings.jsonならバージョン管理に含めてチーム全員に、.claude/settings.local.jsonならそのプロジェクトの自分だけに適用されます。.claude/settings.local.jsonはClaude Codeが書き込むときにグローバルのgit除外へ自動で加えられますが、手作業で作成した場合は自分で.gitignoreに加える必要があります。

{
  "env": {
    "CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIR": "1"
  }
}

値は1またはtrueで有効、0またはfalseで無効です。稼働中のセッションでも、設定ファイルを保存すれば新しい値が環境に反映されます。ただし、起動時に一度だけ読む機能は再起動するまで古い値のままです。

この変数を有効にすると、Claudeがcdで移動した直後でも、次のBashコマンドは常にプロジェクトのルートから始まります。1回のコマンドの中でcd build && makeのように移動して使うのは今までどおりできます。issueで報告されていたような「別ディレクトリのつもりでrmやgit reset --hardを実行する」事故のリスクを、構造的に減らせる設定です。

サブエージェントでは、変数を設定しなくてもcdが呼び出しをまたいで残らないので、この変数が効く対象はメインセッションです。

CwdChangedフックとステータスラインでズレを可視化する

環境変数で戻す以外に、ズレを検知・可視化する手段も用意されています。CwdChangedフックは、メインの会話でシェルコマンドが作業ディレクトリを変えるたびに発火するイベントです。入力にはold_cwdとnew_cwdが含まれます。ディレクトリ移動そのものを止める権限は無く、あくまで移動が起きた後に反応する設計です。

フックの出力にsystemMessageを含めると、ユーザーに表示される警告メッセージとして出ます。次の設定は、移動のたびに行き先を画面へ流す例です。

{
  "hooks": {
    "CwdChanged": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "jq -c '{systemMessage: (\"cwd: \" + .old_cwd + \" -> \" + .new_cwd)}'"
          }
        ]
      }
    ]
  }
}

標準入力に{"old_cwd":"/p","new_cwd":"/p/src"}を流すと、このコマンドは{"systemMessage":"cwd: /p -> /p/src"}を出力します。ファイルに追記したいときは、同じ入力を>> /tmp/cwd.logへ書き出す形にすれば、いつどこへ移動したかを事後に追えます。CwdChangedのフックはCLAUDE_ENV_FILEにも書き込めるので、direnvのようにディレクトリごとの環境変数を切り替える用途にも使えます。

Claude Codeのフック機構全体はHooks完全ガイドで扱っており、CwdChanged以外のイベントもそちらで見られます。

もう一つの手段がステータスラインです。workspace.current_dirを表示に含めておけば、画面の下部でClaudeが今どこにいると認識しているかを常に確認できます。

{
  "statusLine": {
    "type": "command",
    "command": "jq -r '\"[\\(.model.display_name)] \\(.workspace.current_dir)\"'"
  }
}

CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIRで自動的に戻すのが根本対策だとすれば、ステータスラインは「戻っていないことにすぐ気づく」ための補助策にあたります。

手段ごとの守備範囲

使い分け

3つの手段が受け持つ範囲

  • 環境変数で戻す

    CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIRは、メインセッションの各Bash/PowerShellコマンドをプロジェクトのルートから始めさせます。ズレの発生を防ぐのはこの手段だけです。

  • フックで知らせる

    CwdChangedは移動の発生を通知・記録します。移動自体は止められません。

  • ステータスラインで見る

    workspace.current_dirを常時表示します。ズレを防ぐ力はなく、気づくための手段です。

CLAUDE_CODE_HIDE_CWDは名前が似ているため混同しやすい変数です。役割は起動ロゴのパス表示を隠すことで、画面共有でOSのユーザー名を見せないための設定です。Claudeが実際にどこで動くかには影響せず、この現象の解消とは無関係です。

ズレたかもしれないと感じたときの切り分け

手順

コマンドを実行させる前の3手

  1. 1

    現在地を出させる

    破壊的な操作の前に、Claudeへpwdを実行させて結果を見ます。ツール結果にShell cwd was reset toの一文があれば、行き先がプロジェクトの範囲外だったためにリセットされています。

  2. 2

    パスを絶対指定にする

    rm -rfやgit reset --hardのように取り消せない操作は、相対パスでなく絶対パスを明示させます。誤ったディレクトリでの実行事故を避けやすくなります。

  3. 3

    worktreeなら元の場所を見る

    git worktreeを使っているセッションでは、ステータスラインのworktree.original_cwdでworktreeに入る前のディレクトリを見られます。このフィールドはClaude Codeがworktreeセッションに入っているときだけ現れます。workspace.current_dirだけでは、元のツリーへ戻ったのか別のworktree内を移動しただけなのか区別できない場面で判断材料になります。

よくあるつまずき

  • ステータスラインに何も表示されない: ワークスペースの信頼(trust)ダイアログを承認していないと、ステータスラインは空欄のままです。claude --debugのログにはStatus line command skipped: workspace trust not acceptedと記録されます。Claude Codeを再起動して信頼ダイアログを承認すると表示が始まります
  • envに書いたCLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIRが反映されない: 組織のmanaged settingsに書かれた設定は、ユーザー設定やプロジェクト設定より優先されます。個人設定で無効化したい場合は管理者側の見直しが必要です
  • cdしたはずなのに次のコマンドがプロジェクト直下から始まる: 行き先がプロジェクトと追加ディレクトリの外にあるか、サブエージェントの中で実行されているか、CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIRが有効になっています

まとめ

作業ディレクトリのズレは、メインセッションではcdが引き継がれ、サブエージェントでは引き継がれないというBashツールの設計と、issue #1669のように認識と実体が食い違う場面の両方から起きます。破壊的な操作を任せるセッションでは、CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIRでコマンドの出発点をプロジェクトのルートに固定し、CwdChangedフックの通知かステータスラインで現在地が見える状態にしておく選択肢があります。

この記事を共有:XはてブLinkedIn