@asteriidae/lazybum
v0.0.10
Published
LazyBum - AI sandbox CLI
Maintainers
Readme
@asteriidae/lazybum
Ephemeral Docker sandbox CLI for Claude Code with pre-configured tooling, plugins, and secure authentication.
Table of Contents
- Getting Started
- Configuration
- Usage
- How It Works
- Pre-installed Plugins
- Environment Variables
- Features
- Notifications
- Job Control
- Shell Completion
- Troubleshooting
- Migration from Docker Commands
- Legacy Docker Usage
- Development
- Licence
Getting Started
Prerequisites
Required Software:
| Software | Minimum Version | Installation |
| -------- | --------------------------- | -------------------------------- |
| Docker | Desktop 4.25+ or Engine 24+ | docker.com |
| Node.js | 20+ | nodejs.org |
| pnpm | 8+ | npm install -g pnpm |
Platform Support:
| Platform | Architecture | Status | | -------- | --------------------- | -------------- | | macOS | Intel (amd64) | Supported | | macOS | Apple Silicon (arm64) | Supported | | Linux | amd64 | Supported | | Linux | arm64 | Supported | | Windows | - | Coming in v2.0 |
Disk Space: ~4GB free (Docker image + build cache)
Installation
Released Version (Recommended)
pnpm add -g @asteriidae/lazybumAfter installation, the lazybum command is available globally.
From Source (Local Development)
# Clone the repository
git clone https://github.com/asteriidae/lazybum.git
cd lazybum
# Install dependencies
pnpm install
# Build the CLI and bundle assets
pnpm build && pnpm build:assets
# Run locally without global install
pnpm exec lazybum --help
# Or link globally for testing
pnpm link --global
lazybum --helpFirst Run
On first run, lazybum performs these steps automatically:
- Checks Docker availability - Verifies Docker daemon is running
- Builds the Docker image - Takes ~2-3 minutes on first run
- Starts the sandbox - Launches an ephemeral container
- Prompts for authentication (inside the sandbox) - Sign in once to persist credentials
Expected output:
$ lazybum
lazybum v0.0.2
Checking Docker... done
Building image (first run)... done
✓ Image: asteriidae/lazybum:0.0.2-abc1234
Starting sandbox...Authentication: The first run will prompt you to sign in inside the sandbox. Credentials are persisted on your machine for future runs.
Verification
Confirm everything is working:
# Check CLI is installed
lazybum --version
# Check configuration
lazybum config get
# Show config file location
lazybum config path
# Start a sandbox (you should see Claude's interactive prompt)
lazybumSuccess indicators:
lazybum --versionshows version numberlazybum config getdisplays your configurationlazybumlaunches Claude's interactive prompt inside the sandbox
Configuration
Storage Locations
| Item | macOS | Linux |
| -------------- | --------------------------------------- | --------------------------------------- |
| CLI Config | ~/.config/lazybum/config.json | ~/.config/lazybum/config.json |
| Profile Config | ~/.config/lazybum/profiles/<profile>/ | ~/.config/lazybum/profiles/<profile>/ |
| Tool State | Docker volume lazybum-<profile> | Docker volume lazybum-<profile> |
| Docker images | Docker Desktop storage | /var/lib/docker/ |
File permissions: Configuration files are created with mode 0600 (read/write owner only).
Docker volumes: Each profile stores tool configurations (Claude, Codex, Gemini), credentials, and service data in a named Docker volume. This provides native filesystem semantics and eliminates copy-on-start/stop complexity.
Root Configuration
Location: ~/.config/lazybum/config.json
Global settings shared across all profiles:
{
"version": 2,
"workspace": {
"defaultMount": "cwd",
"persistPlans": true
},
"output": {
"verbose": false
}
}| Key | Type | Default | Description |
| ------------------------ | ------- | ------- | ----------------------------------------- |
| workspace.defaultMount | string | "cwd" | Default mount point (cwd or git-root) |
| workspace.persistPlans | boolean | true | Mount ~/.claude/plans for persistence |
| output.verbose | boolean | false | Show detailed output |
Profile Configuration
Location: ~/.config/lazybum/profiles/<profile>/profile.json
Profile-specific settings for Docker resources, ports, environment variables, services, and storage:
{
"version": 4,
"mode": "claude",
"docker": {
"memoryLimit": "4g",
"cpuLimit": 4,
"defaultPorts": [],
"enabled": true
},
"notifications": {
"enabled": true,
"bridgePort": 9876,
"terminal": "auto"
},
"ports": [3000, 5173],
"env": {
"NODE_ENV": "development"
},
"services": {},
"storage": {
"sshKeyMount": "none"
}
}| Key | Type | Default | Description |
| -------------------------- | ------- | -------- | ------------------------------------------- |
| mode | string | claude | AI assistant (claude, gemini, codex, shell) |
| docker.memoryLimit | string | "4g" | Container memory limit |
| docker.cpuLimit | number | 4 | Container CPU core limit |
| docker.defaultPorts | array | [] | Default ports to forward |
| docker.enabled | boolean | auto | Mount Docker socket (auto-detected) |
| notifications.enabled | boolean | true | Enable desktop notifications |
| notifications.bridgePort | number | 9876 | Port for notification bridge |
| notifications.terminal | string | "auto" | Terminal to focus on click |
| ports | array | [] | Additional ports to forward |
| env | object | {} | Environment variables |
| services | object | {} | Background services configuration |
| storage.sshKeyMount | string | "none" | SSH key handling (host or none) |
Validation Rules
| Setting | Format | Valid Examples | Invalid Examples |
| -------------------- | ------------------------ | --------------------- | ----------------- |
| docker.memoryLimit | <number><unit> | 4g, 512m, 2048k | 4, 4gb, big |
| docker.cpuLimit | Positive integer | 1, 4, 8 | 0, -1, 4.5 |
| Ports | Integer 1-65535 | 3000, 8080 | 0, 70000 |
| Environment keys | [A-Za-z_][A-Za-z0-9_]* | NODE_ENV, MY_VAR | 1VAR, my-var |
Configuration Precedence
Settings are merged in this order (later values override earlier ones):
- Built-in defaults - Sensible starting values in Zod schemas
- Root config -
~/.config/lazybum/config.json(workspace, output) - Profile config -
~/.config/lazybum/profiles/<profile>/profile.json(docker, ports, env, services) - Command-line flags - Highest priority
Example: If the profile has ports: [3000] and you run lazybum --port 8080, the container exposes both ports 3000 and 8080.
Configuration Commands
# View entire configuration
lazybum config get
# View a specific value
lazybum config get docker.memoryLimit
# Set a configuration value
lazybum config set docker.memoryLimit 8g
lazybum config set docker.cpuLimit 8
lazybum config set output.verbose true
# Reset to defaults (requires confirmation)
lazybum config reset --force
# Show configuration file path
lazybum config pathUsage
Basic Usage
# Start sandbox in current directory
lazybum
# Start with explicit workspace
lazybum start -w ~/my-project
# Start with port forwarding
lazybum start --port 3000 --port 5173
# Port mapping with host:container syntax
lazybum start --port 8080:3000
# Pass environment variables
lazybum start -e NODE_ENV=production -e DEBUG=true
# Enable Docker (auto-detected when host has Docker)
lazybum start --docker
# Disable Docker socket mounting
lazybum start --no-docker
# Don't mount ~/.claude/plans
lazybum start --no-mount-plans
# Force rebuild the Docker image
lazybum start --rebuild
# Show detailed output
lazybum start --verboseMode Selection
Choose which AI assistant to launch:
# Available modes: claude (default), gemini, codex, shell
lazybum config set mode gemini # Use Google Gemini
lazybum config set mode codex # Use OpenAI Codex
lazybum config set mode shell # Plain bash (no AI)
lazybum config set mode claude # Anthropic Claude (default)Mode is saved per-profile and selected interactively in the settings menu.
API Keys: Configure via profile environment variables:
GOOGLE_API_KEYfor GeminiOPENAI_API_KEYfor Codex
Command Reference
lazybum Start sandbox in current directory
lazybum start [options] Start with explicit options
-w, --workspace <path> Workspace directory (default: cwd)
-e, --env <KEY=VALUE> Environment variable (repeatable)
-p, --port <port|host:container> Port mapping (repeatable)
--profile <name> Use specific profile
--name <name> Custom container name
--docker Mount host Docker socket (auto-detected)
--no-docker Disable Docker socket mounting
--no-mount-plans Don't mount ~/.claude/plans
--ssh-keys Mount host ~/.ssh directory (read-only)
--health Run host health checks before starting
--rebuild Force rebuild of Docker image
--verbose Show detailed output
lazybum config init Setup guidance (auth happens in sandbox)
lazybum config get [key] Get configuration value(s)
lazybum config set <key> <value> Set a configuration value
Supported keys:
mode AI assistant (claude|gemini|codex|shell)
docker.memoryLimit Container memory limit (e.g., 4g)
docker.cpuLimit CPU cores for container
notifications.enabled Enable/disable notifications
storage.sshKeyMount SSH key handling (host|none)
lazybum config reset Reset configuration to defaults
lazybum config path Show configuration file path
lazybum config profile list List all profiles
lazybum config profile create <name> Create a new profile
lazybum config profile delete <name> Delete a profile
lazybum config profile use <name> Set active profile
lazybum volume list List all profile volumes
lazybum volume delete <profile> Delete a profile volume
lazybum volume backup <profile> Backup a profile volume
-o, --output <path> Output file path (default: backup.tar.gz)
lazybum volume restore <profile> Restore a profile volume
<backup-path> Path to backup tarball
--force Skip confirmation prompt
lazybum volume migrate Migrate bind-mount data to volumes
--profile <name> Profile to migrate (default: all)
--dry-run Show what would be migratedHow It Works
Ephemeral Sandboxes
The CLI creates ephemeral containers that disappear when the session ends:
| What | Persists? | Where |
| --------------------------- | --------- | -------------------------------------- |
| Container | No | Removed on exit |
| Workspace files | Yes | Mounted from your machine |
| Claude conversation history | Yes | Anthropic's servers |
| Tool credentials/settings | Yes | Docker volume lazybum-<profile> |
| Plan files | Yes | Docker volume (inside claude/plans/) |
| Todo files | Yes | Docker volume (inside claude/todos/) |
| Service data | Yes | Docker volume (inside services/) |
Authentication
Authentication happens inside the sandbox on first run. Credentials and tool settings are persisted in a Docker volume named lazybum-<profile>.
Inside the container, standard tool paths are symlinked to the volume:
| Standard Path | Volume Path |
| ---------------- | --------------------------------- |
| ~/.claude.json | /mnt/profile/claude/claude.json |
| ~/.claude/ | /mnt/profile/claude/ |
| ~/.codex/ | /mnt/profile/codex/ |
| ~/.gemini/ | /mnt/profile/gemini/ |
This provides native filesystem semantics and eliminates the need for copy-on-start/stop logic. You only need to sign in once per profile.
See docs/volume-architecture.md for detailed architecture documentation.
Default Mounts
Every sandbox automatically mounts:
| Host | Container | Purpose |
| -------------------------- | ---------------------- | ----------------------------------- |
| Current directory | /workspace | Your project files |
| lazybum-<profile> volume | /mnt/profile | Tool configs, credentials, services |
| ~/.ssh (if --ssh-keys) | /mnt/host-ssh | Host SSH keys (read-only, optional) |
| /var/run/docker.sock | /var/run/docker.sock | Docker-in-Docker (if enabled) |
Pre-installed Plugins
The asterias-team plugin is automatically installed on first container startup.
asterias-team
Organisation-wide commands and specialised agents for collaborative development.
Commands: /review, /debug, /fix, /test, /docs, /analyse, /deps, /commit, /commit-msg, /amend
Agents: backend-architect, backend-security-coder, code-reviewer, database-architect, database-optimizer, debugger, frontend-developer, frontend-security-coder, graphql-architect, javascript-pro, security-auditor, senior-staff-engineer, tdd-orchestrator, test-automator, typescript-pro, ui-ux-designer, ui-visual-validator
Environment Variables
The CLI automatically passes these from your host environment:
GITHUB_TOKEN,GH_TOKEN, orGITHUB_PERSONAL_ACCESS_TOKEN- GitHub authenticationNPM_TOKEN- Private npm registry authenticationCONTEXT7_API_KEY- Context7 MCP server for documentation lookup (optional)
Additional variables can be passed with -e:
lazybum start -e AWS_REGION=eu-west-1 -e DEBUG=trueOr configure them in your profile's profile.json:
{
"env": {
"AWS_REGION": "eu-west-1",
"DEBUG": "true"
}
}Features
The Docker image includes:
- Base: Debian trixie-slim
- Init system: tini for proper signal handling (allows EXIT traps to run on container stop)
- Node.js 24 with pnpm
- Python 3.13 with uv and pre-activated virtual environment
- Terraform ecosystem: Terraform, Terragrunt, OpenTofu, tflint
- Docker support (via host socket binding, auto-detected)
- Essential CLI tools: fd, rg, jq, yq, fzf, bat, delta, tree, eza, gh, graphviz
- Git: Pre-configured with delta diffs, rebase-on-pull, auto-setup-remote
- Global CLAUDE.md: Pre-configured coding standards and agent delegation rules
- MCP Servers: repomix, github, sequential-thinking pre-configured
Notifications
The CLI sends desktop notifications (macOS only) to keep you informed of session activity without needing to watch the terminal.
Notification Events
| Event | Sound | When |
| --------------- | ----- | ------------------------------------------- |
| session_start | Glass | Session begins |
| session_end | Blow | Session ends |
| waiting | Ping | Claude is waiting for user input |
| completed | Purr | Task finished |
| error | Basso | An error occurred |
| progress | - | Progress update (silent, replaces previous) |
Clicking a notification focuses the terminal and selects the corresponding tmux window.
Persistent Notifications (macOS)
By default, notification banners auto-dismiss after a few seconds. To make notifications persistent (requiring manual dismissal):
- Open System Settings → Notifications
- Scroll down and find terminal-notifier in the application list
- Click on it and change the notification style from Banners to Alerts
Alerts remain on screen until you click "Close" or take action.
Note: This setting affects all notifications from terminal-notifier, not just Claude notifications.
Job Control
AI assistants (Claude, Gemini, Codex) run inside an interactive bash shell with full job control support:
| Shortcut | Action |
| -------- | ---------------------------------------- |
| Ctrl+Z | Suspend the AI assistant, return to bash |
| fg | Resume the suspended assistant |
| bg | Resume in background |
| jobs | List suspended/background jobs |
This allows you to:
- Temporarily suspend Claude to run shell commands
- Check something in another terminal session
- Resume exactly where you left off
# Example workflow
claude > Working on your task...
# Press Ctrl+Z
[1]+ Stopped claude --permission-mode bypassPermissions
$ git status # Run any shell command
$ fg # Resume Claude
claude > Continuing...Shell Completion
The CLI provides tab completion for bash, zsh, and fish shells, enabling faster command entry and discovery.
Installation
| Shell | Install Command | Reload Command |
| ----- | ------------------------------------------------------------------------------ | ------------------------------------ |
| Bash | lazybum completion bash > ~/.local/share/bash-completion/completions/lazybum | source ~/.bashrc |
| Zsh | lazybum completion zsh > ~/.zsh/completions/_lazybum | autoload -Uz compinit && compinit |
| Fish | lazybum completion fish > ~/.config/fish/completions/lazybum.fish | Automatic (Fish reloads completions) |
Alternative installation (Bash): Add directly to your .bashrc:
lazybum completion bash >> ~/.bashrc
source ~/.bashrcFeatures
Tab completion supports:
| Feature | Example | Completes To |
| ------------------- | ------------------------------ | -------------------------------------------------------- |
| Commands | lazybum [TAB] | start, config, session, hook |
| Config subcommands | lazybum config [TAB] | init, auth, get, set, reset, path, profile |
| Profile subcommands | lazybum config profile [TAB] | list, create, delete, use |
| Start flags | lazybum start --[TAB] | --workspace, --port, --env, --docker, etc. |
| Directory paths | lazybum start -w [TAB] | Directory completion |
| Hook subcommands | lazybum hook [TAB] | format, notify, tool, state |
Verification
Confirm completion is working:
# Test command completion
lazybum [TAB][TAB] # Should show: start config session hook
# Test subcommand completion
lazybum config [TAB] # Should show: init auth get set reset path profile
# Test flag completion
lazybum start --[TAB] # Should show all start command flagsTroubleshooting
| Issue | Solution |
| ----------------------------------- | ------------------------------------------------------------------------- |
| No completions appear | Verify script is in correct location and shell has been reloaded |
| Zsh: command not found: compdef | Run autoload -Uz compinit && compinit or add to .zshrc |
| Bash: Completions don't load | Install bash-completion package: brew install bash-completion (macOS) |
| Fish: Completions don't appear | Ensure directory ~/.config/fish/completions/ exists |
| Stale completions after CLI upgrade | Regenerate the completion script using the install command for your shell |
See docs/shell-completion.md for detailed configuration and customisation.
Troubleshooting
"Docker not available"
Ensure Docker Desktop or Docker Engine is running:
docker infoIf Docker is running but the CLI still fails, check Docker socket permissions:
# Linux only
sudo usermod -aG docker $USER
# Log out and back in"Prompts to authenticate every run"
Delete the profile volume and sign in again:
# Delete and recreate the default profile volume
lazybum volume delete default --force
lazybum startAlternatively, check that the volume exists:
# List volumes
docker volume ls | rg lazybum
# If missing, it will be created automatically on next start
lazybum start"Image build failed"
Force rebuild with verbose output:
lazybum start --rebuild --verboseCommon causes:
- Network issues downloading packages
- Insufficient disk space
- Docker daemon issues
"Permission denied on /workspace files"
Files created in the sandbox may have different ownership. Fix with:
sudo chown -R $(id -u):$(id -g) ."Container won't stop"
If a sandbox doesn't stop cleanly, find and remove it:
docker ps | rg lazybum
docker rm -f <container-id>Configuration not loading
Check configuration file syntax:
# View config file path
lazybum config path
# Validate JSON syntax
cat ~/.config/lazybum/config.json | jq .
# Check profile config
cat ~/.config/lazybum/profiles/default/profile.json | jq .Migration from Docker Commands
If you were using docker sandbox run or docker run directly:
| Before | After |
| ---------------------------------------------- | ---------------------------------------- |
| docker sandbox run --template asteriidae/... | lazybum |
| docker run -it asteriidae/lazybum | lazybum |
| Manual volume mounts | Automatic (cwd + plans) |
| Manual token passing via -e | Not supported (use sandbox login) |
| -p 3000:3000 port mapping | lazybum start --port 3000 |
| -e ENABLE_DOCKER=true --privileged | lazybum start --docker (auto-detected) |
Legacy Docker Usage
Direct Docker commands still work if needed:
Quick Start
docker sandbox run --template asteriidae/lazybum claudeWith Environment Variables
docker sandbox run --template asteriidae/lazybum \
-e GITHUB_TOKEN=ghp_xxx \
claudeWith Port Mapping
docker sandbox run --template asteriidae/lazybum \
-p 3000:3000 \
claudeWith Docker Socket Binding
docker run -it --rm \
-v $(pwd):/workspace \
-v /var/run/docker.sock:/var/run/docker.sock \
--group-add 999 \
asteriidae/lazybumNote: Containers created inside the sandbox are visible on the host via docker ps. Images pulled inside the sandbox use host disk space.
Persisting Plans
docker sandbox run --template asteriidae/lazybum \
-v ~/.claude/plans:/home/agent/.claude/plans \
claudeDevelopment
Building Locally
# Install dependencies
pnpm install
# Build the CLI
pnpm build
# Bundle assets (Dockerfile, entrypoint, etc.)
pnpm build:assets
# Type check
pnpm typecheck
# Run the CLI locally
pnpm exec lazybum --helpTesting
The CLI uses Vitest for testing with separate unit and E2E test suites.
Unit tests:
pnpm test # Run all unit tests
pnpm test:watch # Watch mode for development
pnpm test <pattern> # Run tests matching patternE2E tests:
E2E tests validate Docker container lifecycle operations. They require Docker to be installed and running.
# Run E2E tests (automatically skipped if Docker unavailable)
pnpm test src/lib/__tests__/e2e/| Test Suite | Requirement | Coverage |
| --------------------------------- | ------------- | ---------------------------------------------- |
| container-lifecycle.e2e.test.ts | Docker daemon | Create, run, stop, remove, volumes, ports, env |
Test structure:
src/
├── cli/
│ ├── completions/
│ │ └── *.test.ts # Completion generator tests
│ └── options/
│ └── *.test.ts # CLI option parsing tests
└── lib/
└── __tests__/
└── e2e/
└── *.e2e.test.ts # Docker E2E testsSee docs/e2e-testing.md for test architecture and patterns.
Plugin Development
See CLAUDE.md for plugin development guidelines.
Licence
MIT
