This guide explains how ContainAI manages container lifecycle: creation, starting, stopping, and destruction.
ContainAI containers are designed to be persistent workspaces for AI coding agents. Unlike traditional ephemeral containers, they maintain state across sessions through data volumes and are identified by workspace-derived names.
%%{init: {'theme': 'base', 'themeVariables': {
'primaryColor': '#1a1a2e',
'primaryTextColor': '#ffffff',
'primaryBorderColor': '#16213e',
'secondaryColor': '#0f3460',
'tertiaryColor': '#1a1a2e',
'lineColor': '#a0a0a0',
'textColor': '#ffffff',
'background': '#0d1117'
}}}%%
stateDiagram-v2
[*] --> Running: cai run (first use)
Running --> Running: cai run (attach)
Running --> Stopped: cai stop
Stopped --> Running: cai run
Stopped --> [*]: cai stop --remove
Running --> [*]: cai stop --remove
note right of Running: Agent sessions attach via SSH
note right of Stopped: Volume preserved
Containers are created automatically when you first run cai run or cai for a workspace.
Container names are derived from your workspace:
- Format:
{repo}-{branch_leaf}(max 24 characters) - Branch leaf: Last segment of a branch path (e.g.,
feature/oauthbecomesoauth) - Deterministic: Same repo and branch always produces the same container name
# In a git repo on branch "feature/auth"
cd ~/projects/myapp
cai # Creates container: myapp-auth
ContainAI containers are labeled for identification and management:
| Label | Description |
|---|---|
containai.managed=true |
Identifies ContainAI-managed containers |
containai.workspace |
Original workspace path |
containai.ssh-port |
Assigned SSH port for container |
containai.data-volume |
Associated data volume name |
ai.containai.template |
Template used for container build |
Planned: A
containai.keep=truelabel will be supported in a future release to protect containers from garbage collection.
- Context selection: ContainAI selects the appropriate Docker context (e.g.,
containai-dockerfor Sysbox isolation) - Image resolution: Resolves the container image based on agent and template
- Volume setup: Creates or attaches the data volume for persistent storage
- Container creation: Runs
docker run -dto create and start the container with appropriate mounts and labels - SSH configuration: Sets up SSH access for agent sessions
Note: Containers go directly to "running" state on first use (create+start in one step).
Containers start automatically when accessed. ContainAI handles the transition from stopped to running state transparently.
When you run cai or cai run:
- If container exists and is stopped, it starts automatically
- If container is already running, a new session attaches
- SSH setup is verified on every start
ContainAI verifies container health on start:
- Systemd services are running (systemd is PID 1)
- SSH daemon is accessible
- Required ports are available
ContainAI provides commands to back up and restore your container data.
Use cai export to create a backup archive of your data volume:
# Export data volume to archive
cai export
# Export to specific file
cai export --output ~/backups/my-backup.tgz
# Export specific container's data
cai export --container myapp-main
The export creates a .tgz archive containing agent credentials, configuration, and other persistent data from the data volume.
Planned: A
cai stop --exportflag will be added in a future release to automatically export data before stopping the container.
Use cai import to restore or sync configurations into the data volume:
# Import from host home directory (default)
cai import
# Import from specific directory
cai import --from ~/my-configs
The import syncs host configurations (git config, shell aliases, etc.) into the container's data volume.
Use cai stop to stop containers. Stopping preserves the container and its data volume.
# Stop container for current workspace
cai stop
# Stop specific container
cai stop --container myapp-main
# Stop all ContainAI containers
cai stop --all
When stopping a container with active sessions, ContainAI warns you:
[WARN] Container 'myapp-main' may have active sessions
Stop anyway? [y/N]:
Session detection uses best-effort methods:
- SSH connections: Checks established connections on port 22
- Active terminals: Counts PTY devices in
/dev/pts/ - Unknown: If detection tools are unavailable, proceeds without warning
Use --force to skip the session warning prompt.
| Command | Effect |
|---|---|
cai stop |
Stops container (keeps container and volume) |
cai stop --remove |
Removes container (keeps volume) |
When removing containers, SSH configurations are automatically cleaned up.
Containers can be destroyed in several ways, with different effects on data.
# Remove specific container (volume preserved)
cai stop --remove --container myapp-main
# Remove all containers (volumes preserved)
cai stop --all --remove
# Recreate container with same volume
cai --fresh
# Equivalent alias
cai --restart
This removes and recreates the container while preserving the data volume. Useful after:
- Configuration changes
- Template updates
- Image updates
# Start fresh with new volume
cai --reset
This generates a new unique volume name, effectively starting from scratch. The old volume remains but is no longer referenced.
Data volumes persist independently of containers. This separation ensures your agent credentials, plugins, and configuration survive container recreation.
| Path | Purpose |
|---|---|
/mnt/agent-data |
Primary data mount in container |
~/.config/claude |
Claude agent configuration |
~/.config/gemini |
Gemini agent configuration |
| Agent credentials | OAuth tokens, API keys |
| Shell history | Command history |
| Custom configs | User-specific settings |
| Action | Container | Volume |
|---|---|---|
cai stop |
Stopped | Preserved |
cai stop --remove |
Removed | Preserved |
cai --fresh |
Recreated | Preserved |
cai --reset |
Recreated | New volume (old preserved) |
docker volume rm |
N/A | Deleted |
# Check workspace state for volume name
cai config get data_volume
# List volumes with inspect
docker volume ls
# Inspect container mounts
docker inspect <container> --format '{{range .Mounts}}{{.Name}}{{end}}'
Note: The
cai gccommand is planned for a future release. This section documents the intended behavior.
ContainAI will provide garbage collection to clean up stale resources.
The cai gc command will prune stopped containers based on age:
# Preview what would be removed
cai gc --dry-run
# Remove containers stopped more than 7 days ago
cai gc --age 7d
# Skip confirmation prompt
cai gc --force
Containers will be protected from GC if:
- Running: Active containers are never pruned
- Keep label: Containers with
containai.keep=truelabel will be protected (planned) - Managed only: Only
containai.managed=truecontainers are considered
For stopped containers (status=exited):
- Age is calculated from
.State.FinishedAttimestamp
For never-ran containers (status=created):
- Age is calculated from
.Createdtimestamp
With --images, GC will also prune unused ContainAI images:
cai gc --images
Only images matching these prefixes will be considered:
containai:*(local builds)ghcr.io/containai/*(official registry)
Images in use by any container (running or stopped) are never removed.
Until cai gc is implemented, you can manually clean up:
# Remove specific stopped container
cai stop --remove --container <name>
# Remove all ContainAI containers
cai stop --all --remove
# Remove unused images (Docker native)
docker image prune -f
Use cai status to inspect container state:
# Current workspace container
cai status
# Specific container
cai status --container myapp-main
# JSON output
cai status --json
Required fields (always available):
- Container name
- Status (running/stopped/created)
- Image name
Best-effort fields (5-second timeout):
- Uptime (for running containers)
- Session counts (SSH connections, active terminals)
- Resource usage (memory, CPU)
Example output:
Container: myapp-main
Status: running
Uptime: 3d 4h 12m
Image: containai:latest
Sessions (best-effort):
SSH connections: 2
Active terminals: 3
Resource Usage:
Memory: 1.2GB / 4.0GB (30%)
CPU: 5.2%
For the best experience, leave your container running:
- Faster subsequent connections (no startup delay)
- Background processes continue running
- Agent can perform long-running tasks
After changing templates or configuration:
cai --fresh
Periodically clean up stale resources:
# Remove all stopped ContainAI containers
cai stop --all --remove
# Once cai gc is available (planned):
# cai gc --dry-run
# cai gc --age 30d
For containers you want to keep indefinitely, labels must be set at creation time.
ContainAI will provide a --keep flag in a future release. For now, you can:
# Use --container flag to create with a specific name that's easy to identify
cai --container important-project
# Or simply avoid running cai gc on containers you want to keep
- Check Docker daemon:
docker info - Check Sysbox availability:
cai doctor - Review logs:
docker logs <container>
If session detection returns "unknown":
- The
ssutility may not be installed in the container - ContainAI will proceed without warning in this case
If the expected volume is missing:
- Check workspace state:
cai config get data_volume - List available volumes:
docker volume ls - Use
--resetto start fresh with a new volume
- Clean stale configs:
cai ssh cleanup - Check SSH key:
~/.config/containai/keys/ - View container logs:
docker logs <container>
- Quickstart Guide: Getting started with ContainAI
- Configuration Reference: Config options and workspace settings
- Troubleshooting: Common issues and solutions
- Security Model: Isolation and threat model