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