Skip to content

Commit 71ed2f7

Browse files
authored
Merge pull request #90 from ClaydeCode/fix/claude-creds-dir-mount
fix: dir-mount a dedicated Claude config dir for the CLI backend
2 parents 0083cff + c26dd46 commit 71ed2f7

3 files changed

Lines changed: 28 additions & 6 deletions

File tree

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ Two backends, selected by `CLAYDE_CLAUDE_BACKEND`:
204204
- Session resumption: saves `session_id` from JSON output, resumes via `--resume <session_id>`
205205
- Rate/usage limit detection: text-pattern matching on stdout/stderr
206206
- No per-token cost tracking (returns `cost_eur=0.0`)
207-
- Requires: OAuth credentials mounted from host `~/.claude/.credentials.json` (see docker-compose.yml)
207+
- Requires: a dedicated Claude config dir dir-mounted from the host (`~/clayde-claude``/home/clayde/.claude`); use a separate `CLAUDE_CONFIG_DIR=~/clayde-claude claude login`. Mount the directory, not the `.credentials.json` file — token refresh renames the file (new inode) and a single-file mount goes stale. See docker-compose.yml / README.
208208

209209
---
210210

README.md

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,17 +131,32 @@ Uses the Anthropic Python SDK with a tool-use loop. Pay-per-token.
131131

132132
Runs the Claude Code CLI as a subprocess. Uses your Claude Pro/Max subscription — no per-token cost.
133133

134-
1. On the host machine, log in to the CLI:
134+
1. On the host machine, create a **dedicated** login for the container in its
135+
own config directory (kept separate from your personal `~/.claude`):
135136
```bash
136-
claude login
137+
CLAUDE_CONFIG_DIR=~/clayde-claude claude login
137138
```
138139
2. Set in `data/config.env`:
139140
```
140141
CLAYDE_CLAUDE_BACKEND=cli
141142
```
142143
(`CLAYDE_CLAUDE_API_KEY` is not required for the CLI backend.)
143144

144-
The `docker-compose.yml` mounts `~/.claude/.credentials.json` from the host directly into the container. Token refreshes, logouts, and account switches on the host are immediately reflected.
145+
The `docker-compose.yml` mounts the `~/clayde-claude` **directory** into the
146+
container as its Claude config dir. Two things matter here:
147+
148+
- **Mount the directory, not the `.credentials.json` file.** The CLI refreshes
149+
its short-lived OAuth token by writing a new file and atomically renaming it
150+
into place — which changes the file's inode. A single-file bind mount is
151+
pinned to the original inode at container start, so it never sees the new
152+
token and the container fails with "authentication expired" until you restart
153+
the stack. A directory mount resolves the path live, so refreshes propagate
154+
with no restart.
155+
- **Use a dedicated login, not your personal `~/.claude`.** That directory
156+
holds your interactive sessions, projects, and history; sharing it exposes
157+
that state to the container. A separate login also gives the container its own
158+
OAuth refresh-token lineage, so its token refreshes can't invalidate your
159+
host login (refresh tokens are single-use).
145160

146161
### 5. Start the container
147162

docker-compose.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,15 @@ services:
3434
- CLAYDE_ENABLED=true
3535
volumes:
3636
- ./data:/data
37-
# Mount Claude CLI OAuth credentials (required when CLAYDE_CLAUDE_BACKEND=cli)
38-
- ~/.claude/.credentials.json:/home/clayde/.claude/.credentials.json
37+
# Dedicated Claude config dir for the container (required when
38+
# CLAYDE_CLAUDE_BACKEND=cli). Use a SEPARATE login here — see README:
39+
# CLAUDE_CONFIG_DIR=~/clayde-claude claude login
40+
# Mount the DIRECTORY, not the single .credentials.json file: the CLI
41+
# refreshes its short-lived OAuth token via atomic rename (new inode),
42+
# which a single-file bind mount pins to the stale inode at start —
43+
# causing "authentication expired" until the stack is restarted. A
44+
# directory mount resolves the path live, so refreshes are picked up.
45+
- ~/clayde-claude:/home/clayde/.claude
3946
# Pebble skill directories — mount one or more host dirs read-only
4047
# under /skills/. Subdirectory layout is free; discovery is recursive.
4148
- ~/skills/personal:/skills/personal:ro

0 commit comments

Comments
 (0)