From 46013b5ec058aa90e10708eddc46ae53c77842bf Mon Sep 17 00:00:00 2001 From: Tim Perkins Date: Sat, 6 Jun 2026 22:58:18 -0400 Subject: [PATCH] Add agent layer Adds the Claude Code CLI to start with. --- .github/workflows/build.yaml | 13 ++++++++++++- containers/agent/Containerfile | 34 ++++++++++++++++++++++++++++++++++ containers/build.sh | 17 +++++++++++------ containers/run.sh | 11 +++++++++-- 4 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 containers/agent/Containerfile diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 83e02f1..910a578 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -72,6 +72,17 @@ jobs: skip-pull: true push: true registry-pass: ${{ secrets.REGISTRY_TOKEN }} + - name: Build Agent Layer + id: agent + uses: taughz/hn2b@2b065e13aafcbe62e4f104412243382011ab836d + with: + image: ${{ env.TARGET_IMAGE }} + context: containers/agent + dockerfile: Containerfile + base-image: ${{ steps.base.outputs.image }} + skip-pull: true + push: true + registry-pass: ${{ secrets.REGISTRY_TOKEN }} - name: Build C++ Layer id: cpp uses: taughz/hn2b@2b065e13aafcbe62e4f104412243382011ab836d @@ -79,7 +90,7 @@ jobs: image: ${{ env.TARGET_IMAGE }} context: containers/cpp dockerfile: Containerfile - base-image: ${{ steps.base.outputs.image }} + base-image: ${{ steps.agent.outputs.image }} skip-pull: true push: true registry-pass: ${{ secrets.REGISTRY_TOKEN }} diff --git a/containers/agent/Containerfile b/containers/agent/Containerfile new file mode 100644 index 0000000..b13906f --- /dev/null +++ b/containers/agent/Containerfile @@ -0,0 +1,34 @@ +# cpp/Containerfile + +# Copyright (c) 2026 Tim Perkins + +ARG BASE_IMAGE="scratch" +FROM $BASE_IMAGE + +# Ensure root user +USER root +WORKDIR / + +# Make sure we don't get prompted +ARG DEBIAN_FRONTEND="noninteractive" +ARG TERM="dumb" + +# You can use the following URL to determine the current stable version: +# https://downloads.claude.ai/claude-code-releases/stable + +ARG CLAUDE_VERSION="2.1.153" +ARG CLAUDE_PLATFORM="linux-x64" +ARG CLAUDE_URL="https://downloads.claude.ai/claude-code-releases/$CLAUDE_VERSION/$CLAUDE_PLATFORM/claude" +ARG CLAUDE_FILE="/usr/local/bin/claude" +ARG CLAUDE_SHA256SUM="214f603f31942162dac9a65f18d43b3ac646ae215240fad481c4aad6c60f2e38" + +# You can find the official checksum here: +# https://downloads.claude.ai/claude-code-releases/$CLAUDE_VERSION/manifest.json + +RUN curl -fL -o $CLAUDE_FILE "$CLAUDE_URL" \ + && (echo "$CLAUDE_SHA256SUM $CLAUDE_FILE" | sha256sum --quiet -c -) \ + && chmod +x $CLAUDE_FILE + +# Switch to non-root user +USER $DEV_USER +WORKDIR $DEV_USER_HOME diff --git a/containers/build.sh b/containers/build.sh index 390bdbb..489c435 100755 --- a/containers/build.sh +++ b/containers/build.sh @@ -17,10 +17,11 @@ DEFAULT_TARGET_TAG="built" EMACS_BUILDER_REPO="ghcr.io/taughz/dev-emacs-builder" DOOM_CACHE_REPO="ghcr.io/taughz/dev-doom-cache" -IMAGES=("BASE" "CPP" "PYTHON" "ROS" "EMSDK" "EMACS" "XPRA" "USER") +IMAGES=("BASE" "AGENT" "CPP" "PYTHON" "ROS" "EMSDK" "EMACS" "XPRA" "USER") declare -A IMAGE_DIRS=( ["BASE"]="$SCRIPT_DIR/base" + ["AGENT"]="$SCRIPT_DIR/agent" ["CPP"]="$SCRIPT_DIR/cpp" ["PYTHON"]="$SCRIPT_DIR/python" ["ROS"]="$SCRIPT_DIR/ros" @@ -37,15 +38,16 @@ declare -A IMAGE_DIRS=( # Prints help message for this script. function show_usage() { cat <&2 -Usage: $(basename "$0") [-t | --tag TAG] [-a | --all] [-c | --cpp] - [-p | --python] [-r | --ros] [-w | --emsdk] [-e | --emacs] - [-x | --xpra] [-u | --user] [-k | --no-cache] [-n | --name] - [-l | --log] [-h | --help] +Usage: $(basename "$0") [-t | --tag TAG] [-a | --all] [-b | --agent] + [-c | --cpp] [-p | --python] [-r | --ros] [-w | --emsdk] + [-e | --emacs] [-x | --xpra] [-u | --user] [-k | --no-cache] + [-n | --name] [-l | --log] [-h | --help] Make the Taughz development image. -t | --tag TAG Tag the image with the given tag -a | --all Build all layers + -b | --agent Build the agent layer -c | --cpp Build the C++ layer -p | --python Build the Python layer -r | --ros Build the ROS layer @@ -64,6 +66,7 @@ EOF target_tag=$DEFAULT_TARGET_TAG declare -A layer_requested=( ["BASE"]=1 + ["AGENT"]=0 ["CPP"]=0 ["PYTHON"]=0 ["ROS"]=0 @@ -81,6 +84,7 @@ for arg in "$@"; do case "$arg" in "--tag") set -- "$@" "-t";; "--all") set -- "$@" "-a";; + "--agent") set -- "$@" "-b";; "--cpp") set -- "$@" "-c";; "--python") set -- "$@" "-p";; "--ros") set -- "$@" "-r";; @@ -98,10 +102,11 @@ for arg in "$@"; do done # Parse short options using getopts -while getopts "t:acprwexuknlh" arg &> /dev/null; do +while getopts "t:abcprwexuknlh" arg &> /dev/null; do case "$arg" in "t") target_tag=$OPTARG;; "a") for co in "${IMAGES[@]}"; do layer_requested[$co]=1; done;; + "b") layer_requested["AGENT"]=1;; "c") layer_requested["CPP"]=1;; "p") layer_requested["PYTHON"]=1;; "r") layer_requested["ROS"]=1;; diff --git a/containers/run.sh b/containers/run.sh index 7690abb..f90feda 100755 --- a/containers/run.sh +++ b/containers/run.sh @@ -155,6 +155,8 @@ ensure_exists d 700 $HOME/.ssh ensure_exists d 700 $HOME/.gnupg ensure_exists f 644 $HOME/.gitconfig ensure_exists d 700 $HOME/.xpra +ensure_exists f 600 $HOME/.claude.json +ensure_exists d 700 $HOME/.claude # Get the user data ready passwd_ent=$(getent passwd $(id -u)) @@ -201,6 +203,11 @@ XPRA_FLAGS=( --mount "type=bind,src=$HOME/.xpra,dst=$CHOME/.xpra" ) +CLAUDE_FLAGS=( + --mount "type=bind,src=$HOME/.claude.json,dst=$CHOME/.claude.json" + --mount "type=bind,src=$HOME/.claude,dst=$CHOME/.claude" +) + SHELL_FLAGS=( --mount "type=volume,src=$SHELL_CONFIG_VOL,dst=$SHELL_CONFIG_DIR" ) @@ -225,7 +232,7 @@ fi echo_cmd docker run --rm --tty --interactive --privileged --network=host --env "TERM=$TERM" \ "${DISPLAY_FLAGS[@]}" "${SSH_FLAGS[@]}" "${GPG_FLAGS[@]}" "${GIT_FLAGS[@]}" \ - "${XPRA_FLAGS[@]}" "${SHELL_FLAGS[@]}" "${fixed_user_flags[@]}" "${emacs_flags[@]}" \ - "${projects_flags[@]}" "${tz_flags[@]}" "$TARGET_IMAGE" + "${XPRA_FLAGS[@]}" "${CLAUDE_FLAGS[@]}" "${SHELL_FLAGS[@]}" "${fixed_user_flags[@]}" \ + "${emacs_flags[@]}" "${projects_flags[@]}" "${tz_flags[@]}" "$TARGET_IMAGE" exit 0