Initial commit
This commit is contained in:
26
.claudio
Normal file
26
.claudio
Normal file
@@ -0,0 +1,26 @@
|
||||
# .claudio — project settings for claudio.
|
||||
# Sourced as bash from the project directory. Everything here is optional;
|
||||
# the project directory itself is always mounted at its own path.
|
||||
|
||||
# Extra mounts, passed to `podman run -v`:
|
||||
# "/host/path" same path inside the container, read-write
|
||||
# "/host/path:/container/path" different path
|
||||
# "/host/path:/host/path:ro" same path, read-only
|
||||
MOUNTS=(
|
||||
# "$HOME/.gitconfig:/home/claude/.gitconfig:ro"
|
||||
# "$HOME/shared-libs:$HOME/shared-libs:ro"
|
||||
# "$PWD/../sibling-project"
|
||||
)
|
||||
|
||||
# Extra `podman run` options (env vars, ports, resources, ...).
|
||||
PODMAN_ARGS=(
|
||||
# -e GITHUB_TOKEN
|
||||
# -p 3000:3000
|
||||
# --memory 4g
|
||||
)
|
||||
|
||||
# Default arguments for claude itself.
|
||||
CLAUDE_ARGS=(
|
||||
# --dangerously-skip-permissions
|
||||
# --model opus
|
||||
)
|
||||
24
Containerfile
Normal file
24
Containerfile
Normal file
@@ -0,0 +1,24 @@
|
||||
# claudio — minimal image for running Claude Code in isolation.
|
||||
# Rebuild with `claudio update` to get the latest base packages and Claude Code.
|
||||
FROM docker.io/library/debian:stable-slim
|
||||
|
||||
# Base tools Claude Code relies on. Add project-wide tools here (python3, nodejs, ...).
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
ca-certificates curl git ripgrep less procps openssh-client \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& useradd -m -u 1000 -s /bin/bash claude
|
||||
|
||||
# Native Claude Code binary, installed system-wide (not in $HOME) so that image
|
||||
# rebuilds update it even though /home/claude is a persistent volume.
|
||||
RUN curl -fsSL https://claude.ai/install.sh | HOME=/tmp/cc bash \
|
||||
&& cp -L /tmp/cc/.local/bin/claude /usr/local/bin/claude \
|
||||
&& rm -rf /tmp/cc
|
||||
|
||||
# Updates come from rebuilding the image, not from in-container self-updates.
|
||||
ENV DISABLE_AUTOUPDATER=1 \
|
||||
PATH=/home/claude/.local/bin:$PATH
|
||||
|
||||
USER claude
|
||||
WORKDIR /home/claude
|
||||
ENTRYPOINT ["claude"]
|
||||
24
LICENSE
Normal file
24
LICENSE
Normal file
@@ -0,0 +1,24 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <https://unlicense.org/>
|
||||
68
README.md
Normal file
68
README.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# claudio
|
||||
|
||||
Run Claude Code isolated in a podman container, one command per project.
|
||||
|
||||
## Files
|
||||
|
||||
- `Containerfile`: the image (Debian slim + Claude Code).
|
||||
- `claudio.sh`: builds, updates and runs the container.
|
||||
- `.claudio`: template for per-project settings (plain bash).
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
mkdir -p ~/claudio && cp Containerfile claudio.sh ~/claudio/
|
||||
chmod +x ~/claudio/claudio.sh
|
||||
echo 'alias claudio=~/claudio/claudio.sh' >> ~/.bashrc
|
||||
```
|
||||
|
||||
Requires `podman` (rootless is fine).
|
||||
|
||||
## Usage
|
||||
|
||||
```sh
|
||||
cd ~/projects/myapp
|
||||
claudio # start Claude Code here (builds the image on first run)
|
||||
claudio --resume # any extra args are passed to claude
|
||||
claudio shell # bash inside the container instead of claude
|
||||
claudio build # build the image
|
||||
claudio update # rebuild from scratch: latest base image + latest Claude Code
|
||||
```
|
||||
|
||||
The current directory is mounted at the same path inside the container.
|
||||
Nothing else from the host is visible unless you add it to a `.claudio` file.
|
||||
|
||||
## Per-project settings
|
||||
|
||||
Copy the template into a project and uncomment what you need:
|
||||
|
||||
```sh
|
||||
cp ~/claudio/.claudio ~/projects/myapp/
|
||||
```
|
||||
|
||||
```bash
|
||||
MOUNTS=("$HOME/.gitconfig:/home/claude/.gitconfig:ro" "/data/shared")
|
||||
PODMAN_ARGS=(-e GITHUB_TOKEN -p 3000:3000)
|
||||
CLAUDE_ARGS=(--model opus)
|
||||
```
|
||||
|
||||
- `MOUNTS`: extra `-v` mounts. A bare path is mounted at the same path. Add `:ro` for read-only.
|
||||
- `PODMAN_ARGS`: extra `podman run` options.
|
||||
- `CLAUDE_ARGS`: default arguments for `claude`.
|
||||
|
||||
`.claudio` is sourced as bash, so only use ones you trust.
|
||||
|
||||
## State
|
||||
|
||||
The container's home (`/home/claude`) lives in the podman volume `claudio-home`.
|
||||
This volume is shared by all projects and holds your login, settings and history.
|
||||
The container itself is removed after every run.
|
||||
|
||||
- Reset everything: `podman volume rm claudio-home`
|
||||
- Need more tools in the image? Add them to the `apt-get install` line, then run `claudio update`.
|
||||
|
||||
## Notes
|
||||
|
||||
- Files written in mounts are owned by your host user (`--userns=keep-id`).
|
||||
- SELinux labeling is disabled for the container, so mounts work without relabeling.
|
||||
- claudio refuses to run from `$HOME` or `/`.
|
||||
61
claudio.sh
Executable file
61
claudio.sh
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env bash
|
||||
# claudio — run Claude Code isolated in a podman container.
|
||||
#
|
||||
# Install: keep this file next to the Containerfile, then
|
||||
# alias claudio=/path/to/claudio.sh (e.g. in ~/.bashrc)
|
||||
#
|
||||
# Usage: claudio [claude args...] run Claude Code in the current directory
|
||||
# claudio shell [bash args] open a bash shell in the container instead
|
||||
# claudio build build the image
|
||||
# claudio update rebuild from scratch (latest Debian + Claude Code)
|
||||
#
|
||||
# The current directory is mounted at its own path. If it contains a .claudio
|
||||
# file, that file is sourced (bash) for extra mounts and options.
|
||||
# The container's home (/home/claude: login, settings, history) lives in the
|
||||
# global podman volume "claudio-home".
|
||||
set -euo pipefail
|
||||
|
||||
IMAGE=localhost/claudio:latest
|
||||
VOLUME=claudio-home
|
||||
DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"
|
||||
|
||||
build() { podman build -t "$IMAGE" "$@" "$DIR"; }
|
||||
|
||||
case "${1:-}" in
|
||||
build) build; exit ;;
|
||||
update) build --pull=always --no-cache && podman image prune -f; exit ;;
|
||||
esac
|
||||
|
||||
if [[ "$PWD" == "$HOME" || "$PWD" == / ]]; then
|
||||
echo "claudio: refusing to mount $PWD — run it from a project directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
podman image exists "$IMAGE" || build
|
||||
|
||||
# Project settings (see the .claudio template).
|
||||
MOUNTS=() PODMAN_ARGS=() CLAUDE_ARGS=()
|
||||
if [[ -f .claudio ]]; then source ./.claudio; fi
|
||||
|
||||
args=(-v "$PWD:$PWD" -w "$PWD" -v "$VOLUME:/home/claude")
|
||||
for m in "${MOUNTS[@]}"; do
|
||||
[[ "$m" == *:* ]] || m="$m:$m" # bare path -> same path inside the container
|
||||
args+=(-v "$m")
|
||||
done
|
||||
|
||||
if [[ "${1:-}" == shell ]]; then
|
||||
shift
|
||||
args+=(--entrypoint bash)
|
||||
CLAUDE_ARGS=()
|
||||
fi
|
||||
|
||||
if [[ -t 0 && -t 1 ]]; then args+=(-it); else args+=(-i); fi
|
||||
|
||||
# keep-id maps your host user to the container's uid 1000, so files written
|
||||
# in mounts stay owned by you. label=disable avoids SELinux relabeling of mounts.
|
||||
exec podman run --rm "${args[@]}" \
|
||||
--userns=keep-id:uid=1000,gid=1000 \
|
||||
--security-opt label=disable \
|
||||
--hostname claudio \
|
||||
"${PODMAN_ARGS[@]}" \
|
||||
"$IMAGE" "${CLAUDE_ARGS[@]}" "$@"
|
||||
Reference in New Issue
Block a user