Image Management - mensfeld/code-on-incus GitHub Wiki
Advanced image operations for creating and managing custom COI images.
List Images
# List COI images
coi image list
# List all local images
coi image list --all
# Filter by prefix
coi image list --prefix claudeyard-
# JSON output
coi image list --format json
Publish Containers as Images
Convert a container into a reusable image:
# Publish container as image
coi image publish my-container my-custom-image
# With description
coi image publish my-container my-custom-image --description "Custom build with Python 3.11"
# Skip compression for faster publishing
coi image publish my-container my-custom-image --compression none
# Create image from container with installed tools
coi image publish coi-workspace-1 coi-rust --description "COI with Rust toolchain"
Delete Images
# Delete specific image
coi image delete my-custom-image
# Delete old image
coi image delete my-old-image
Check Image Existence
# Check if image exists
coi image exists coi-default
# Use in scripts
if coi image exists my-custom-image; then
echo "Image exists"
fi
Clean Up Old Versions
# Keep only 3 most recent versions, delete older ones
coi image cleanup claudeyard-node-42- --keep 3
# Clean up all old images (keep latest only)
coi image cleanup my-project- --keep 1
Creating Custom Images
Workflow 1: Install Tools in Container
# Start a session and install tools
coi shell --persistent
# Inside container: install your tools
sudo apt update
sudo apt install -y rust-all python3.11 golang
cargo install ripgrep
exit
# Publish the container as an image
coi image publish coi-workspace-1 coi-dev-full
# Use the custom image
coi shell --image coi-dev-full
Workflow 2: Profile with Build Script
Create a profile directory with a [container.build] section:
coi profile create my-custom --image my-custom-image
Edit ~/.coi/profiles/my-custom/config.toml:
[container]
image = "my-custom-image"
[container.build]
base = "coi-default"
script = "build.sh" # resolved relative to this config.toml
Create ~/.coi/profiles/my-custom/build.sh:
#!/bin/bash
apt update
apt install -y your-tools
pip install your-packages
Build and use:
coi build --profile my-custom
coi shell --profile my-custom
Use Cases
Team Images
Create standardized images for your team:
# Create team image with specific tools
coi shell --persistent
# Install team tools...
exit
coi image publish coi-workspace-1 team-nodejs-2024
# Team members use it
coi shell --image team-nodejs-2024
Project-Specific Images
# Create image per project with dependencies pre-installed
coi image publish project-container myapp-v1.0
Version Management
# Keep multiple versions
coi image publish coi-workspace-1 myproject-v1.0
coi image publish coi-workspace-1 myproject-v1.1
# Clean up old versions, keep last 3
coi image cleanup myproject- --keep 3
Image Compression
By default, Incus compresses images with gzip when publishing. Use --compression to control the algorithm:
# Skip compression entirely (fastest, larger images — good for iteration)
coi build --compression none
coi image publish my-container my-image --compression none
# Use xz for high compression ratio (slowest, smallest images — good for distribution)
coi build --compression xz
Available values: none, gzip (default), xz, or any algorithm supported by Incus. The value is passed directly to incus publish --compression.
Build Configuration in Project Config
You can define how to build custom images directly in .coi/config.toml using the [container.build] section:
# .coi/config.toml
[container]
image = "coi-myproject"
[container.build]
base = "coi-default" # Base image (default: "coi-default")
script = "build.sh" # Path to build script (relative to config file)
# commands = ["apt-get update", "apt-get install -y rustup"] # Or inline commands
When container.image is set to a custom name and [container.build] is configured:
coi buildbuilds the custom image automaticallycoi shellandcoi runauto-detect missing images and trigger the build before launching
Script vs commands: If both script and commands are set, script takes precedence. Script paths are resolved relative to the config file location.
See also Profiles — Build Scripts for per-profile build configuration.
Pre-installed Runtime Manager (mise)
The base coi-default image includes mise — a polyglot runtime manager for installing and managing language runtimes. The following are pre-installed:
| Tool | Notes |
|---|---|
| Python 3 | python3, pip, venv |
| pnpm | Fast Node.js package manager |
| TypeScript | tsc compiler |
| tsx | TypeScript execution without compilation |
Install additional runtimes inside your container or build script:
mise use --global go@latest # Install Go
mise use --global ruby@3 # Install Ruby
mise use node@22 # Install Node.js 22 (per-project)
Create a .mise.toml in your project root to pin runtime versions per-project. mise is activated in all shell sessions (interactive and non-interactive), so tools are available to AI agents automatically.
Note: System Node.js (v20 LTS) is retained for Claude CLI and core tooling alongside mise-managed runtimes.
Notes
- Images are stored locally in Incus
- Publishing an image captures the complete container state
- Custom images can be used with
--imageflag - Image cleanup helps manage disk space
- Use descriptive names and versions for easy identification