Test worked
This commit is contained in:
+43
-29
@@ -1,8 +1,11 @@
|
||||
# The `claudaris` executable
|
||||
|
||||
`./claudaris` is a single bash script at the repo root that wraps every
|
||||
Docker operation. It `cd`s to its own directory first, so it can be invoked
|
||||
from anywhere. Run it with no arguments (or `help`) for usage.
|
||||
`./claudaris` is a single bash script at the repo root that wraps
|
||||
`docker compose` (see `docker-compose.yml`). It `cd`s to its own directory
|
||||
first, so it can be invoked from anywhere. Run it with no arguments (or
|
||||
`help`) for usage. Plain `docker compose` subcommands work directly too, as
|
||||
long as `.env` is present (compose reads it automatically) — `claudaris`
|
||||
just adds the `config` wizard and the host-side seeding/mount logic below.
|
||||
|
||||
```
|
||||
Usage: ./claudaris <command>
|
||||
@@ -33,43 +36,53 @@ means.
|
||||
sudo ./claudaris build
|
||||
```
|
||||
|
||||
Runs `docker build --no-cache --pull -t "$NAME" .`. Always uncached so a
|
||||
Runs `docker compose build --no-cache --pull`. 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](mcp.md) releases.
|
||||
|
||||
## `start`
|
||||
|
||||
Creates and starts the container — or just `docker start`s 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).
|
||||
Runs `docker compose up -d`, which creates the container if it doesn't exist
|
||||
and (re)starts it otherwise, per `docker-compose.yml`. Container/image name,
|
||||
volumes, and workspace mount come from `NAME`/`DATA_DIR`/`WORKSPACE_DIR`,
|
||||
which compose reads from `.env` the same way `claudaris` does — mount
|
||||
changes in `docker-compose.yml` take effect on the next `up -d` without
|
||||
needing `remove` first.
|
||||
|
||||
On the host side it first seeds, without overwriting anything that already
|
||||
exists:
|
||||
Before calling compose, `start` seeds the host side, without overwriting
|
||||
anything that already exists:
|
||||
|
||||
- `$DATA_DIR/home/.bashrc` and `$DATA_DIR/home/bash_aliases` — copied from
|
||||
`files/bashrc` and `files/bash_aliases`.
|
||||
- `$DATA_DIR/claude/credentials.json` and `$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.
|
||||
- `$DATA_DIR/claude/credentials.json`, `$DATA_DIR/claude/claude.json`, and
|
||||
`$DATA_DIR/opencode/auth.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.
|
||||
- `docker-compose.override.yml` (gitignored) — written to add the SSH mount
|
||||
below if `$DATA_DIR/ssh` exists, removed otherwise. Compose merges this
|
||||
file automatically when present; it's the only mount that can't live in
|
||||
`docker-compose.yml` directly, since compose has no way to make a volume
|
||||
conditional on a host path existing.
|
||||
|
||||
Then it runs the container with:
|
||||
The mounts, all declared in `docker-compose.yml`:
|
||||
|
||||
| Mount / flag | Purpose |
|
||||
| Mount | Purpose |
|
||||
| --- | --- |
|
||||
| `--name "$NAME" --hostname "$NAME"` | Prompt reads `root@$NAME` instead of a random container ID. |
|
||||
| `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](mcp.md); 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. |
|
||||
| `$DATA_DIR/opencode/auth.json` → `/root/.local/share/opencode/auth.json` | OpenCode provider credentials (API keys/OAuth tokens). |
|
||||
| `$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. |
|
||||
| `$DATA_DIR/ssh` → `/root/.ssh` (read-only, override file, 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.
|
||||
purpose: both Claude Code and OpenCode likely save 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`
|
||||
|
||||
@@ -77,20 +90,21 @@ persistence. A bind mount doesn't have that failure mode.
|
||||
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.
|
||||
Runs `docker compose up -d` (a no-op if already running) and then
|
||||
`docker compose exec claudaris bash`.
|
||||
|
||||
The explicit `docker start` matters because the container stops itself: the
|
||||
The explicit `up -d` 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.
|
||||
container sits stopped until `connect` (or `start`) brings it back. `tmux`
|
||||
itself stays installed and available — run it manually inside the container
|
||||
(the in-container `tmux` wrapper attaches to the `main` session if it exists
|
||||
and creates it otherwise) if you want it.
|
||||
|
||||
## `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
|
||||
Runs `docker compose down`, stopping and removing 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.
|
||||
|
||||
Reference in New Issue
Block a user