{"id":45919191,"url":"https://github.com/deevus/pixels","last_synced_at":"2026-03-05T13:01:45.195Z","repository":{"id":340977354,"uuid":"1168355951","full_name":"deevus/pixels","owner":"deevus","description":"Disposable Linux containers for AI coding agents, with extensible backends","archived":false,"fork":false,"pushed_at":"2026-03-02T23:13:52.000Z","size":299,"stargazers_count":45,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-03-04T16:37:51.295Z","etag":null,"topics":["ai-agents","cli","containers","devtools","go","incus","linux","sandboxing","truenas","zfs"],"latest_commit_sha":null,"homepage":null,"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/deevus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","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-02-27T09:43:25.000Z","updated_at":"2026-03-04T06:09:03.000Z","dependencies_parsed_at":"2026-03-02T10:00:58.741Z","dependency_job_id":null,"html_url":"https://github.com/deevus/pixels","commit_stats":null,"previous_names":["deevus/pixels"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/deevus/pixels","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deevus%2Fpixels","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deevus%2Fpixels/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deevus%2Fpixels/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deevus%2Fpixels/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/deevus","download_url":"https://codeload.github.com/deevus/pixels/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deevus%2Fpixels/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30127201,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-05T12:40:50.676Z","status":"ssl_error","status_checked_at":"2026-03-05T12:39:32.209Z","response_time":93,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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-agents","cli","containers","devtools","go","incus","linux","sandboxing","truenas","zfs"],"created_at":"2026-02-28T08:17:32.268Z","updated_at":"2026-03-05T13:01:45.159Z","avatar_url":"https://github.com/deevus.png","language":"Go","readme":"# pixels\n\nDisposable Linux containers for AI coding agents, powered by TrueNAS and Incus.\n\nSpin up sandboxed Linux containers pre-loaded with AI coding tools (Claude Code, Codex, OpenCode via mise). Each container gets SSH access, ZFS snapshot-based checkpoints, and network egress policies that control what the agent can reach. Managed entirely from the CLI over TrueNAS WebSocket API.\n\n## Features\n\n- **Container lifecycle** -- create, start, stop, destroy, and list Incus containers\n- **SSH access** -- interactive console and remote command execution\n- **ZFS checkpoints** -- snapshot, restore, delete, and clone containers from checkpoints\n- **AI agent provisioning** -- automatically installs mise, Claude Code, Codex, and OpenCode\n- **Network egress policies** -- restrict outbound traffic to AI APIs, package registries, and Git (or a custom allowlist)\n- **Configuration** -- TOML config file, `PIXELS_*` environment variables, and CLI flags\n- **Network accessible** -- each container gets its own IP, reachable from the host for running and accessing services\n- **Local caching** -- disk cache avoids WebSocket round-trips for console/exec\n\n## Prerequisites\n\n- [TrueNAS SCALE](https://www.truenas.com/truenas-scale/) with Incus virtualization enabled\n- TrueNAS API key (create one in the TrueNAS web UI under Credentials \u003e API Keys)\n- Go 1.25+ (for building from source)\n- SSH key pair (defaults to `~/.ssh/id_ed25519`)\n\n## Installation\n\n```bash\ngo install github.com/deevus/pixels@latest\n```\n\nOr build from source:\n\n```bash\ngit clone https://github.com/deevus/pixels.git\ncd pixels\ngo build\n```\n\n## Quick Start\n\n```bash\n# Create a base container with agent egress restrictions\npixels create base --egress agent --console\n\n# Set up your environment, install dependencies, etc.\n# Then save a checkpoint\npixels checkpoint create base --label ready\n\n# Spin up new containers from the checkpoint\npixels create task1 --from base:ready\npixels create task2 --from base:ready\n\n# Or clone from a container's current state\npixels create task3 --from base\n\n# Tear down when done\npixels destroy task1\npixels destroy task2\n```\n\n## Commands\n\n| Command | Description |\n|---------|-------------|\n| `pixels create \u003cname\u003e` | Create a new container |\n| `pixels start \u003cname\u003e` | Start a stopped container |\n| `pixels stop \u003cname\u003e` | Stop a running container |\n| `pixels destroy \u003cname\u003e` | Permanently destroy a container and all its checkpoints |\n| `pixels list` | List all containers with status and IP |\n| `pixels console \u003cname\u003e` | Open an interactive SSH session |\n| `pixels exec \u003cname\u003e -- \u003ccommand...\u003e` | Run a command via SSH |\n| `pixels checkpoint create \u003cname\u003e` | Create a ZFS snapshot |\n| `pixels checkpoint list \u003cname\u003e` | List checkpoints with sizes |\n| `pixels checkpoint restore \u003cname\u003e \u003clabel\u003e` | Restore to a checkpoint |\n| `pixels checkpoint delete \u003cname\u003e \u003clabel\u003e` | Delete a checkpoint |\n| `pixels network show \u003cname\u003e` | Show current egress rules |\n| `pixels network set \u003cname\u003e \u003cmode\u003e` | Set egress mode |\n| `pixels network allow \u003cname\u003e \u003cdomain\u003e` | Add a domain to the allowlist |\n| `pixels network deny \u003cname\u003e \u003cdomain\u003e` | Remove a domain from the allowlist |\n\nGlobal flags: `--host`, `--api-key`, `-u/--username`, `-v/--verbose`\n\n## Container Lifecycle\n\n```bash\n# Create with custom resources\npixels create mybox --image ubuntu/24.04 --cpu 4 --memory 4096\n\n# Create with agent sandbox and open console when ready\npixels create mybox --egress agent --console\n\n# Skip all provisioning (no SSH keys, devtools, or egress setup)\npixels create mybox --no-provision\n\n# Clone from an existing container's checkpoint\npixels create newbox --from mybox:ready\n\n# Clone from an existing container's current state\npixels create newbox --from mybox\n```\n\nAll containers are prefixed `px-` internally. Commands accept bare names (e.g., `mybox` becomes `px-mybox`).\n\n## SSH Access\n\n**Console** opens an interactive SSH session. If the container is stopped, it starts it automatically:\n\n```bash\npixels console mybox\n```\n\n**Exec** runs a command and returns its exit code:\n\n```bash\npixels exec mybox -- ls -la /home/pixel\n```\n\nBoth commands check the local cache first for the container's IP, falling back to the TrueNAS API. SSH key auth is verified on connect -- if it fails, the current machine's public key is automatically written to the container.\n\n## Checkpoints\n\nCheckpoints are ZFS snapshots of the container's root filesystem.\n\n```bash\n# Create with auto-generated label\npixels checkpoint create mybox\n\n# Create with a custom label\npixels checkpoint create mybox --label ready\n\n# List checkpoints\npixels checkpoint list mybox\n# LABEL       SIZE\n# ready       42.0 MiB\n\n# Restore (stops container, rolls back, restarts)\npixels checkpoint restore mybox ready\n\n# Delete\npixels checkpoint delete mybox ready\n```\n\nClone a new container from a checkpoint to get identical copies:\n\n```bash\npixels create worker1 --from mybox:ready\npixels create worker2 --from mybox:ready\n```\n\nThe `checkpoint` command can also be abbreviated as `cp`.\n\n## Agent Provisioning\n\nBy default, new containers are provisioned with:\n\n- SSH public key injection (root + `pixel` user)\n- DNS configuration via systemd-resolved\n- Environment variables from config written to `/etc/environment`\n- **Dev tools**: mise, Node.js LTS, Claude Code, Codex, and OpenCode (installed via a background systemd service)\n\nDev tools install asynchronously after container creation. Use `--console` to wait for them to finish before dropping into a shell, or monitor progress with:\n\n```bash\npixels exec mybox -- sudo journalctl -fu pixels-devtools\n```\n\nDisable provisioning entirely with `--no-provision`, or just dev tools via config:\n\n```toml\n[provision]\ndevtools = false\n```\n\n## Network Egress\n\nControl outbound network access with three modes:\n\n| Mode | Description |\n|------|-------------|\n| `unrestricted` | No filtering (default) |\n| `agent` | Preset allowlist: AI APIs, package registries, Git/GitHub, Ubuntu repos, plus any custom domains |\n| `allowlist` | Custom domain list only |\n\n### Setting Egress at Creation\n\n```bash\npixels create mybox --egress agent\n```\n\n### Changing Egress on a Running Container\n\n```bash\n# Switch to agent mode\npixels network set mybox agent\n\n# Switch to unrestricted\npixels network set mybox unrestricted\n\n# Show current rules\npixels network show mybox\n```\n\n### Managing the Allowlist\n\n```bash\n# Add a domain\npixels network allow mybox api.example.com\n\n# Remove a domain\npixels network deny mybox api.example.com\n```\n\nThe `agent` preset includes domains for Anthropic, OpenAI, Google AI, npm, PyPI, crates.io, Go proxy, GitHub (including release CDN), mise, Node.js, and Ubuntu package repos. CIDR ranges are included for Google and GitHub/Azure CDN IPs.\n\nEgress is enforced via nftables rules inside the container with restricted sudo access. See [SECURITY.md](SECURITY.md) for known limitations and mitigations.\n\n## Configuration\n\nCreate `~/.config/pixels/config.toml`:\n\n```toml\n[truenas]\nhost = \"truenas.local\"\n# api_key: prefer PIXELS_TRUENAS_API_KEY env var over storing here\n# username = \"root\"           # default\n# insecure_skip_verify = false # default; set true for self-signed certs\n\n[defaults]\n# image = \"ubuntu/24.04\"     # default\n# cpu = \"2\"                  # default\n# memory = 2048              # MiB, default\n# pool = \"tank\"              # discovered from server; override if needed\n# dns = [\"1.1.1.1\"]          # optional; nameservers to inject into containers\n\n[ssh]\n# user = \"pixel\"             # default\n# key = \"~/.ssh/id_ed25519\"  # default\n\n[provision]\n# enabled = true             # default\n# devtools = true            # default\n\n[network]\n# egress = \"unrestricted\"    # default\n# allow = [\"api.example.com\"]  # additional domains for agent/allowlist modes\n\n[env]\n# ANTHROPIC_API_KEY = \"sk-ant-...\"\n# OPENAI_API_KEY = \"sk-...\"\n```\n\n### Priority Order\n\n1. TOML config file (`~/.config/pixels/config.toml`)\n2. Environment variables (`PIXELS_TRUENAS_HOST`, `PIXELS_TRUENAS_API_KEY`, etc.)\n3. CLI flags (`--host`, `--api-key`, `-u`)\n\n### Environment Variables\n\n| Variable | Config key |\n|----------|-----------|\n| `PIXELS_TRUENAS_HOST` | `truenas.host` |\n| `PIXELS_TRUENAS_USERNAME` | `truenas.username` |\n| `PIXELS_TRUENAS_API_KEY` | `truenas.api_key` |\n| `PIXELS_TRUENAS_PORT` | `truenas.port` |\n| `PIXELS_TRUENAS_INSECURE` | `truenas.insecure_skip_verify` |\n| `PIXELS_DEFAULT_IMAGE` | `defaults.image` |\n| `PIXELS_DEFAULT_CPU` | `defaults.cpu` |\n| `PIXELS_DEFAULT_MEMORY` | `defaults.memory` |\n| `PIXELS_DEFAULT_POOL` | `defaults.pool` |\n| `PIXELS_SSH_USER` | `ssh.user` |\n| `PIXELS_SSH_KEY` | `ssh.key` |\n| `PIXELS_CHECKPOINT_DATASET_PREFIX` | `checkpoint.dataset_prefix` |\n| `PIXELS_PROVISION_ENABLED` | `provision.enabled` |\n| `PIXELS_PROVISION_DEVTOOLS` | `provision.devtools` |\n| `PIXELS_NETWORK_EGRESS` | `network.egress` |\n\n## Security\n\nContainer egress filtering uses nftables rules inside the container. A root process with `cap_net_admin` could bypass these rules. The `pixel` user has restricted sudo that only permits safe-apt, dpkg-query, systemctl, journalctl, and nft list.\n\nSee [SECURITY.md](SECURITY.md) for the full threat model, known issues, and mitigations.\n\n## License\n\n[MIT](LICENSE)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeevus%2Fpixels","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdeevus%2Fpixels","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeevus%2Fpixels/lists"}