Complete documentation for Maestro (Multi-Container Claude), covering advanced features, configuration, architecture, and troubleshooting.
- Installation
- Configuration
- Usage
- Background Daemon
- Token Management
- Network Management
- Architecture
- Troubleshooting
- Development
curl -fsSL https://raw.githubusercontent.com/uprockcom/maestro/main/install.sh | bashThis will:
- Download the latest release for your platform
- Install the
maestrobinary to/usr/local/bin - Pull the Docker image
- Create the config directory at
~/.maestro - Set up the example configuration
Prerequisites:
- Docker must be installed and running
curlcommand available
For development or if you prefer to build from source:
# Clone the repository
git clone https://github.com/uprockcom/maestro.git
cd maestro
# Build everything (binary + Docker image)
make all
# Install to /usr/local/bin (requires sudo)
sudo make installAvailable make targets:
make build # Build maestro binary only
make docker # Build Docker image only
make all # Build both binary and image
make install # Install maestro to /usr/local/bin
make test # Run Go tests
make clean # Remove built binaries
make help # Show all available targetsAfter installation, set up authentication:
maestro authConfigure your preferences:
nano ~/.maestro/config.ymlThe configuration file lives at ~/.maestro/config.yml. Here's a complete reference:
claude:
config_path: ~/.claude # Your Claude auth directory
auth_path: ~/.maestro/.claude # Maestro's centralized auth storage
default_mode: yolo # Auto-approve mode
containers:
prefix: maestro- # Container name prefix
image: maestro:latest # Docker image name
resources:
memory: 4g # Memory limit
cpus: "2" # CPU limit
firewall:
allowed_domains: # Whitelisted domains
- github.com
- pypi.org
- api.anthropic.com
# Add your domains here
sync:
additional_folders: # Folders to copy as siblings
- ~/Documents/Code/mcp-servers
- ~/Documents/Code/helpers
compress: true # Set to false for faster copying of large projects
github:
enabled: false # Enable GitHub CLI (gh) integration
config_path: ~/.maestro/gh # Path to gh config directory
daemon:
check_interval: 30m # How often to check containers
show_nag: true # Show reminder to start daemon
token_refresh:
enabled: true # Auto-refresh expiring tokens
threshold: 6h # Refresh when < 6h remaining
notifications:
enabled: true # Send desktop notifications
attention_threshold: 5m # Wait 5m before notifying
notify_on:
- attention_needed # Notify when container needs attention
- token_expiring # Notify when token < 1h
quiet_hours:
start: "23:00" # Optional: quiet hours start (24h format)
end: "08:00" # Optional: quiet hours end- show_nag: Set to
falseto disable the "start daemon" reminder inmaestro list - check_interval: How often the daemon checks containers (e.g., "30m", "1h", "15m")
- attention_threshold: How long to wait before sending notification (prevents spam)
- quiet_hours: Optional. Leave empty (
"") to disable quiet hours - Time formats: Use Go duration format ("30m", "6h") or 24-hour time ("23:00")
# Quick task description
maestro new "implement OAuth authentication"
# From a specification file
maestro new -f specs/feature-design.md
# Interactive mode
maestro newThis will:
- Use Claude to generate an appropriate branch name
- Create a new container with incremented numbering (e.g.,
maestro-feat-oauth-1) - Copy your entire project into the container
- Create and checkout the new git branch
- Start tmux with Claude in planning mode
- Connect you to the container
# List all containers with status indicators
maestro list # or: maestro ls, maestro ps
# Connect to a container
maestro connect feat-oauth-1
# Restart a crashed Claude process (preserves container state)
maestro restart feat-oauth-1
# Full container restart (if needed)
maestro restart feat-oauth-1 --full
# Stop a specific container
maestro stop feat-oauth-1
# Stop all dormant containers (where Claude has exited)
maestro stop
# Clean up stopped containers and their volumes
maestro cleanup
# Remove all containers (including running) and their volumes
maestro cleanup --all
# Clean up orphaned volumes (volumes without containers)
maestro cleanup-volumesThe maestro list command shows comprehensive status:
NAME STATUS BRANCH GIT ACTIVITY AUTH
---- ------ ------ --- -------- ----
feat-oauth-1 running feat/oauth Δ79 ↑2 2m ago ✓ 147.2h 🔔
fix-api-bug-1 running fix/api-bug ✓ 5m ago ⚠ 2.3h
refactor-db-1 running refactor/db Δ5 ↓1 12h ago ✗ EXPIRED 💤
Status Indicators:
- GIT:
Δ79= 79 changed files↑2= 2 commits ahead of remote↓1= 1 commit behind remote✓= clean working tree
- AUTH:
✓ Xh= Token valid for X hours (green)⚠ Xh= Token expires in < 24 hours (yellow warning)✗ EXPIRED= Token has expired (red)
- 🔔: Container needs attention (Claude is idle, waiting for input)
- 💤: Container is dormant (Claude process has exited)
When connected to a container via maestro connect:
- Window 0: Claude Code running in auto-approve mode
- Window 1: Shell for manual commands
- Switch windows:
Ctrl+b 0(Claude) orCtrl+b 1(shell) - Detach:
Ctrl+b d(returns you to host, container keeps running)
The tmux status line shows:
- Container name
- Current git branch
- Bell indicator when Claude needs attention
Maestro includes a background daemon that monitors your containers for token expiry and attention needs.
# Start the daemon (runs in background)
maestro daemon start
# Check daemon status
maestro daemon status
# View daemon logs
maestro daemon logs
# Stop the daemon
maestro daemon stopToken Monitoring: Automatically checks token expiration and warns when tokens are expiring (< 1 hour remaining). Future versions will support automatic token refresh.
Smart Notifications: Only notifies after containers have needed attention for a configurable threshold (default 5 minutes), preventing notification spam.
Quiet Hours: Configure time ranges when notifications should be suppressed (e.g., 23:00-08:00).
Activity Tracking: Monitors container activity and Claude process health.
Custom Notification Icons: On macOS, install terminal-notifier for custom icon support:
brew install terminal-notifierWithout terminal-notifier, notifications still work via macOS's built-in osascript, but will use the Terminal/iTerm icon.
The daemon behavior is controlled by the daemon section in ~/.maestro/config.yml:
- check_interval: How frequently to check containers (default: 30m)
- show_nag: Show reminder in
maestro listif daemon isn't running (default: true) - notifications.enabled: Enable/disable desktop notifications (default: true)
- notifications.attention_threshold: Wait time before notifying (default: 5m)
- notifications.quiet_hours: Optional time range to suppress notifications
Claude authentication tokens automatically expire after approximately 1 week. Maestro provides comprehensive tools to manage token expiration.
The maestro list command shows authentication status for each running container:
maestro listOutput example:
NAME STATUS BRANCH AUTH STATUS ATTENTION
---- ------ ------ ----------- ---------
feat-oauth-1 running feat/oauth ✓ 147.2h
fix-api-bug-1 running fix/api-bug ⚠ 2.3h
refactor-db-1 running refactor/db ✗ EXPIRED 💤 DORMANT
Claude CLI automatically refreshes tokens when actively used in a container. Use maestro refresh-tokens to find and propagate the freshest token:
maestro refresh-tokensThis command:
- Scans all running containers and the host for credentials
- Finds the container with the freshest token (Claude auto-refreshes during normal use)
- Copies the fresh token to all other containers and the host
- Ensures new containers will use the fresh token
Example output:
Scanning for credentials...
✓ Host: EXPIRED 2.8h ago
✓ maestro-feat-oauth-1: Valid for 147.2h
✓ maestro-fix-api-bug-1: EXPIRED 2.8h ago
✓ Found fresh token in maestro-feat-oauth-1
Expires: Sat, 18 Oct 2025 06:33:27 PDT
Status: Valid for 147.2h
Syncing credentials...
✓ Synced to host
✓ Synced to maestro-fix-api-bug-1
✅ Refresh complete! Synced to 2 location(s).
If all tokens are expired, maestro refresh-tokens will prompt you to run maestro auth:
maestro authThis will:
- Start a temporary authentication container
- Complete OAuth flow in your browser
- Automatically sync new credentials to all running containers
When creating a new container, Maestro will warn you if tokens are expired or expiring soon:
maestro new "implement feature"
⚠️ WARNING: Authentication token is EXPIRED!
Status: EXPIRED 2.8h ago
Run 'maestro auth' or 'maestro refresh-tokens' to get a fresh token.
Continue creating container with expired token? (y/N):- Check token status regularly: Run
maestro listto see auth status for all containers - Use
refresh-tokensfirst: If you see expired tokens, trymaestro refresh-tokensbefore runningmaestro auth(it's faster and reuses existing fresh tokens) - Run
authwhen needed: Only runmaestro authif all tokens are expired orrefresh-tokensfails - Monitor expiration warnings: If you see "⚠" warnings in
maestro list, consider refreshing tokens soon
Containers include a firewall that restricts network access to whitelisted domains only.
# Add a domain temporarily to a running container
maestro add-domain feat-oauth-1 api.example.com
# The tool will offer to add it to ~/.maestro/config.yml for permanent accessEdit ~/.maestro/config.yml to manage the domain whitelist:
firewall:
allowed_domains:
- github.com
- pypi.org
- api.anthropic.com
- your-domain.comContainers can access:
- Whitelisted domains from config
- GitHub API endpoints (auto-detected from git remotes)
- Local Docker network
- DNS resolution (port 53)
/workspace/ # Your main project (copied from host)
/workspace/../mcp-servers/ # Additional folders (from config)
/home/node/.claude/ # Claude config (mounted read-only)
.credentials.json # Shared OAuth credentials
.claude.json # Container-specific state
Each container has named volumes for:
- npm cache (
<container>-npm): Speeds up Node.js package installation - UV cache (
<container>-uv): Speeds up Python package installation - Command history (
<container>-history): Preserves bash/zsh history
These volumes persist across container restarts but are removed with maestro cleanup.
Host (macOS): Credentials stored in keychain + ~/.maestro/.claude/.credentials.json
Containers (Linux): File-based authentication only. Each container:
- Mounts
~/.maestro/.claude/read-only - Copies
.credentials.jsonto container-specific location - Generates its own
.claude.jsonstate file
This ensures:
- Single OAuth flow on the host
- Complete isolation between containers
- No credential conflicts
Containers launch with NET_ADMIN capability to manage iptables rules:
- Initialization:
init-firewall.shruns at container startup - Custom chain: Sets up iptables firewall rules
- Default policy: DROP all outgoing traffic
- Whitelist: Allow configured domains + GitHub API
- Dynamic updates:
maestro add-domainmodifies running containers
Check Docker logs:
docker logs maestro-feat-name-1Common issues:
- Docker daemon not running
- Insufficient resources (memory/CPU)
- Port conflicts
Add it temporarily:
maestro add-domain container-name api.example.comThen add to ~/.maestro/config.yml for permanent access.
Ensure it's running:
docker ps
docker start <container-name>
maestro connect <container-name>Check authentication status:
maestro list # Shows auth status
maestro refresh-tokens # Sync fresh tokens
maestro auth # Re-authenticate if neededVerify credentials exist:
ls -la ~/.maestro/.claude/.credentials.jsonOn macOS, install terminal-notifier for better notifications:
brew install terminal-notifierCheck daemon is running:
maestro daemon statusCheck notification settings in ~/.maestro/config.yml:
daemon:
notifications:
enabled: trueClaude tokens expire after ~1 week. Best practices:
- Start the daemon:
maestro daemon start- monitors and warns about expiration - Use refresh-tokens regularly:
maestro refresh-tokenssyncs fresh tokens from active containers - Re-authenticate when needed:
maestro authwhen all tokens expire
To modify the maestro binary:
# Make changes to Go files
# Run tests
make test
# Rebuild binary
make build
# Test changes
./bin/maestro --help
# Install updated binary
make installTo modify the container environment:
# Edit docker/Dockerfile
# Rebuild image
make docker
# Or rebuild everything
make allmaestro/
├── cmd/ # Cobra commands
│ ├── new.go # Container creation
│ ├── list.go # Status display
│ ├── connect.go # Container connection
│ ├── auth.go # Authentication
│ ├── daemon.go # Background daemon
│ └── ...
├── pkg/ # Internal packages
│ ├── container/ # Container operations
│ ├── daemon/ # Daemon implementation
│ ├── tui/ # Terminal UI components
│ ├── version/ # Version management
│ └── paths/ # Path utilities
├── docker/ # Container images
│ ├── Dockerfile # Main container image
│ └── signing/ # Code signing tools
├── scripts/ # Build and release scripts
└── Makefile # Build automation
Run the test suite:
make testTest specific packages:
go test ./pkg/version/
go test ./pkg/paths/Maestro uses GoReleaser for automated releases:
# Create a new release
make release VERSION=v1.2.3
# Test release build without publishing
make release-snapshotThe release process:
- Runs preflight checks (git status, credentials, etc.)
- Builds binaries for all platforms (Linux, macOS, Windows)
- Signs macOS and Windows binaries
- Creates GitHub release with changelog
- Uploads binaries and checksums
The numbering system (-1, -2, etc.) lets you create multiple implementations:
maestro new "implement auth with OAuth" # Creates maestro-feat-auth-oauth-1
maestro new "implement auth with JWT" # Creates maestro-feat-auth-jwt-1
maestro new "implement auth with OAuth" # Creates maestro-feat-auth-oauth-2Use maestro list frequently to:
- Check which containers need attention (🔔)
- Monitor token expiration
- See git status at a glance
- Identify dormant containers (💤)
Clean up dormant containers quickly:
maestro stop # Stops all dormant containersStart the daemon: Run maestro daemon start for automatic monitoring and notifications.
Use refresh-tokens: Before running maestro auth, try maestro refresh-tokens to reuse fresh tokens from active containers.
Clean up regularly: Run maestro cleanup to remove stopped containers and free disk space.
When you run maestro auth, you'll be prompted to set up GitHub CLI. This enables features like:
gh pr review 123gh issue listgh repo view
To enable GitHub CLI in containers, set in ~/.maestro/config.yml:
github:
enabled: true
config_path: ~/.maestro/gh # Managed by maestro authContainers are firewalled by default. Only whitelisted domains are accessible. This prevents:
- Accidental data exfiltration
- Unauthorized API access
- Network scanning from containers
- Credentials stored in
~/.maestro/.claude/ - Mounted read-only in containers
- Each container has isolated state
- GitHub CLI integration is opt-in
Containers run with minimal privileges except:
NET_ADMINcapability (required for iptables/firewall)- Access to Docker socket (not mounted by default)
- GitHub Issues: https://github.com/uprockcom/maestro/issues
- Documentation: This guide and the main README.md
Apache 2.0 - See LICENSE file for details.