---
title: "ディレクトリごとにClaude Codeのアカウントを分ける"
description: "Claude Codeの設定ディレクトリは CLAUDE_CONFIG_DIR で切り替えられます。macOSは認証情報をKeychainに置くので空の設定ディレクトリでもログイン状態は引き継がれる、と公式ドキュメントにありますが、実際にはKeychainのサービス名に設定ディレクトリのパスのsha256が付くため引き継がれません。ディレクトリごとにアカウントを分ける運用と、その根拠を書きます。"
category: "DevOps"
tags: ["Claude Code","macOS","direnv","Security"]
publishedAt: "2026-08-13"
lastmod: "2026-08-13"
---

Claude Code の設定ディレクトリは `CLAUDE_CONFIG_DIR` で切り替えられます。作業ディレクトリごとにこの環境変数を仕込んでおけば、`cd` するだけでログイン中のアカウントが入れ替わります。

```jsonc
// ~/Workspace/org-b/.sallyport.jsonc
{
  "expand": true,
  "env": {
    "CLAUDE_CONFIG_DIR": "$WORKSPACE_PATH/.claude",
  },
}
```

`CLAUDE_CONFIG_DIR` でアカウントを切り替えるやり方そのものについては、既に何本か記事が出ています。この記事で書くのは、macOS でこれが効く理由のほうです。

ところが公式ドキュメントには「macOS は認証情報が Keychain にあるので引き継がれる」と書かれていて、素直に読むとアカウントは分けられないことになります。実際には分けることができます。

## 設定ディレクトリの下に何が入るのか

`CLAUDE_CONFIG_DIR` を設定すると、通常 `~/.claude` の下に置かれるものがまるごとそちらへ移ります。`settings.json`、`skills/`、`plugins/`、`projects/` の下のセッション履歴、`shell-snapshots/` あたりが該当します。

見落としやすいのが `~/.claude.json` です。これは `~/.claude` ディレクトリの中ではなく、ホーム直下に置かれる、アプリケーションの状態を持つファイルです。ところが `CLAUDE_CONFIG_DIR` が設定されていると、参照先は設定ディレクトリの中の `.claude.json` に移ります。

ログイン中のアカウント情報もここに入っています。実際に手元の2つの設定ディレクトリを覗くと、それぞれ別のアカウントが記録されています。

`claude auth status` で確認するのが早いです。環境変数を付けるかどうかで出力が変わります。

```bash
claude auth status --text
CLAUDE_CONFIG_DIR=~/Workspace/org-b/.claude claude auth status --text
```

```text
Login method: Claude Max account
Organization: Org A
Email: a@example.com

Login method: Claude Max account
Organization: Org B
Email: b@example.com
```

2つのアカウントが同時にログインしたままになっています。片方に入り直すともう片方が落ちる、ということは起きません。

## リファレンスに項目がないまま他のページから参照されている

`CLAUDE_CONFIG_DIR` は [Environment variables](https://code.claude.com/docs/en/env-vars) のリファレンスに項目がありません。[Claude Code settings](https://code.claude.com/docs/en/settings) にも出てこず、`claude --help` にも出てきません。

それでいて、他のページからは参照されています。[Explore the .claude directory](https://code.claude.com/docs/en/claude-directory) は「これを設定すると、このページに出てくる `~/.claude` のパスはすべてそのディレクトリの下になる」と書いていますし、[Manage sessions](https://code.claude.com/docs/en/sessions) はセッションの保存先を `~/.claude` の外へ移す手段として表に載せています。どちらもリンク先は Environment variables で、そこに項目がありません。

[Debug your configuration](https://code.claude.com/docs/en/debug-your-config) では、設定が壊れているときに何も読み込まないセッションと比較するための手段として紹介されています。

> Point `CLAUDE_CONFIG_DIR` at an empty directory to bypass everything under `~/.claude`, and launch from a directory that has no `.claude` folder, `.mcp.json`, or `CLAUDE.md` so project configuration is also skipped.
>
> — [Debug your configuration](https://code.claude.com/docs/en/debug-your-config)

マルチアカウント用途もドキュメントに載せてほしい、という [issue #33430](https://github.com/anthropics/claude-code/issues/33430) は closed as not planned で閉じています。つまり今のところ、この使い方は公式に想定された用途ではありません。動くけれど、この使い方はドキュメントには無い、という位置付けのまま使うことになります。

## macOSのKeychainは設定ディレクトリごとに別のエントリになる

同じ Debug ページには、空の設定ディレクトリで起動したときの挙動がこう書かれています。

> * On Linux and Windows, you'll be prompted to log in again because credentials are stored under the configuration directory
> * On macOS, credentials are in the Keychain and carry over to the clean session
>
> — [Debug your configuration](https://code.claude.com/docs/en/debug-your-config)

Linux と Windows は認証情報が設定ディレクトリの下にあるので再ログインが要る、macOS は Keychain にあるので引き継がれる、と読めます。これを真に受けると、macOS で `CLAUDE_CONFIG_DIR` を分けてもアカウントは1つのまま、という結論になります。

空のディレクトリを指して確かめると、そうはなりません。

```bash
CLAUDE_CONFIG_DIR=/tmp/claude-clean claude auth status --text
```

```text
Not logged in. Run claude auth login to authenticate.
```

理由は Keychain のサービス名の作り方にあります。

手元にインストールされている v2.1.233 のバイナリから、サービス名を組み立てている箇所を引用します。minify されたままなので変数名は読めませんが、やっていることは追えます。`bzu` には同じ場所で `require("crypto")` が入っています。

```javascript
function WZ(e=""){
  let t=process.env.CLAUDE_SECURESTORAGE_CONFIG_DIR,
      r=t!==void 0?!t:!process.env.CLAUDE_CONFIG_DIR,
      n=t!==void 0?t.normalize("NFC"):En(),
      o=r?"":`-${bzu.createHash("sha256").update(n).digest("hex").substring(0,8)}`;
  return `Claude Code${Ua().OAUTH_FILE_SUFFIX}${e}${o}`
}
```

`e` に渡ってくるのは `-credentials` という文字列です。`r` は末尾に何も付けないかどうかの判定です。`CLAUDE_SECURESTORAGE_CONFIG_DIR` が定義されていればそれが空文字のときだけ、定義されていなければ `CLAUDE_CONFIG_DIR` が未設定か空文字のときだけ真になります。真のときは `o` が空文字になり、サービス名は `Claude Code-credentials` のままです。

`CLAUDE_CONFIG_DIR` が設定されていると `o` に `-` と設定ディレクトリのパスの sha256 の **先頭8桁** が入ります。サービス名が `Claude Code-credentials-<8桁>` になるので、Keychain 上でも別のエントリとして扱われます。設定ディレクトリが違えばパスが違い、パスが違えばハッシュが違うので、衝突しません。

![CLAUDE_CONFIG_DIR の有無で Keychain のサービス名が変わる。未設定なら Claude Code-credentials、設定するとそのパスの sha256 先頭8桁が末尾に付き、同じ login.keychain の中に別のエントリとして並ぶので、2つのアカウントが同時にログインしたままになる](/images/posts/claude-config-dir-account-separation/keychain-service-name.svg)

同じ計算は手元でも再現できます。ハッシュを取る対象は `CLAUDE_CONFIG_DIR` に渡した文字列そのものです。`path.resolve()` は挟まらないので、相対パスを渡すとその文字列がそのままハッシュに掛かり、同じディレクトリを指していても絶対パスで渡したときとは別のエントリになります。

```bash
printf '%s' "/Users/example/Workspace/org-b/.claude" | shasum -a 256 | cut -c1-8
```

```text
46474663
```

この8桁をそのままサービス名に埋めて Keychain を引くと、エントリが返ってきます。`-w` を付けなければパスワード本体は表示されず、メタデータだけが出ます。実際には16進のキーや `<NULL>` の属性が十数行続くので、主要なものだけ抜き出します。

```bash
security find-generic-password -s "Claude Code-credentials-46474663"
```

```text
keychain: "/Users/example/Library/Keychains/login.keychain-db"
class: "genp"
attributes:
    "acct"<blob>="example"
    "svce"<blob>="Claude Code-credentials-46474663"
    ...
```

`acct` に入るのは `$USER` の値で、Claude Code 側のアカウントとは関係ありません。アカウントを区別しているのは `svce` の末尾8桁だけです。

なお、ハッシュを取る前に NFC 正規化が挟まります。パスにマルチバイト文字が入っていると、手計算した値と食い違います。

コードからはもうひとつ、`CLAUDE_SECURESTORAGE_CONFIG_DIR` という別の環境変数を先に見にいっていることも分かります。こちらが設定されていればそちらが優先され、空文字を渡したときだけデフォルト扱いに戻ります。認証情報の置き場所だけを設定ディレクトリと切り離したい場合の逃げ道になっていますが、これもドキュメントには出てきません。

Linux と Windows なら認証情報そのものが設定ディレクトリの下に入るため、ここまでの Keychain の話は関係なく、ディレクトリを分ければそのまま分かれます。macOS だけが一段回りくどい経路を通ります。

ドキュメントの記述と実装が食い違っているので、macOS でアカウントを分ける運用は、いま動いていても将来も動く保証はありません。バージョンを上げたら再ログインを求められる可能性は残ります。

## ディレクトリごとに環境変数を設定する

`CLAUDE_CONFIG_DIR` を毎回手で入力するのは現実的ではありません。エイリアスで `claude-personal` のようなコマンドを作る方法もありますが、それだと `gh` や `git` が別のアカウントを向いたままになります。設定ディレクトリだけでなく、SSH 鍵も 1Password のアカウントも同じ単位で切り替えたいので、ディレクトリに入った時点で環境変数がまとめて入る形にしています。

長らく [direnv](https://direnv.net/) を使っていました。今は Nix と home-manager でリポジトリごとのセットアップを配っている都合もあって、個人で作っている [sallyport](https://github.com/corrupt952/sallyport) に移しています。

```jsonc
// ~/Workspace/org-b/.sallyport.jsonc
{
  // Environment variables applied while inside this workspace.
  // WORKSPACE_PATH is exported automatically.
  "expand": true,
  "env": {
    // Git
    "GIT_ALLOW_PUSH_MAIN_BRANCH": "yes",

    // 1Password
    "OP_ACCOUNT": "my.1password.com",
    "OP_SSH_KEY": "Development/GitHub - org-b",

    // Claude
    "CLAUDE_CONFIG_DIR": "$WORKSPACE_PATH/.claude",
  },
}
```

承認していない設定を適用しないのは、sallyport に限った話ではありません。direnv も同じで、`.envrc` を書き換えれば承認は外れます。

承認は `sha256(設定の識別子 + 中身)` で記録します。Nix の store へのシンボリックリンクとして配られた設定はリンク先ではなく置かれている場所で識別するので、rebuild で store パスが変わっても承認は保たれ、中身を書き換えたときだけ外れます。

sallyport で変えたのは適用する対象のほうです。direnv が実行するのはシェルスクリプトですが、`.sallyport.jsonc` に書けるのは環境変数の宣言だけで、既定では値がコードとして解釈されることもありません。

同じ狙いのツールは他にもあります。[shadowenv](https://github.com/Shopify/shadowenv) は Shadowlisp という宣言的な言語で環境変数の差分を書く形で、任意のシェルコマンドは走りません。安全側に倒れている代わりに、値を `$(op read ...)` のようなコマンドの出力から取る書き方ができません。

sallyport で `expand` を opt-in にしてあるのはそのためです。既定では値をシングルクオートでそのまま適用し、`expand: true` を書いたときだけ zsh の展開を通します。

1Password の SSH エージェントまわりは以前も書きました。

::card[https://labee.jp/posts/claude-code-sandbox-1password-ssh-signing]

ここで使うツールは何でも構いません。direnv でも、direnv に暗号化を組み合わせた構成でも、やりたいことは「そのディレクトリにいる間だけ環境変数が入っていて、出たら元に戻る」の一点です。設定ディレクトリを分ける話とツールの選定は独立しているので、既に direnv が入っているならそのまま `export CLAUDE_CONFIG_DIR=...` を書けば済みます。

## 共有したいものはプラグインにする

どちらのアカウントでも使いたいスキルやサブエージェントは、設定ディレクトリを分けた時点で別々の実体になります。

ここはプラグインで揃えられます。組織ごとに standards リポジトリを1つ持ってマーケットプレイスにし、それぞれの設定ディレクトリへインストールする形です。ラビーの分は公開しています。

::card[https://github.com/LabeeHive/standards]

公式マーケットプレイスのプラグインのように両方で使うものも、同じ要領で両方へ入れます。更新は設定ディレクトリごとに走るので、放っておいて揃うわけではありません。

プラグインに載らないものは残ります。ユーザー全体に効く `CLAUDE.md` のように home-manager から配っているものもありますが、今のところ多くは手で複製しています。

分ける単位も配り方も、まだ様子を見ながら決めている最中です。

## どこで分かれるかは設定ディレクトリのパスで決まる

`--resume` で拾えるセッションも設定ディレクトリごとに分かれます。別のアカウントで始めた作業の続きを拾いたいときは、そちらに合わせてから起動することになります。

どこで分かれるかを決めているのは、設定ディレクトリのパスの文字列そのものです。ワークスペースを別の場所へ移すとサービス名のハッシュも変わるので、移す前に作られた Keychain のエントリは新しいパスからは引けません。ディレクトリ名を変えるだけでも同じことが起きます。

設定ディレクトリの中身を新しいパスへコピーしても、`claude auth status` は未ログインと出ます。認証情報はファイル側ではなく、パスから引く Keychain のエントリ側にあるためです。