Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# ~/.agentbox/.env.example
# ============================================================================
# AgentBox Global Environment Variables
# Copy this file to ~/.agentbox/.env and replace placeholders with actual values
#
# This template is for GLOBAL configuration (~/.agentbox/.env).
# Project-level .env files (<project-dir>/.env) override these settings.
#
# Setup:
# cp ~/.agentbox/.env.example ~/.agentbox/.env
# chmod 600 ~/.agentbox/.env
#
# SECURITY: Never commit the actual .env file with real API keys!
# ============================================================================

# Anthropic (Claude)
# Get API key: https://console.anthropic.com/api-keys
# Used by: Claude Code, Pi Agent, OpenCode
ANTHROPIC_AUTH_TOKEN=sk-ant-your-anthropic-api-key-here
ANTHROPIC_BASE_URL=https://api.anthropic.com

# Claude Code model selection (optional, uses sensible defaults if not set)
ANTHROPIC_MODEL=claude-3-5-sonnet-20241022
ANTHROPIC_SMALL_FAST_MODEL=claude-3-5-haiku-20241022
ANTHROPIC_DEFAULT_OPUS_MODEL=claude-3-opus-20250219
ANTHROPIC_DEFAULT_SONNET_MODEL=claude-3-5-sonnet-20241022
ANTHROPIC_DEFAULT_HAIKU_MODEL=claude-3-5-haiku-20241022

# ============================================================================
# Docker Host Access (Optional)
# ============================================================================
# For containers to reach services running on the host, use:
# AGENTBOX_EXTRA_HOSTS=service.example.com:host-gateway
# Multiple entries can be comma-separated

# ============================================================================
# Optional: Additional LLM Providers
# ============================================================================
# Set API keys for any additional providers you use with OpenCode or Pi:
#
# OpenAI (https://platform.openai.com/api-keys)
# OPENAI_API_KEY=sk-...
#
# Google Gemini (https://aistudio.google.com/app/apikey)
# GEMINI_API_KEY=...
#
# Mistral (https://console.mistral.ai/api-keys)
# MISTRAL_API_KEY=...
#
# Groq (https://console.groq.com/keys)
# GROQ_API_KEY=...
#
# Other providers: Cerebras, xAI, OpenRouter, Azure OpenAI, Amazon Bedrock, etc.
# See Pi docs: https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/providers.md
# And OpenCode docs: https://opencode.ai/docs/config/

# ============================================================================
# Tool Configuration
# ============================================================================
# Claude Code, OpenCode, and Pi auto-mount configuration directories:
# - Claude: ~/.claude
# - OpenCode: ~/.config/opencode and ~/.local/share/opencode
# - Pi: ~/.pi/agent
#
# Authenticate tools inside agentbox:
# - Claude Code: automatic via ANTHROPIC_API_KEY
# - OpenCode: run 'opencode login' for OAuth
# - Pi: auto-uses ANTHROPIC_API_KEY or OPENAI_API_KEY etc.
#
# ANTHROPIC_API_KEY=sk-ant-your-anthropic-api-key-here
#
# SECURITY NOTE: This file is sourced automatically when using agentbox.
# Keep it private: chmod 600 ~/.agentbox/.env
# Never commit real API keys to git.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ Thumbs.db
# Docker
.dockerignore.local

# Worktrees
.worktrees/

# Logs
*.log

Expand Down
55 changes: 43 additions & 12 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
# AgentBox - Simplified multi-language development environment for Claude
FROM debian:trixie

# Optional Java toolchain (default: on for compatibility)
ARG AGENTBOX_INCLUDE_JAVA=true

# Claude Code channel (stable or latest)
ARG AGENTBOX_CC_CHANNEL=stable

# Include OpenCode (default: on)
ARG AGENTBOX_INCLUDE_OPENCODE=true

# Include Pi (default: off)
ARG AGENTBOX_INCLUDE_PI=false

# Simple traditional Unix-style prompt (default: off for backwards compatibility)
ARG AGENTBOX_SIMPLE_PROMPT=false

# Prevent interactive prompts during installation
ENV DEBIAN_FRONTEND=noninteractive
ENV LANG=en_US.UTF-8
Expand Down Expand Up @@ -33,8 +48,8 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
# Python build dependencies
python3-dev python3-pip python3-venv \
libssl-dev libffi-dev \
# Java dependencies
default-jdk maven gradle \
# Java dependencies (conditional)
$(if [ "$AGENTBOX_INCLUDE_JAVA" = "true" ]; then echo "default-jdk maven gradle"; fi) \
# Search tools
ripgrep fd-find && \
# Setup locale
Expand Down Expand Up @@ -111,13 +126,15 @@ RUN bash -c "source $NVM_DIR/nvm.sh && \
yarn \
pnpm"

# Install SDKMAN for Java toolchain management
RUN curl -s "https://get.sdkman.io?rcupdate=false" | bash && \
echo 'source "$HOME/.sdkman/bin/sdkman-init.sh"' >> ~/.bashrc && \
echo 'source "$HOME/.sdkman/bin/sdkman-init.sh"' >> ~/.zshrc && \
bash -c "source $HOME/.sdkman/bin/sdkman-init.sh && \
sdk install java 21.0.9-tem && \
sdk install gradle"
# Install SDKMAN for Java toolchain management (conditional)
RUN if [ "$AGENTBOX_INCLUDE_JAVA" = "true" ]; then \
curl -s "https://get.sdkman.io?rcupdate=false" | bash && \
echo 'source "$HOME/.sdkman/bin/sdkman-init.sh"' >> ~/.bashrc && \
echo 'source "$HOME/.sdkman/bin/sdkman-init.sh"' >> ~/.zshrc && \
bash -c "source $HOME/.sdkman/bin/sdkman-init.sh && \
sdk install java 21.0.9-tem && \
sdk install gradle"; \
fi

# Setup Python tools
RUN /home/${USERNAME}/.local/bin/uv tool install black && \
Expand Down Expand Up @@ -154,6 +171,11 @@ if [[ -n "$PS1" ]] && command -v stty >/dev/null; then
fi
EOF

# Simple traditional Unix-style prompt (opt-in: AGENTBOX_SIMPLE_PROMPT=true)
RUN if [ "$AGENTBOX_SIMPLE_PROMPT" = "true" ]; then \
echo 'PROMPT='"'"'%n@%m:%~ $ '"'"'' >> ~/.zshrc; \
fi

# Configure git
RUN git config --global init.defaultBranch main && \
git config --global pull.rebase false
Expand Down Expand Up @@ -201,11 +223,20 @@ USER ${USERNAME}
# Dockerfile hasn't changed. This ensures fresh installs on explicit rebuilds instead
# of relying on unpredictable auto-update timing.
ARG BUILD_TIMESTAMP=unknown
RUN curl -fsSL https://claude.ai/install.sh | bash -s stable && \
RUN curl -fsSL https://claude.ai/install.sh | bash -s ${AGENTBOX_CC_CHANNEL} && \
zsh -i -c 'which claude && claude --version'

RUN curl -fsSL https://opencode.ai/install | bash && \
zsh -i -c 'which opencode && opencode --version'
RUN if [ "$AGENTBOX_INCLUDE_OPENCODE" = "true" ]; then \
curl -fsSL https://opencode.ai/install | bash && \
zsh -i -c 'which opencode && opencode --version'; \
fi

RUN if [ "$AGENTBOX_INCLUDE_PI" = "true" ]; then \
export NVM_DIR="/home/agent/.nvm" && \
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" && \
npm install -g @mariozechner/pi-coding-agent && \
zsh -i -c 'which pi && pi --version'; \
fi

# Entrypoint
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
Expand Down
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ No configuration needed - just install either runtime.

- claude code: built-in
- opencode: built-in
- pi: built-in (opt-in via AGENTBOX_TOOL=pi)
- any other agents (copilot CLI, Aider, Cursor CLI...): easily add it yourself using the prompt at [docs/prompts/add-tool.md](docs/prompts/add-tool.md).

### Adding tools
Expand All @@ -56,6 +57,9 @@ agentbox
# Use OpenCode instead of Claude
agentbox --tool opencode

# Use Pi instead of Claude (requires AGENTBOX_TOOL=pi in config first)
agentbox --tool pi

# Or set via environment variable
AGENTBOX_TOOL=opencode agentbox

Expand Down Expand Up @@ -96,6 +100,7 @@ Persistent data (survives container removal):
History: ~/.agentbox/projects/agentbox-<hash>/history/
Claude: ~/.claude
OpenCode: ~/.config/opencode and ~/.local/share/opencode
Pi: ~/.pi
```

## Languages and Tools
Expand All @@ -108,6 +113,7 @@ The unified container image includes:
- **Shell**: Zsh (default) and Bash with common utilities
- **Claude CLI**: Pre-installed with per-project authentication
- **OpenCode**: Pre-installed as an alternative AI coding tool
- **Pi**: Pre-installed (opt-in via `--tool pi` or config)

## Authenticating to Git or other SCC Providers

Expand Down Expand Up @@ -184,13 +190,16 @@ Zsh history is preserved in `~/.agentbox/projects/<container-name>/history`

Both tools use bind mounts to share authentication across all AgentBox projects:

**Claude CLI**:
**Claude**:
- `~/.claude` mounted at `/home/agent/.claude`

**OpenCode**:
- Config: `~/.config/opencode` mounted at `/home/agent/.config/opencode`
- Auth: `~/.local/share/opencode` mounted at `/home/agent/.local/share/opencode`

**Pi**:
- `~/.pi` mounted at `/home/agent/.pi`

## Advanced Usage

### Running One-Off Commands
Expand Down
78 changes: 71 additions & 7 deletions agentbox
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ build_image() {
--build-arg GROUP_ID="${group_id}" \
--build-arg USERNAME="agent" \
--build-arg BUILD_TIMESTAMP=${build_timestamp} \
--build-arg AGENTBOX_INCLUDE_JAVA="${include_java}" \
--build-arg AGENTBOX_INCLUDE_OPENCODE="${include_opencode}" \
--build-arg AGENTBOX_INCLUDE_PI="${include_pi}" \
--build-arg AGENTBOX_CC_CHANNEL="${cc_channel}" \
--build-arg AGENTBOX_SIMPLE_PROMPT="${simple_prompt}" \
--label "agentbox.hash=${combined_hash}" \
--label "agentbox.version=1.0.0" \
--label "agentbox.built=${build_timestamp}" \
Expand Down Expand Up @@ -332,6 +337,16 @@ run_container() {
)

log_info "OpenCode configuration and auth mounted"
elif [[ "$tool" == "pi" ]]; then
local pi_dir="${HOME}/.pi"

mkdir -p "$pi_dir"

mount_opts+=(
-v "${pi_dir}:/home/agent/.pi"
)

log_info "Pi configuration mounted"
else
local claude_dir="${HOME}/.claude"

Expand Down Expand Up @@ -370,6 +385,8 @@ run_container() {
local tool_cmd
if [[ "$tool" == "opencode" ]]; then
tool_cmd="opencode"
elif [[ "$tool" == "pi" ]]; then
tool_cmd="pi"
else
tool_cmd="claude --dangerously-skip-permissions"
fi
Expand Down Expand Up @@ -466,11 +483,14 @@ Usage:

Options:
-h, --help Show this help message
--tool TOOL Choose tool: claude (default) or opencode
--tool TOOL Choose tool: claude (default), opencode, or pi
-p PORT Forward a port from host to container (can be used multiple times)
--rebuild Force rebuild of the image
--add-dir DIR Mount additional directory (can be used multiple times)
--ignore-dot-env Do not load .env files as environment variables (still mounted)
--no-java Exclude Java toolchain for smaller image (default: included)
--no-opencode Exclude OpenCode installation for smaller image (default: included)
--cc-latest Use Claude Code latest channel instead of stable (may be ahead of stable)

Commands:
shell [--admin] Start interactive shell instead of Claude CLI
Expand All @@ -481,18 +501,23 @@ Commands:
Use 'shell --admin' to get a shell with sudo privileges.
Other commands will be executed inside the container.

Configuration:
Config file: ~/.agentbox/config
CLI flags override config file settings.
See config.example for all available options.

Examples:
agentbox # Start Claude CLI for current project
agentbox --tool opencode # Start OpenCode instead of Claude
agentbox --tool pi # Start Pi instead of Claude
agentbox -p 3002 # Forward port 3002
agentbox -p 3002:8080 # Map host port 3002 to container port 8080
agentbox shell # Start interactive shell instead of Claude
agentbox shell --admin # Start admin shell with sudo access
agentbox --add-dir ~/1 --add-dir ~/2 # Add dirs with Claude CLI
agentbox --add-dir ~/1 --add-dir ~/2 # Add dirs with Claude CLI
agentbox python script.py # Run Python script in container
agentbox --rebuild # Force rebuild image
agentbox ssh-init # Set up SSH for AgentBox
AGENTBOX_TOOL=opencode agentbox # Use env var to select tool

Environment variables (set in ~/.agentbox/.env):
AGENTBOX_EXTRA_HOSTS Comma-separated host:ip pairs added to container /etc/hosts
Expand Down Expand Up @@ -543,8 +568,20 @@ ssh_setup() {
log_info "AgentBox will use this directory for all SSH operations."
}

# Load config file if exists
load_config() {
local config_file="${HOME}/.agentbox/config"
if [[ -f "$config_file" ]]; then
# Source the config file, allowing it to override defaults
source "$config_file"
fi
}

# Main execution
main() {
# Load config file first (before CLI args, so CLI args can override)
load_config

# Parse arguments
local force_rebuild=false
local shell_mode=false
Expand All @@ -553,7 +590,12 @@ main() {
declare -a ports=()
local extra_dirs=()
local tool="${AGENTBOX_TOOL:-claude}"
local ignore_dot_env=false
local ignore_dot_env="${AGENTBOX_IGNORE_DOT_ENV:-false}"
local include_java="${AGENTBOX_INCLUDE_JAVA:-true}"
local include_opencode="${AGENTBOX_INCLUDE_OPENCODE:-true}"
local include_pi="${AGENTBOX_INCLUDE_PI:-false}"
local cc_channel="${AGENTBOX_CC_CHANNEL:-stable}"
local simple_prompt="${AGENTBOX_SIMPLE_PROMPT:-false}"

while [[ $# -gt 0 ]]; do
case "$1" in
Expand Down Expand Up @@ -586,7 +628,7 @@ main() {
--tool)
shift
if [[ -z "${1:-}" ]]; then
log_error "--tool requires a value (claude or opencode)"
log_error "--tool requires a value (claude, opencode, or pi)"
exit 1
fi
tool="$1"
Expand All @@ -596,6 +638,18 @@ main() {
ignore_dot_env=true
shift
;;
--no-java)
include_java=false
shift
;;
--no-opencode)
include_opencode=false
shift
;;
--cc-latest)
cc_channel=latest
shift
;;
shell)
shell_mode=true
shift
Expand All @@ -620,11 +674,21 @@ main() {
done

# Validate tool selection
if [[ "$tool" != "claude" && "$tool" != "opencode" ]]; then
log_error "Invalid tool: $tool (must be 'claude' or 'opencode')"
if [[ "$tool" != "claude" && "$tool" != "opencode" && "$tool" != "pi" ]]; then
log_error "Invalid tool: $tool (must be 'claude', 'opencode', or 'pi')"
exit 1
fi

# Auto-enable OpenCode if tool is set to opencode
if [[ "$tool" == "opencode" ]]; then
include_opencode=true
fi

# Auto-enable Pi if tool is set to pi
if [[ "$tool" == "pi" ]]; then
include_pi=true
fi

# Check runtime
RUNTIME=$(check_runtime)
log_info "Using container runtime: $RUNTIME"
Expand Down
Loading
Loading