Add opt-in GUI and audio support
This commit is contained in:
7
.claudio
7
.claudio
@@ -12,6 +12,13 @@ MOUNTS=(
|
|||||||
# "$PWD/../sibling-project"
|
# "$PWD/../sibling-project"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# GUI=1: graphical apps show up on your desktop (host Wayland socket + GPU).
|
||||||
|
# On KDE Plasma this also lets them control input, the screen and clipboard.
|
||||||
|
# AUDIO=1: apps can play sound through the host's PulseAudio/PipeWire socket.
|
||||||
|
# This also lets them record from your microphone.
|
||||||
|
GUI=0
|
||||||
|
AUDIO=0
|
||||||
|
|
||||||
# Extra `podman run` options (env vars, ports, resources, ...).
|
# Extra `podman run` options (env vars, ports, resources, ...).
|
||||||
PODMAN_ARGS=(
|
PODMAN_ARGS=(
|
||||||
# -e GITHUB_TOKEN
|
# -e GITHUB_TOKEN
|
||||||
|
|||||||
@@ -3,11 +3,15 @@
|
|||||||
FROM docker.io/library/debian:stable-slim
|
FROM docker.io/library/debian:stable-slim
|
||||||
|
|
||||||
# Base tools Claude Code relies on. Add project-wide tools here (python3, nodejs, ...).
|
# Base tools Claude Code relies on. Add project-wide tools here (python3, nodejs, ...).
|
||||||
|
# The second line is for GUI=1 / AUDIO=1: OpenGL drivers, a font, PulseAudio client.
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install -y --no-install-recommends \
|
&& apt-get install -y --no-install-recommends \
|
||||||
ca-certificates curl git ripgrep less procps openssh-client \
|
ca-certificates curl git ripgrep less procps openssh-client \
|
||||||
|
libgl1-mesa-dri fonts-dejavu-core libpulse0 libasound2-plugins \
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
&& useradd -m -u 1000 -s /bin/bash claude
|
&& useradd -m -u 1000 -s /bin/bash claude \
|
||||||
|
&& install -d -m 700 -o claude -g claude /run/user/1000 \
|
||||||
|
&& printf 'pcm.!default pulse\nctl.!default pulse\n' > /etc/asound.conf
|
||||||
|
|
||||||
# Native Claude Code binary, installed system-wide (not in $HOME) so that image
|
# Native Claude Code binary, installed system-wide (not in $HOME) so that image
|
||||||
# rebuilds update it even though /home/claude is a persistent volume.
|
# rebuilds update it even though /home/claude is a persistent volume.
|
||||||
@@ -17,7 +21,8 @@ RUN curl -fsSL https://claude.ai/install.sh | HOME=/tmp/cc bash \
|
|||||||
|
|
||||||
# Updates come from rebuilding the image, not from in-container self-updates.
|
# Updates come from rebuilding the image, not from in-container self-updates.
|
||||||
ENV DISABLE_AUTOUPDATER=1 \
|
ENV DISABLE_AUTOUPDATER=1 \
|
||||||
PATH=/home/claude/.local/bin:$PATH
|
PATH=/home/claude/.local/bin:$PATH \
|
||||||
|
XDG_RUNTIME_DIR=/run/user/1000
|
||||||
|
|
||||||
USER claude
|
USER claude
|
||||||
WORKDIR /home/claude
|
WORKDIR /home/claude
|
||||||
|
|||||||
21
README.md
21
README.md
@@ -41,17 +41,38 @@ cp ~/claudio/.claudio ~/projects/myapp/
|
|||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
GUI=1
|
||||||
|
AUDIO=1
|
||||||
MOUNTS=("$HOME/.gitconfig:/home/claude/.gitconfig:ro" "/data/shared")
|
MOUNTS=("$HOME/.gitconfig:/home/claude/.gitconfig:ro" "/data/shared")
|
||||||
PODMAN_ARGS=(-e GITHUB_TOKEN -p 3000:3000)
|
PODMAN_ARGS=(-e GITHUB_TOKEN -p 3000:3000)
|
||||||
CLAUDE_ARGS=(--model opus)
|
CLAUDE_ARGS=(--model opus)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- `GUI=1`: graphical apps open on your desktop (see below).
|
||||||
|
- `AUDIO=1`: apps can play sound (see below).
|
||||||
- `MOUNTS`: extra `-v` mounts. A bare path is mounted at the same path. Add `:ro` for read-only.
|
- `MOUNTS`: extra `-v` mounts. A bare path is mounted at the same path. Add `:ro` for read-only.
|
||||||
- `PODMAN_ARGS`: extra `podman run` options.
|
- `PODMAN_ARGS`: extra `podman run` options.
|
||||||
- `CLAUDE_ARGS`: default arguments for `claude`.
|
- `CLAUDE_ARGS`: default arguments for `claude`.
|
||||||
|
|
||||||
`.claudio` is sourced as bash, so only use ones you trust.
|
`.claudio` is sourced as bash, so only use ones you trust.
|
||||||
|
|
||||||
|
## Graphical apps and sound
|
||||||
|
|
||||||
|
Both are off by default and work by sharing a single socket from your session.
|
||||||
|
|
||||||
|
- `GUI=1` shares your Wayland socket and the GPU (`/dev/dri`), and makes
|
||||||
|
GTK, Qt, SDL and Electron apps use Wayland. It requires a Wayland session
|
||||||
|
(there is no X11 support). How isolated the container is depends on your
|
||||||
|
compositor: on KDE Plasma it **can type and click into other apps, record
|
||||||
|
the screen, read the clipboard and control all windows**, because KWin
|
||||||
|
offers those interfaces to every app.
|
||||||
|
- `AUDIO=1` shares the PulseAudio socket (`pulse/native`, also provided by
|
||||||
|
PipeWire). It works both ways: anything in the container can also **record
|
||||||
|
from your microphone**.
|
||||||
|
|
||||||
|
The image only ships OpenGL drivers, a font and the PulseAudio client. Add the
|
||||||
|
apps you want to run (and their libraries) to the `apt-get install` line.
|
||||||
|
|
||||||
## State
|
## State
|
||||||
|
|
||||||
The container's home (`/home/claude`) lives in the podman volume `claudio-home`.
|
The container's home (`/home/claude`) lives in the podman volume `claudio-home`.
|
||||||
|
|||||||
25
claudio.sh
25
claudio.sh
@@ -10,7 +10,8 @@
|
|||||||
# claudio update rebuild from scratch (latest Debian + Claude Code)
|
# claudio update rebuild from scratch (latest Debian + Claude Code)
|
||||||
#
|
#
|
||||||
# The current directory is mounted at its own path. If it contains a .claudio
|
# 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.
|
# file, that file is sourced (bash) for extra mounts and options, and can set
|
||||||
|
# GUI=1 / AUDIO=1 to share the host's Wayland / PulseAudio sockets.
|
||||||
# The container's home (/home/claude: login, settings, history) lives in the
|
# The container's home (/home/claude: login, settings, history) lives in the
|
||||||
# global podman volume "claudio-home".
|
# global podman volume "claudio-home".
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
@@ -34,7 +35,7 @@ fi
|
|||||||
podman image exists "$IMAGE" || build
|
podman image exists "$IMAGE" || build
|
||||||
|
|
||||||
# Project settings (see the .claudio template).
|
# Project settings (see the .claudio template).
|
||||||
MOUNTS=() PODMAN_ARGS=() CLAUDE_ARGS=()
|
MOUNTS=() PODMAN_ARGS=() CLAUDE_ARGS=() GUI=0 AUDIO=0
|
||||||
if [[ -f .claudio ]]; then source ./.claudio; fi
|
if [[ -f .claudio ]]; then source ./.claudio; fi
|
||||||
|
|
||||||
args=(-v "$PWD:$PWD" -w "$PWD" -v "$VOLUME:/home/claude")
|
args=(-v "$PWD:$PWD" -w "$PWD" -v "$VOLUME:/home/claude")
|
||||||
@@ -43,6 +44,26 @@ for m in "${MOUNTS[@]}"; do
|
|||||||
args+=(-v "$m")
|
args+=(-v "$m")
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# GUI/AUDIO: share a socket from the host's runtime dir into the container's.
|
||||||
|
host_run="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
|
||||||
|
share() {
|
||||||
|
[[ -S "$host_run/$1" ]] || { echo "claudio: no socket at $host_run/$1" >&2; exit 1; }
|
||||||
|
args+=(-v "$host_run/$1:/run/user/1000/$1")
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "$GUI" == 1 ]]; then
|
||||||
|
wl="${WAYLAND_DISPLAY:-wayland-0}"
|
||||||
|
share "$wl"
|
||||||
|
args+=(-e WAYLAND_DISPLAY="$wl" -e GDK_BACKEND=wayland -e QT_QPA_PLATFORM=wayland
|
||||||
|
-e SDL_VIDEODRIVER=wayland -e ELECTRON_OZONE_PLATFORM_HINT=wayland)
|
||||||
|
if [[ -e /dev/dri ]]; then args+=(--device /dev/dri); fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$AUDIO" == 1 ]]; then
|
||||||
|
share pulse/native
|
||||||
|
args+=(-e PULSE_SERVER=unix:/run/user/1000/pulse/native)
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ "${1:-}" == shell ]]; then
|
if [[ "${1:-}" == shell ]]; then
|
||||||
shift
|
shift
|
||||||
args+=(--entrypoint bash)
|
args+=(--entrypoint bash)
|
||||||
|
|||||||
Reference in New Issue
Block a user