#!/bin/sh # Prepend the sandbox system prompt so Claude knows it is containerised and asks # the user to run host-side commands. Skipped for subcommands and for # --help/--version, which do not take the flag. # # With CCC_DIND=1 (and --privileged), a Docker daemon is started inside the # container first so Claude gets its own docker, isolated from the host's. set -e PROMPT_FILE=/etc/ccc/sandbox-prompt.md DIND_PROMPT_FILE=/etc/ccc/sandbox-prompt-dind.md DIND_LOG=/var/log/dockerd.log start_dind() { # cgroup v2: move ourselves out of the root cgroup and delegate all # controllers, otherwise dockerd cannot create cgroups for its containers. # Same trick as the official docker:dind entrypoint. if [ -f /sys/fs/cgroup/cgroup.controllers ]; then mkdir -p /sys/fs/cgroup/init xargs -rn1 < /sys/fs/cgroup/cgroup.procs > /sys/fs/cgroup/init/cgroup.procs 2>/dev/null || : sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers \ > /sys/fs/cgroup/cgroup.subtree_control 2>/dev/null || : fi dockerd > "$DIND_LOG" 2>&1 & i=0 until docker info > /dev/null 2>&1; do i=$((i + 1)) if [ "$i" -ge 30 ] || ! kill -0 "$!" 2>/dev/null; then echo "ccc: dockerd failed to start (is the container --privileged?). Last log lines:" >&2 tail -n 20 "$DIND_LOG" >&2 return 1 fi sleep 1 done } DIND_OK= if [ "$CCC_DIND" = 1 ]; then if start_dind; then DIND_OK=1 else echo "ccc: continuing without docker-in-docker" >&2 fi fi case "$1" in agents|attach|auth|auto-mode|doctor|gateway|import|install|logs|mcp|plugin|plugins|project|respawn|rm|setup-token|stop|kill|ultrareview|update|upgrade|-h|--help|-v|--version) exec claude "$@" ;; esac if [ -r "$PROMPT_FILE" ]; then PROMPT="$(cat "$PROMPT_FILE")" if [ -n "$DIND_OK" ] && [ -r "$DIND_PROMPT_FILE" ]; then PROMPT="$PROMPT $(cat "$DIND_PROMPT_FILE")" fi exec claude --append-system-prompt "$PROMPT" "$@" fi exec claude "$@"