Visualise Claude Code session logs with a web UI. The ccdt command launches
claude-devtools as an on-demand Podman container,
restoring the detailed tool-output visibility that recent Claude Code updates replaced with opaque
summaries such as "Read 3 files".
Claude Code's recent updates removed detailed tool output from the UI, replacing it with brief
summaries. claude-devtools reconstructs and visualises the full session log by reading the raw
.claude/ session files on disk — no network access required.
ccdt wraps the tool as an on-demand Podman container. It starts instantly (image pre-built at
install time), opens a web UI at http://localhost:3456, and cleans up completely on exit.
ccdt supports two distinct session locations:
| Session type | Host filesystem path | When used |
|---|---|---|
| Host Claude Code | ~/.claude/ |
Regular claude / claude-code sessions |
| CCY project sessions | <project-dir>/.claude/ccy/ |
Sessions run inside the CCY container |
The command auto-detects which type applies based on your current directory.
Sessions are plain files on disk — there is nothing to "watch" at idle. Launching on demand means:
- Zero resource usage when not viewing sessions
- The correct
CLAUDE_ROOTis passed at launch time (no restart needed to switch projects) - Clean container teardown on Ctrl+C (no dangling processes)
- Podman installed (
ansible-playbook playbooks/imports/play-podman.yml) ~/.bashrc-includes/directory (created by main playbook)- Internet access to clone
https://github.com/matt1398/claude-devtoolsduring install
ansible-playbook playbooks/imports/optional/common/play-claude-devtools.ymlThe playbook:
- Clones
https://github.com/matt1398/claude-devtoolsto/opt/claude-devtools/ - Builds the container image locally as
claude-devtools:latest - Installs
~/.local/bin/ccdt(the wrapper script) - Installs
~/.bashrc-includes/claude-devtools.bash(shell alias)
After deployment:
source ~/.bashrc
ccdt --helpRun ccdt with no arguments from anywhere. It walks up the directory tree looking for
.claude/ccy/ (a CCY project). If found, it uses that. Otherwise it falls back to ~/.claude
(host sessions).
# From inside a CCY project → shows project sessions
cd ~/Projects/my-project
ccdt
# From anywhere else → shows host Claude Code sessions
cd ~
ccdtUse --host to always view host sessions regardless of your current directory:
ccdt --hostUseful when you are inside a CCY project directory but want to review host sessions.
Pass a path directly. ccdt checks for .claude/ccy/ within it first, then .claude/:
# View sessions for a specific project
ccdt ~/Projects/my-project
# View host sessions by path
ccdt ~/.claude# Non-existent path → clear error, non-zero exit
ccdt /nonexistent/path
# ERROR: Path does not exist: /nonexistent/pathccdt --help
ccdt-help # aliasOnce running, open http://localhost:3456 in your browser.
The web UI shows:
- Session list with timestamps
- Full tool call detail (the detail Claude Code's UI now hides)
- Tool inputs and outputs
- File reads, writes, bash commands, and their results
Press Ctrl+C in the terminal to stop. The container is removed automatically (--rm).
ccdt runs:
podman run \
--rm \
--init \
--replace \
--name "<project>_ccdt" \
-p 3456:3456 \
-v <CLAUDE_ROOT>:/data/.claude:ro \
-e CLAUDE_ROOT=/data/.claude \
claude-devtoolsKey points:
- Read-only mount (
:ro) — claude-devtools cannot modify your session files - No network required at runtime — reads files directly from disk
- Port 3456 — the claude-devtools default; must be free before running
--nameis derived from the session path, not fixed:~/.claude→host_ccdt,~/Projects/foo/.claude→foo_ccdt. So each project's container is identifiable rather than anonymous.--replaceis what makes a re-run work. Without it the secondccdtfor the same project fails with "container name already in use", because the name is deterministic.--initis what makes Ctrl+C work. It gives PID 1 a real init that forwards signals and reaps zombies; without it the container may not stop cleanly when you interrupt it.
Copy-pasting the command without --replace and --init gets you a container that collides on
the second run and may ignore Ctrl+C — the three flags are the run/stop/re-run loop, not noise.
Check what is using the port:
ss -tlnp | grep 3456Stop the conflicting process, then retry ccdt.
If the container image was not built during installation:
ansible-playbook playbooks/imports/optional/common/play-claude-devtools.ymlThis re-clones the repo (or pulls updates) and rebuilds the image.
Verify the session directory is correct and non-empty:
# For host sessions
ls ~/.claude/projects/
# For CCY project sessions
ls <project-dir>/.claude/ccy/projects/If the directory is empty, no sessions have been saved yet. Run Claude Code in the project first.
Ensure you are running ccdt from within the project directory (or a subdirectory), not from
an unrelated location:
cd ~/Projects/my-project
ccdt # should auto-detect .claude/ccy/Or pass the path explicitly:
ccdt ~/Projects/my-projectTo update to the latest claude-devtools:
# On host system (not in CCY container)
ansible-playbook playbooks/imports/optional/common/play-claude-devtools.ymlThe playbook pulls the latest source and rebuilds the image.
- CCY Guide — containerised Claude Code
- Playbooks Reference
- claude-devtools upstream