Summary
On a containerized deployment, redeploying the dashboard makes the entire
chat session list disappear — the UI looks "reset to zero". The durable chat
history is not lost (the .jsonl logs survive), but the session index
that powers the conversation list is stored in an ephemeral path and is gone
after the container is recreated.
Root cause
SessionStore defaults its storage dir to the home directory:
// dashboard/terminal-server/src/utils/session-store.js
this.storageDir = options.storageDir || path.join(os.homedir(), '.claude-code-web');
this.sessionsFile = path.join(this.storageDir, 'sessions.json');
In the official container, os.homedir() is /root, so the index lives at
/root/.claude-code-web/sessions.json. That path is not under any of the
documented volumes, so a docker compose redeploy (new container) starts with
an empty index and loadSessions() returns an empty Map → the agent's session
list is empty.
The durable history is fine: ChatLogger writes to
workspace/ADWs/logs/chat/{agent}_{sessionId}.jsonl (under the workspace
volume), and sessions.json is explicitly described in the code as "a
fast-access cache; JSONL survives restarts and cleanups." The problem is only
that losing the cache makes the conversations unreachable from the UI,
because the list is built from the in-memory Map (seeded from sessions.json),
not by scanning the JSONL directory.
Steps to reproduce
- Run the dashboard in a container with the documented volumes mounted.
- Have one or more chat conversations with an agent.
- Recreate the container (
docker compose up -d --force-recreate, or any
redeploy via Coolify/Dokploy/etc.).
- Open the agent chat → the previous conversations are no longer listed.
(/root/.claude-code-web/sessions.json was reset; the .jsonl files are
still on disk in the workspace volume.)
Expected
Chat conversations remain listed across redeploys, as long as the data volumes
are intact.
Possible fixes (for maintainer discussion)
- Default
storageDir to a persisted path, e.g. under the existing
dashboard/data (or workspace) volume, so the index is durable by default.
- Honor an env var (e.g.
SESSION_STORE_DIR) and mount it, documented in
the deployment guide.
- Document that
/root/.claude-code-web must be a named volume in any
container deployment.
- Rebuild the index from JSONL on startup when
sessions.json is missing
(scan workspace/ADWs/logs/chat/*.jsonl, group by {agent}_{shortId}), so
the list self-heals even if the cache is lost. This also makes the cache
truly a cache.
Options 1 or 4 give the best out-of-the-box experience; (4) is the most robust
since it removes the cache as a single point of failure.
Workaround
Mount a volume at /root/.claude-code-web. To recover an already-lost list,
the index can be reconstructed from the surviving .jsonl files (filename
{agent}_{shortId}.jsonl) into sessions.json.
Environment
- Deployment: Docker container (official image), reverse-proxied.
- Affected file:
dashboard/terminal-server/src/utils/session-store.js.
Summary
On a containerized deployment, redeploying the dashboard makes the entire
chat session list disappear — the UI looks "reset to zero". The durable chat
history is not lost (the
.jsonllogs survive), but the session indexthat powers the conversation list is stored in an ephemeral path and is gone
after the container is recreated.
Root cause
SessionStoredefaults its storage dir to the home directory:In the official container,
os.homedir()is/root, so the index lives at/root/.claude-code-web/sessions.json. That path is not under any of thedocumented volumes, so a
docker composeredeploy (new container) starts withan empty index and
loadSessions()returns an empty Map → the agent's sessionlist is empty.
The durable history is fine:
ChatLoggerwrites toworkspace/ADWs/logs/chat/{agent}_{sessionId}.jsonl(under the workspacevolume), and
sessions.jsonis explicitly described in the code as "afast-access cache; JSONL survives restarts and cleanups." The problem is only
that losing the cache makes the conversations unreachable from the UI,
because the list is built from the in-memory Map (seeded from
sessions.json),not by scanning the JSONL directory.
Steps to reproduce
docker compose up -d --force-recreate, or anyredeploy via Coolify/Dokploy/etc.).
(
/root/.claude-code-web/sessions.jsonwas reset; the.jsonlfiles arestill on disk in the workspace volume.)
Expected
Chat conversations remain listed across redeploys, as long as the data volumes
are intact.
Possible fixes (for maintainer discussion)
storageDirto a persisted path, e.g. under the existingdashboard/data(or workspace) volume, so the index is durable by default.SESSION_STORE_DIR) and mount it, documented inthe deployment guide.
/root/.claude-code-webmust be a named volume in anycontainer deployment.
sessions.jsonis missing(scan
workspace/ADWs/logs/chat/*.jsonl, group by{agent}_{shortId}), sothe list self-heals even if the cache is lost. This also makes the cache
truly a cache.
Options 1 or 4 give the best out-of-the-box experience; (4) is the most robust
since it removes the cache as a single point of failure.
Workaround
Mount a volume at
/root/.claude-code-web. To recover an already-lost list,the index can be reconstructed from the surviving
.jsonlfiles (filename{agent}_{shortId}.jsonl) intosessions.json.Environment
dashboard/terminal-server/src/utils/session-store.js.