{"id":44922635,"url":"https://github.com/mensfeld/code-on-incus","last_synced_at":"2026-09-22T01:57:41.057Z","repository":{"id":331692443,"uuid":"1129585228","full_name":"mensfeld/code-on-incus","owner":"mensfeld","description":"Give each AI agent its own isolated machine with root, Docker, and systemd. Active defense detects and stops threats automatically.","archived":false,"fork":false,"pushed_at":"2026-09-15T18:55:39.000Z","size":9203,"stargazers_count":706,"open_issues_count":23,"forks_count":62,"subscribers_count":4,"default_branch":"master","last_synced_at":"2026-09-16T02:55:01.092Z","etag":null,"topics":["agentic-ai","ai-tools","anthropic","claude","claude-code","code-sandbox","codex","coding-assistant","container-security","containers","developer-tools","incus","llm-security","llm-tools","lxc","opencode","opencode-ai","sandbox","sandboxing-tool","security"],"latest_commit_sha":null,"homepage":"","language":"Go","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,"claude":null,"gemini":null,"cursor":null,"copilot":null,"dco":null,"cla":null,"disclosure":null}},"created_at":"2026-01-07T09:47:42.000Z","updated_at":"2026-09-15T18:55:43.000Z","dependencies_parsed_at":"2026-09-08T05:24:03.030Z","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":16,"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":341189360,"owners_count":37392327,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-08-22T15:14:58.755Z","status":"online","status_checked_at":"2026-09-17T02:00:07.197Z","response_time":111,"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":["agentic-ai","ai-tools","anthropic","claude","claude-code","code-sandbox","codex","coding-assistant","container-security","containers","developer-tools","incus","llm-security","llm-tools","lxc","opencode","opencode-ai","sandbox","sandboxing-tool","security"],"created_at":"2026-02-18T03:41:12.331Z","updated_at":"2026-09-17T13:44:37.995Z","avatar_url":"https://github.com/mensfeld.png","language":"Go","funding_links":[],"categories":["AI","Detailed Sandboxes Reference","Tools and Development Workflows","Sandboxing \u0026 Isolation","Security","Containers \u0026 gVisor"],"sub_categories":["Agents","Standalone / Self-Hosted Tools","Obsidian","What this ranking does not measure"],"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[![Join the chat at https://slack.karafka.io](https://raw.githubusercontent.com/karafka/misc/master/slack.svg)](https://slack.karafka.io)\n\n**Give every AI coding agent its own machine - with active defense.**\n\n`coi` runs your AI coding tool (Claude Code, Codex, opencode, pi, omp) inside its own isolated Linux system - a full-OS container with root access, systemd, Docker, and the freedom to install anything. The agent works like it would on a real server - but it can't touch your host, can't see your credentials, and if it does something dangerous, `coi` pauses or kills the container on its own.\n\nOne command drops you into a coding session. Your project is mounted, file permissions just work, and your SSH keys, tokens, and environment variables never enter the container unless you explicitly say so.\n\nBuilt by developers, for developers who run AI agents and want to know what those agents are doing. Not a product, not a startup - a tool that does the job.\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.youtube.com/watch?v=t78-JUnTK5Q\"\u003e\n    \u003cimg src=\"https://img.youtube.com/vi/t78-JUnTK5Q/maxresdefault.jpg\" alt=\"BetterStack video about Code on Incus\" width=\"600\"\u003e\n  \u003c/a\u003e\n  \u003cbr\u003e\n  \u003cem\u003eWatch the BetterStack video about Code on Incus\u003c/em\u003e\n\u003c/p\u003e\n\n![Demo](misc/demo.gif)\n\n## Get started in three commands\n\n```bash\n# 1. Install\ncurl -fsSL https://raw.githubusercontent.com/mensfeld/code-on-incus/master/install.sh | bash\n\n# 2. Build the base image (first time only, ~5-10 min)\ncoi build\n\n# 3. Start coding - from any project directory\ncd your-project\ncoi shell\n```\n\nThat's it. Your agent is now running in an isolated container with your project at `/workspace`, correct file ownership (no more `chown`), Docker and `gh` available inside, every workspace change saved back to the host - and **no** access to your host SSH keys, env vars, or credentials.\n\n\u003e Requires Linux with [Incus](https://linuxcontainers.org/incus/docs/main/installing/) (macOS works too, via Colima/Lima - see [macOS Setup](https://github.com/mensfeld/code-on-incus/wiki/macOS-Setup-Guide)).\n\n## Who it's for\n\n- You run AI coding agents and want them to have **full machine access** - root, Docker, package managers, services - without risking your host.\n- You want to **know when an agent does something suspicious**, not find out after the fact.\n- You run **multiple agents in parallel** and need them isolated from each other.\n- You want **persistent dev environments** that survive restarts, not throwaway containers that lose your setup every time.\n- You care about your **credentials never ending up** inside an agent-controlled environment.\n\n## What makes it different\n\n- **A real machine, not a locked box.** Incus *system* containers run a full OS with systemd and native Docker inside. Agents install packages, run services, use cron - exactly like a server, with none of Docker's permission hell (files come out correctly owned).\n\n- **Your credentials stay home.** SSH keys, `.env` files, Git tokens, and host environment variables are **never** exposed unless you explicitly mount them. Need to give an agent a secret? Forward a host socket or mint a short-lived token per session - the secret itself never enters the container.\n\n- **Active defense, not just a wall.** Kernel-level monitoring catches reverse shells, C2 connections, data exfiltration, DNS tunneling, and credential scanning in real time - and **auto-pauses on HIGH, auto-kills on CRITICAL**. No babysitting.\n\n- **Parallel agents, fully isolated.** Run several sessions on the same project at once; each slot gets its own home directory, so nothing leaks between them.\n\n- **Your work always survives.** Containers can be ephemeral (deleted on exit) or persistent (kept with installed packages) - either way, **workspace files and session history are always saved**. Resume any session later with full conversation history and credentials restored.\n\n### `coi` vs. the alternatives\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 / exfil response | Auto-kill / auto-pause | No | No |\n| Network isolation | nftables (3 modes) | Basic | No |\n| Supply-chain protection | Git hooks / IDE configs read-only | No | No |\n| Audit logging | JSONL forensics | No | No |\n| Runs on Linux natively | Yes | microVM only on macOS/Windows | - |\n\n## Profiles: your setups, one flag\n\nProfiles are the feature you'll reach for every day. A profile is a **reusable, named container setup** - image, tool, resource limits, mounts, network mode, build scripts, and AI-agent instructions bundled into one template you can apply with a single flag.\n\n```bash\ncoi shell --profile rust-dev        # spin up your Rust environment, ready to go\ncoi profile create rust-dev         # scaffold a new profile, then edit its config.toml\ncoi profile list                    # see what you've got\n```\n\nProfiles support **inheritance** (`inherits = \"parent\"`), ship AI-agent context files, and can carry their own build scripts - so \"my hardened Python box with these limits and these tools\" becomes one word.\n\n**The killer preset: `hardened`.** Opening a repo you don't trust? One flag gives you `coi`'s strongest lockdown - restricted network (no exfil path), workspace secret masking, an ephemeral container, **no SSH-agent forwarding**, and live threat monitoring with auto-pause/kill:\n\n```bash\ncoi shell --profile hardened        # inspect untrusted code safely\ncoi profile info hardened           # see exactly what it locks down\n```\n\nIt overrides a weaker global config (a global `mode = \"open\"` still becomes restricted) and needs zero setup. See the [Profiles wiki page](https://github.com/mensfeld/code-on-incus/wiki/Profiles) for the full reference and schema.\n\n## Supported AI tools\n\n**Claude Code** (default) · **Codex CLI** · **opencode** · **pi** · **omp** (Oh My Pi) - pick one in config or a profile:\n\n```toml\n# ~/.coi/config.toml or ./.coi/config.toml\n[tool]\nname = \"claude\"              # or \"codex\", \"opencode\", \"pi\", \"omp\"\npermission_mode = \"bypass\"   # run autonomously (\"bypass\") or ask first (\"interactive\")\n```\n\n**Switching tools on the same container.** Tool choice is config/profile-shaped, not a per-command flag. To re-enter one persistent container (same code, packages, and running services) with a different tool, give two profiles the **same `[container] session_name`** — a container's identity is `hash(workspace, session_name)`, so they resolve to the same box:\n\n```toml\n# ~/.coi/profiles/box-claude/config.toml        # ~/.coi/profiles/box-codex/config.toml\n[container]                                      # [container]\npersistent = true                                # persistent = true\nsession_name = \"box\"                             # session_name = \"box\"\n[tool]                                           # [tool]\nname = \"claude\"                                  # name = \"codex\"\n```\n```bash\ncoi shell --profile box-claude    # create/enter the \"box\" running claude\ncoi shell --profile box-codex     # re-enter the SAME box running codex\n```\n\nOn reuse, coi seeds the re-entering tool's credentials/config the first time that tool is used in the box (without disturbing the other tool's config or history). Session history is per-tool (`~/.coi/sessions-\u003ctool\u003e`), so `--resume`/`--continue` resume that tool's own conversations.\n\n_Aider and Cursor are on the way._ See the [Supported Tools wiki page](https://github.com/mensfeld/code-on-incus/wiki/Supported-Tools) for per-tool auth and configuration.\n\n## Everyday commands\n\n```bash\ncoi shell                 # interactive AI session (Claude Code by default)\ncoi run -- npm test       # run any command in the sandbox (streams output, propagates exit code)\ncoi run --prompt-name nightly   # fire-and-forget: run the agent headlessly from a predefined prompt\ncoi top                   # per-container CPU/memory/IO, resolved to workspace + alias\ncoi monitor               # real-time security dashboard\ncoi list --all            # active containers + saved sessions\ncoi attach                # attach to a running session\ncoi audit                 # stream the JSONL threat-event log (pipe into a SIEM or jq)\ncoi shutdown / coi kill   # stop or force-kill containers\ncoi clean                 # remove stopped containers and orphaned resources\n```\n\nDrop a `.coi/config.toml` in any repo to auto-configure `coi` for that project - teams share one image, network mode, and limits. Run `coi \u003ccommand\u003e --help` for any command.\n\n## Fire and forget: headless prompts + cron\n\n`coi run --prompt` runs the AI agent **headlessly** - it executes a prompt to completion, streams output, and exits with the agent's status code. No TTY, no interaction. That makes it a clean building block for automation: a **list of predefined prompts** + a **persistent setup** + your host's **cron**.\n\n```bash\ncoi run --prompt \"update dependencies, run the tests, and open a PR if green\"\ncoi run --prompt-file ./task.md --profile hardened\ncoi run --prompt-name nightly-maintenance          # from the [prompts] config table\n```\n\nDefine reusable prompts once, in your trusted config `~/.coi/config.toml` (or a profile under it):\n\n```toml\n[prompts]\nnightly-maintenance = \"Update dependencies, run the tests, and open a PR if green.\"\ntriage = { file = \"prompts/triage.md\" }            # long prompts can live in a file\n```\n\nThen schedule them with plain host cron - exit codes propagate, so failures show up in your logs:\n\n```cron\n# crontab -e   (runs on the host, which owns cron and drives coi)\n0 3 * * *    cd ~/project \u0026\u0026 coi run --prompt-name nightly-maintenance \u003e\u003e ~/coi-nightly.log 2\u003e\u00261\n*/30 * * * * cd ~/project \u0026\u0026 coi run --profile triage --prompt-name triage \u003e\u003e ~/coi-triage.log 2\u003e\u00261\n```\n\nEach fire is a fresh ephemeral session by default, and prompt mode currently supports the `claude` tool with `permission_mode = \"bypass\"` (a headless run has no TTY to approve tool use). **Prompts are honored only from trusted-scope config** (`~/.coi/config.toml` / `$COI_CONFIG`); a `[prompts]` table in an untrusted project `.coi/config.toml` (or a project-scoped profile) is ignored entirely - so a cloned repo can never define or redefine a prompt you invoke by name. This matches how `env_commands` and the default-profile selector are treated.\n\n## Documentation\n\nThe README is the pitch; the wiki is the manual. Everything below lives there in full:\n\n- **[Configuration](https://github.com/mensfeld/code-on-incus/wiki/Configuration)** - the complete config reference, precedence, and per-repo setup\n- **[Profiles](https://github.com/mensfeld/code-on-incus/wiki/Profiles)** - reusable setups, inheritance, and the JSON schema\n- **[Network Isolation](https://github.com/mensfeld/code-on-incus/wiki/Network-Isolation)** - restricted/allowlist/open modes, DNS pinning, egress and per-host port controls\n- **[Security Monitoring](https://github.com/mensfeld/code-on-incus/wiki/Security-Monitoring)** \u0026 **[Audit Log](https://github.com/mensfeld/code-on-incus/wiki/Audit-Log)** - threat detection, automated response, and the event format\n- **[Security Best Practices](https://github.com/mensfeld/code-on-incus/wiki/Security-Best-Practices)** - protected paths, the trust model, hardening\n- **[Container Lifecycle \u0026 Sessions](https://github.com/mensfeld/code-on-incus/wiki/Container-Lifecycle-and-Sessions)** - ephemeral vs. persistent, resume, aliases\n- **[Resource \u0026 Time Limits](https://github.com/mensfeld/code-on-incus/wiki/Resource-and-Time-Limits)** · **[Snapshot Management](https://github.com/mensfeld/code-on-incus/wiki/Snapshot-Management)** · **[Image Management](https://github.com/mensfeld/code-on-incus/wiki/Image-Management)**\n- **[File Transfer](https://github.com/mensfeld/code-on-incus/wiki/File-Transfer)** · **[Tmux Automation](https://github.com/mensfeld/code-on-incus/wiki/Tmux-Automation)** · **[Container Operations](https://github.com/mensfeld/code-on-incus/wiki/Container-Operations)**\n- **[System Health Check](https://github.com/mensfeld/code-on-incus/wiki/System-Health-Check)** - `coi health` diagnoses your setup end-to-end\n- **[Troubleshooting](https://github.com/mensfeld/code-on-incus/wiki/Troubleshooting)** · **[FAQ](https://github.com/mensfeld/code-on-incus/wiki/FAQ)** · **[Migration Guide](https://github.com/mensfeld/code-on-incus/wiki/Migration-Guide)**\n\n## Why Incus, not Docker?\n\nIncus (a modern LXD fork) gives you **system containers** - which behave like lightweight VMs (a real init system and full OS userspace) while sharing the host kernel, so they start in seconds - instead of Docker's application containers. That means one clean isolation layer running a full OS with native Docker inside, correct file ownership on the host by default, and no Docker Desktop, no vendor lock-in, no opaque VM nesting. It's Linux-native and fully open source. (More in the [FAQ](https://github.com/mensfeld/code-on-incus/wiki/FAQ).)\n\n## Getting help\n\n- **Slack**: [Join the COI community](https://slack.karafka.io) - ask questions, report issues, share feedback\n- **GitHub Issues**: [Open an issue](https://github.com/mensfeld/code-on-incus/issues) for bugs and feature requests\n- **Wiki**: [Browse the documentation](https://github.com/mensfeld/code-on-incus/wiki)\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"}