Skip to content

Instantly share code, notes, and snippets.

@DimmKirr
Last active September 18, 2025 06:35
Show Gist options
  • Select an option

  • Save DimmKirr/1c21b3c13a6c50dca4adba2ed1c80f1f to your computer and use it in GitHub Desktop.

Select an option

Save DimmKirr/1c21b3c13a6c50dca4adba2ed1c80f1f to your computer and use it in GitHub Desktop.
Claude Jail DevContainer
claude-jail-banner

Claude Jail DevContainer

This is a Taskfile that would start claude in an isolated Docker container in the "unhinghed" node with --dangerously-skip-permissions.

Creates:

  1. Directory: .devcontainer/ directory
  2. Files: .devcontainer/Dockerfile, .devcontainer/compose.dev.yml, .devcontainer/devcontainer.json

Mounts

  1. ./: Local directory at it's full path (without access to others)
  2. ~/.claude-sandbox (will be a new container-only claude home)
  3. ~/.claude/agents in read-only mode
  4. ~/.claude/commands in read-only mode

Usage

  1. Get Taskfile
  2. Get the Taskfile.yml into your local directory
  3. Run it
curl https://gist.githubusercontent.com/DimmKirr/1c21b3c13a6c50dca4adba2ed1c80f1f/raw/4b3281b7415c2936666e6c59ab74789aa83b900b/Taskfile.yml > Taskfile.yml
task claude

Motivation

I like Taskfile and I just needed a quick way to run Claude in multiple projects

# Claude Jail Taskfile. Used to run Claude.
# Actual app-related taskfile must be in Taskfile.yml
version: '3'
vars:
PORT: '{{.PORT | default "9090"}}'
HTTP_HOST: '{{.HTTP_HOST | default "0.0.0.0"}}'
APP_NAME: '{{ .APP_NAME | default (base .PWD)}}'
WORKSPACE: "{{.APP_NAME}}"
BINARY_NAME: "{{.APP_NAME}}"
COMPOSE: "docker compose -f {{.USER_WORKING_DIR}}/.devcontainer/compose.dev.yml"
RUN: "{{.COMPOSE}} run --remove-orphans -it claude"
CLAUDE: "{{.RUN}} claude --dangerously-skip-permissions"
DB_PATH: ./data/{{.APP_NAME}}.db
BASE_DIR: "{{ default .USER_WORKING_DIR }}"
env:
APP_NAME: "{{.APP_NAME}}"
BASE_DIR: "{{.BASE_DIR}}"
PORT: "{{.PORT}}"
tasks:
claude:
desc: Run Claude CLI in the dev container
silent: true
deps:
- _generate-all-configs
cmds:
- |
echo "APP_NAME: {{.APP_NAME}}"
- "{{.CLAUDE}} {{.CLI_ARGS}}"
deploy:
silent: true
cmds:
- |
if ! git remote -v | grep -q "dokku-{{.APP_NAME}}"; then
echo "Error: dokku-{{.APP_NAME}} remote not found"
echo "Please add the remote with: git remote add dokku-{{.APP_NAME}} [email protected]:{{.APP_NAME}}"
exit 1
fi
git commit --allow-empty -am "WIP" && git push dokku-{{.APP_NAME}} $(git branch --show-current):main
########## Generators ##########
_generate-mcp-config:
desc: Generate .mcp.json configuration file
silent: true
cmds:
- |
cat > {{.BASE_DIR}}/.mcp.json << 'EOF'
{
"mcpServers": {
"kitcut-sse": {
"type": "sse",
"url": "http://host.docker.internal:9090/sse",
"headers": {
"Authorization": "Bearer ${TEST_AUTH_TOKEN}"
}
},
"kitcut-local": {
"command": "./kitcut/kitcut",
"env": {
"DATA_DIR": "./kitcut/data"
}
}
}
}
EOF
echo "Generated {{.BASE_DIR}}/.mcp.json"
_generate-app-config:
desc: Generate app.json configuration file
silent: true
cmds:
- |
cat > {{.BASE_DIR}}/app.json << 'EOF'
{
"healthchecks": {
"web": [
{
"type": "startup",
"name": "web check",
"description": "Checking if the app responds to the /healthz endpoint",
"path": "/healthz",
"attempts": 3
}
]
}
}
EOF
echo "Generated {{.BASE_DIR}}/app.json"
_generate-devcontainer-compose:
desc: Generate .devcontainer/compose.dev.yml file
silent: true
cmds:
- mkdir -p {{.USER_WORKING_DIR}}/.devcontainer
- |
cat > {{.USER_WORKING_DIR}}/.devcontainer/compose.dev.yml << 'EOF'
---
services:
claude:
build:
context: .
dockerfile: Dockerfile
working_dir: /${BASE_DIR:-app}
container_name: claude-jail-${APP_NAME:-app}
volumes:
# Mount BASE_DIR under the same path
- ${BASE_DIR}:/${BASE_DIR}
# Mount the test run directory as workspace
- ${BASE_DIR}:/${APP_NAME:-app}
# Mount Claude and host agents
- ${HOME:-}/.claude-sandbox/:/root/ # Host-based sandbox home dir
- ${HOME:-}/.claude/agents:/root/.claude/agents:ro # Host-based agents
- ${HOME:-}/.claude/commands/kitcut:/root/.claude/commands/kitcut:ro # Host-based commands
environment:
APP_NAME: ${APP_NAME:-app}
IS_SANDBOX: 1
WORKSPACE: /${APP_NAME:-app}
TEST_AUTH_TOKEN: ${TEST_AUTH_TOKEN}
command: tail -f /dev/null # Keep container running
networks:
- claude-jail-network
networks:
claude-jail-network:
driver: bridge
EOF
echo "Generated {{.USER_WORKING_DIR}}/.devcontainer/compose.dev.yml"
_generate-devcontainer-dockerfile:
desc: Generate .devcontainer/Dockerfile
silent: true
cmds:
- mkdir -p {{.USER_WORKING_DIR}}/.devcontainer
- |
cat > {{.USER_WORKING_DIR}}/.devcontainer/Dockerfile << 'EOF'
FROM public.ecr.aws/docker/library/debian:trixie
# Install system dependencies
# build-essential is the meta-package that includes gcc, g++, make, libc-dev, etc.
# binutils-gold adds the gold linker that Go prefers
RUN apt-get update && apt-get install -y \
build-essential \
binutils-gold \
curl \
wget \
git \
jq \
tree \
ripgrep \
ca-certificates \
sqlite3 \
postgresql-client \
pkg-config \
procps \
htop \
vim \
&& rm -rf /var/lib/apt/lists/*
# Install Go (multi-arch support)
ENV GO_VERSION=1.24.6
RUN ARCH=$(dpkg --print-architecture) && \
curl -LO https://go.dev/dl/go${GO_VERSION}.linux-${ARCH}.tar.gz && \
tar -C /usr/local -xzf go${GO_VERSION}.linux-${ARCH}.tar.gz && \
rm go${GO_VERSION}.linux-${ARCH}.tar.gz
ENV PATH="/usr/local/go/bin:${PATH}"
ENV GOPATH="/go"
ENV PATH="${GOPATH}/bin:${PATH}"
# Install Task (Taskfile)
RUN sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin
# Install Node.js and npm (for potential frontend tools)
RUN curl -fsSL https://deb.nodesource.com/setup_24.x | bash - && \
apt-get install -y nodejs && \
rm -rf /var/lib/apt/lists/*
# Install Go development tools
RUN go install github.com/air-verse/air@latest && \
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest && \
go install golang.org/x/tools/cmd/goimports@latest
# Install Docker CLI and Docker Compose v2 (optional - for compose:* tasks)
# Note: Standard tasks (build, start, test) don't require Docker
RUN apt-get update && \
apt-get install -y \
apt-transport-https \
gnupg \
lsb-release && \
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && \
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null && \
apt-get update && \
apt-get install -y docker-ce-cli docker-compose-plugin && \
rm -rf /var/lib/apt/lists/*
# Install Claude CLI
RUN npm install -g @anthropic-ai/claude-code
# Set environment variables
ENV CLAUDE_HOME=/root
WORKDIR /${APP_NAME}
EOF
echo "Generated {{.USER_WORKING_DIR}}/.devcontainer/Dockerfile"
_generate-devcontainer-config:
desc: Generate .devcontainer/devcontainer.json file
silent: true
cmds:
- mkdir -p {{.USER_WORKING_DIR}}/.devcontainer
- |
cat > {{.USER_WORKING_DIR}}/.devcontainer/devcontainer.json << 'EOF'
{
"name": "Context Engineering Dev Container",
"dockerComposeFile": "compose.dev.yml",
"service": "claude",
"workspaceFolder": "/workspace",
// Features to add to the dev container
// Note: JetBrains may not support all features - these are primarily for VS Code
"features": {
"ghcr.io/devcontainers/features/git:1": {},
"ghcr.io/devcontainers/features/github-cli:1": {}
},
// Configure tool-specific properties
"customizations": {
// JetBrains IDE Native Dev Container Support (2024.3+)
// See: https://www.jetbrains.com/help/idea/start-dev-container-inside-ide.html
"jetbrains": {
// Product-specific IDE backend to use
"product": "GO", // Can be "GO" for GoLand, "IU" for IntelliJ Ultimate, "IC" for Community
// Plugins to install in the IDE backend
"plugins": [
"com.intellij.plugins.go",
"org.jetbrains.plugins.github",
"Docker",
"com.jetbrains.sh",
"name.kropp.intellij.makefile",
"com.github.copilot",
"org.jetbrains.plugins.terminal",
"org.jetbrains.plugins.yaml",
"com.intellij.tasks"
],
// IDE backend configuration
"ideOptions": {
"vmoptions": [
"-Xmx2048m",
"-XX:+UseG1GC",
"-XX:SoftRefLRUPolicyMSPerMB=50"
]
}
},
// Codespaces configuration (works with JetBrains Gateway)
"codespaces": {
"openFiles": [
"README.md"
]
},
"vscode": {
"extensions": [
"golang.Go",
"ms-vscode.makefile-tools",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"bradlc.vscode-tailwindcss",
"redhat.vscode-yaml",
"ms-azuretools.vscode-docker",
"GitHub.copilot",
"task.vscode-task"
],
"settings": {
"go.toolsManagement.checkForUpdates": "local",
"go.useLanguageServer": true,
"go.gopath": "/go",
"go.goroot": "/usr/local/go",
"terminal.integrated.defaultProfile.linux": "bash",
"editor.formatOnSave": true,
"editor.rulers": [80, 120],
"files.watcherExclude": {
"**/target/**": true,
"**/node_modules/**": true,
"**/.git/objects/**": true,
"**/vendor/**": true
}
}
}
},
// Environment variables
"remoteEnv": {
"GOPATH": "/go",
"PATH": "/usr/local/go/bin:/go/bin:${PATH}",
"DATA_DIR": "/data",
"CLAUDE_HOME": "/home/claude",
"WORKSPACE": "/workspace",
"GO111MODULE": "on"
},
// Mount points - these work with both VS Code and JetBrains
// JetBrains will use these if dockerComposeFile is not specified
"mounts": [
"source=${localWorkspaceFolder},target=/workspace,type=bind",
"source=${localWorkspaceFolder}/mcp-kits-server/data/KITS,target=/kits,type=bind,readonly",
"source=${localWorkspaceFolder}/mcp-kits-server,target=/mcp-server,type=bind,readonly",
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
],
// Run as the claude user
"remoteUser": "claude",
// Commands to run after container is created
"postCreateCommand": "go version && task --version && echo 'Dev container ready!'",
// Commands to run when attaching to the container
"postAttachCommand": "echo 'Welcome to Context Engineering Development Environment'",
// Forward ports from container to host
"forwardPorts": [8080, 3000, 5173],
// Comment out to run as root instead
"containerUser": "claude",
// Use 'postStartCommand' to run commands after the container is started
"postStartCommand": "git config --global --add safe.directory /workspace",
// Additional Docker run arguments - needed for debugging
"runArgs": [
"--cap-add=SYS_PTRACE",
"--security-opt",
"seccomp=unconfined",
"--init"
],
// JetBrains-specific: Ensure the container stays running
"overrideCommand": false,
// Ensure compatibility with both VS Code and JetBrains
"updateRemoteUserUID": true
}
EOF
echo "Generated {{.USER_WORKING_DIR}}/.devcontainer/devcontainer.json"
_generate-all-configs:
desc: Generate all configuration files
silent: true
cmds:
- task: _generate-mcp-config
vars:
BASE_DIR: "{{.BASE_DIR}}"
- task: _generate-app-config
vars:
BASE_DIR: "{{.BASE_DIR}}"
- task: _generate-devcontainer-compose
vars:
BASE_DIR: "{{.BASE_DIR}}"
- task: _generate-devcontainer-dockerfile
vars:
BASE_DIR: "{{.BASE_DIR}}"
- task: _generate-devcontainer-config
vars:
BASE_DIR: "{{.BASE_DIR}}"
- echo "All configuration files generated successfully!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment