Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4.1 KiB
The claudaris executable
./claudaris is a single bash script at the repo root that wraps every
Docker operation. It cds to its own directory first, so it can be invoked
from anywhere. Run it with no arguments (or help) for usage.
Usage: ./claudaris <command>
Commands:
config, configure Interactive wizard to write .env with your settings
build Build the container image (always --no-cache --pull)
start Start (or create) the container
connect Start the container if needed, then attach a tmux session
remove, stop, rm Stop and remove the container
help Show this message
All commands source .env if present (gitignored, written by config),
falling back to NAME=claudaris and the defaults listed below.
config (alias: configure)
Interactive wizard: prompts for NAME, DATA_DIR, and WORKSPACE_DIR,
showing the current/default value for each (enter keeps it), then writes all
three to .env. Safe to re-run any time. See
Getting started for what each variable
means.
build
sudo ./claudaris build
Runs docker build --no-cache --pull -t "$NAME" .. Always uncached so a
rebuild picks up the latest Arch packages, the latest Claude Code release
(installed straight into /root in the image), and the latest
MCP server releases.
start
Creates and starts the container — or just docker starts it if a container
named $NAME already exists (in that case none of the mount setup below is
re-evaluated; use remove first to pick up mount changes).
On the host side it first seeds, without overwriting anything that already exists:
$DATA_DIR/home/.bashrcand$DATA_DIR/home/bash_aliases— copied fromfiles/bashrcandfiles/bash_aliases.$DATA_DIR/claude/credentials.jsonand$DATA_DIR/claude/claude.json— created empty. Seeding them as files matters: if Docker had to create the mount targets itself it would make directories, breaking the login mounts.
Then it runs the container with:
| Mount / flag | Purpose |
|---|---|
--name "$NAME" --hostname "$NAME" |
Prompt reads root@$NAME instead of a random container ID. |
$DATA_DIR/home/.bashrc → /root/.bashrc |
Per-host shell config, editable without a rebuild. |
$DATA_DIR/home/bash_aliases → /opt/dotfiles/bash_aliases |
Per-host aliases and MCP env vars; sourced by .bashrc. |
$DATA_DIR/claude/credentials.json → /root/.claude/.credentials.json |
Claude Code OAuth token. |
$DATA_DIR/claude/claude.json → /root/.claude.json |
Claude Code account/onboarding state and user-scope MCP config. |
$WORKSPACE_DIR → /projects |
Your project workspace. |
$DATA_DIR/ssh → /root/.ssh (read-only, only if the host dir exists) |
Opt-in SSH access to other machines. |
The login files are individual file mounts rather than a directory volume on
purpose: Claude Code saves them atomically (write a temp file, then
rename() over the target), and rename() onto a symlink replaces the
symlink instead of writing through it — which would silently break
persistence. A bind mount doesn't have that failure mode.
connect
sudo ./claudaris connect
Runs docker start "$NAME" (a no-op if already running) and then
docker exec -it "$NAME" tmux. The in-container tmux is a wrapper that
attaches to the main session if it exists and creates it otherwise, so
connect always lands you in the same session.
The explicit docker start matters because the container stops itself: the
entrypoint creates the main tmux session and exits once that session ends
(tmux defaults — a window closes when its shell exits, the session closes
with its last window). There's no --restart policy, so after a Ctrl+D the
container sits stopped until connect (or start) brings it back.
remove (aliases: stop, rm)
Stops (ignoring errors if already stopped) and removes the container, so the
next start recreates it fresh — needed after a build to actually run the
new image, or after changing mounts. Nothing under $DATA_DIR or
$WORKSPACE_DIR is touched.