Summary
- What's confusing: In Docker,
ARCHON_HOME and ARCHON_DATA both leak into the container env via env_file: .env, but neither is read by Archon code in the container — ARCHON_HOME is silently overridden by isDocker(), and ARCHON_DATA is a Compose host-side substitution token that no TS source ever reads. Operators see ARCHON_DATA=/Users/x/data inside the container, try cd $ARCHON_DATA, and get "no such file or directory". .env.example documents both as configurable without the Docker caveats.
- What's missing: The Docker image runs Claude Code as
appuser with $HOME=/home/appuser, but no compose file mounts /home/appuser/.claude/ — so user-installed Claude Code skills/prompts are lost on every docker compose up --build / image pull. There's no documented persistence story for "shared .claude/skills across all repos in the container."
- Severity:
minor (UX / docs — no functional break; the bind mount itself works correctly)
- Reported by: Community member Zolto on Dynamous forum (cross-posted by maintainer)
Steps to Reproduce
cp .env.example .env
- Add to
.env: ARCHON_DATA=/Users/myuser/develop-local/archon-data-volume (a host path)
mkdir -p /Users/myuser/develop-local/archon-data-volume
docker compose up -d
docker compose exec app bash
- Inside the container:
echo $ARCHON_DATA
# /Users/myuser/develop-local/archon-data-volume <-- host path, leaked
cd $ARCHON_DATA
# /bin/sh: cd: can't cd to /Users/myuser/develop-local/archon-data-volume
- Try setting
ARCHON_HOME=/anywhere/else in .env, restart:
echo $ARCHON_HOME
# /anywhere/else <-- leaked into env
ls /.archon
# ... contents of the bind mount, NOT /anywhere/else — ARCHON_HOME ignored
- Try
mkdir -p ~/.claude/skills/myskill and re-create the container — the directory is gone (not on the bind mount).
Expected vs Actual
- Expected (operator's mental model):
ARCHON_DATA and ARCHON_HOME either work consistently inside and outside Docker, OR .env.example warns clearly that they don't.
- There's a documented place to drop
.claude/skills that survives container recreation.
- Actual:
ARCHON_HOME is silently ignored in Docker (packages/paths/src/archon-paths.ts:56-74 — getArchonHome() returns hardcoded /.archon when isDocker() is true).
ARCHON_DATA is never read by any TS source — only by Compose substitution at docker-compose.yml:41 (${ARCHON_DATA:-archon_data}:/.archon).
- Both leak into the container via
env_file: .env (docker-compose.yml:35, deploy/docker-compose.yml:17) and sit there as dead weight.
- No mount exists for
/home/appuser/.claude/, so any Claude Code config the user adds inside the container is ephemeral.
User Flow
Operator's expectation: Reality:
───────────────────────── ────────
.env: ARCHON_HOME=/foo .env: ARCHON_HOME=/foo
| |
v v
Compose env_file: .env ---> container Compose env_file: .env ---> container
process.env.ARCHON_HOME=/foo
|
Archon reads ARCHON_HOME = /foo Archon: isDocker() -> true
|
v
getArchonHome() returns '/.archon' [X] silently ignores /foo
|
v
Operator: "echo $ARCHON_HOME shows /foo, but
workspaces went to /.archon — wat?"
.claude/skills: .claude/skills:
mkdir -p ~/.claude/skills/foo mkdir -p ~/.claude/skills/foo (= /home/appuser/.claude/skills/foo)
docker compose up -d --build docker compose up -d --build
ls ~/.claude/skills/foo -> persists ls ~/.claude/skills/foo -> [X] gone (not on a volume)
Environment
- Platform: Docker (any host)
- Database: any
- OS: any (reported on macOS bind mount, but the env-leak applies everywhere)
- Versions: dev branch @ 4631b8e (also present on main)
Logs
Inside container:
$ env | grep ARCHON
ARCHON_DOCKER=true
ARCHON_DATA=/Users/myuser/develop-local/archon-data-volume # leaked, dead
ARCHON_HOME=~/.archon # leaked, ignored
Source confirming the silent override:
// packages/paths/src/archon-paths.ts:56-74
export function getArchonHome(): string {
if (isDocker()) {
return '/.archon'; // ARCHON_HOME never consulted in Docker
}
const envHome = process.env.ARCHON_HOME;
...
}
grep -r ARCHON_DATA packages/ returns only doc files — no source reads it.
Impact
- Affected workflows: any user setting up Docker for the first time who reads
.env.example and tries to customize paths.
- Reproduction rate: Always (deterministic).
- Workaround: ignore the env vars; add a manual bind mount for
/home/appuser/.claude/ via docker-compose.override.yml.
- Data loss risk: No (just operator confusion + ephemeral skills).
Scope
- Package(s):
paths, infra, docs
- Module:
packages/paths/src/archon-paths.ts (clarify intent), .env.example, docker-compose.yml, deploy/docker-compose.yml, packages/docs-web/src/content/docs/deployment/docker.md
Proposed Cleanup
Three small, independent changes — pick any subset:
-
Annotate .env.example (lowest cost, highest UX win):
# ARCHON_HOME — local-only. IGNORED in Docker (the container always uses /.archon).
# ARCHON_HOME=~/.archon
# ARCHON_DATA — host-only. Used by docker-compose to choose the bind-mount source for /.archon.
# NOT read by Archon source code. The container always sees data at /.archon regardless.
# ARCHON_DATA=/opt/archon-data
-
Document a ~/.claude/ persistence recipe in docs/deployment/docker.md and docker-compose.override.example.yml:
# Persist Claude Code skills/prompts across container recreations
services:
app:
volumes:
- claude_home:/home/appuser/.claude
volumes:
claude_home:
Or via bind mount: ${CLAUDE_HOME:-claude_home}:/home/appuser/.claude mirroring the ARCHON_DATA pattern. (Needs the entrypoint to chown this on bind mounts the same way it does /.archon — see docker-entrypoint.sh:7-15.)
-
(Optional) Entrypoint warning: log a one-line stderr notice if ARCHON_HOME or ARCHON_DATA is set inside the container, e.g. [archon] ARCHON_HOME=… ignored in Docker (container home is fixed at /.archon). Deters silent confusion. Keeps existing behavior.
Definition of Done
Summary
ARCHON_HOMEandARCHON_DATAboth leak into the container env viaenv_file: .env, but neither is read by Archon code in the container —ARCHON_HOMEis silently overridden byisDocker(), andARCHON_DATAis a Compose host-side substitution token that no TS source ever reads. Operators seeARCHON_DATA=/Users/x/datainside the container, trycd $ARCHON_DATA, and get "no such file or directory"..env.exampledocuments both as configurable without the Docker caveats.appuserwith$HOME=/home/appuser, but no compose file mounts/home/appuser/.claude/— so user-installed Claude Code skills/prompts are lost on everydocker compose up --build/ image pull. There's no documented persistence story for "shared.claude/skillsacross all repos in the container."minor(UX / docs — no functional break; the bind mount itself works correctly)Steps to Reproduce
cp .env.example .env.env:ARCHON_DATA=/Users/myuser/develop-local/archon-data-volume(a host path)mkdir -p /Users/myuser/develop-local/archon-data-volumedocker compose up -ddocker compose exec app bashARCHON_HOME=/anywhere/elsein.env, restart:mkdir -p ~/.claude/skills/myskilland re-create the container — the directory is gone (not on the bind mount).Expected vs Actual
ARCHON_DATAandARCHON_HOMEeither work consistently inside and outside Docker, OR.env.examplewarns clearly that they don't..claude/skillsthat survives container recreation.ARCHON_HOMEis silently ignored in Docker (packages/paths/src/archon-paths.ts:56-74—getArchonHome()returns hardcoded/.archonwhenisDocker()is true).ARCHON_DATAis never read by any TS source — only by Compose substitution atdocker-compose.yml:41(${ARCHON_DATA:-archon_data}:/.archon).env_file: .env(docker-compose.yml:35,deploy/docker-compose.yml:17) and sit there as dead weight./home/appuser/.claude/, so any Claude Code config the user adds inside the container is ephemeral.User Flow
Environment
Logs
Inside container:
Source confirming the silent override:
grep -r ARCHON_DATA packages/returns only doc files — no source reads it.Impact
.env.exampleand tries to customize paths./home/appuser/.claude/viadocker-compose.override.yml.Scope
paths,infra,docspackages/paths/src/archon-paths.ts(clarify intent),.env.example,docker-compose.yml,deploy/docker-compose.yml,packages/docs-web/src/content/docs/deployment/docker.mdProposed Cleanup
Three small, independent changes — pick any subset:
Annotate
.env.example(lowest cost, highest UX win):Document a
~/.claude/persistence recipe indocs/deployment/docker.mdanddocker-compose.override.example.yml:Or via bind mount:
${CLAUDE_HOME:-claude_home}:/home/appuser/.claudemirroring theARCHON_DATApattern. (Needs the entrypoint to chown this on bind mounts the same way it does/.archon— seedocker-entrypoint.sh:7-15.)(Optional) Entrypoint warning: log a one-line stderr notice if
ARCHON_HOMEorARCHON_DATAis set inside the container, e.g.[archon] ARCHON_HOME=… ignored in Docker (container home is fixed at /.archon). Deters silent confusion. Keeps existing behavior.Definition of Done
.env.examplenotes the Docker semantics forARCHON_HOMEandARCHON_DATAdocs/deployment/docker.mdhas a "Persisting Claude Code config" recipe (or equivalent under "Data Directory")docker-compose.override.example.ymlshows the mount pattern as a comment