[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-83925":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":18,"stars90d":16,"forks30d":16,"starsTrendScore":19,"compositeScore":20,"rankGlobal":10,"rankLanguage":10,"license":21,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":22,"hasPages":22,"topics":24,"createdAt":10,"pushedAt":10,"updatedAt":35,"readmeContent":36,"aiSummary":10,"trendingCount":16,"starSnapshotCount":16,"syncStatus":37,"lastSyncTime":38,"discoverSource":39},83925,"sandboxd","tastyeffectco\u002Fsandboxd","tastyeffectco","Self-hosted dev sandboxes with preview URLs. One command. No Kubernetes, perfect for coding agents and Saas factories","https:\u002F\u002Fupilote.com",null,"Go",569,19,4,6,0,10,55,75,93.4,"MIT License",false,"main",[25,26,27,28,29,30,31,32,33,34],"ai","ai-agent","dev-environment","docker","isolation","pinokio","preview","preview-environment","sandbox","self-hosted","2026-06-12 04:01:42","\u003Ch1 align=\"center\">sandboxd\u003C\u002Fh1>\n\n\n\u003Cp align=\"center\">\n  \u003Cb>The open-source engine for AI app-builder products.\u003C\u002Fb>\u003Cbr\u002F>\n  Give every user an isolated cloud dev environment, a built-in coding agent,\n  and a live preview URL — self-hosted, on one machine, in one command.\n\u003C\u002Fp>\n\n\u003Cp align=\"center\">\n  \u003Ca href=\"LICENSE\">\u003Cimg alt=\"License: MIT\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-MIT-green.svg\">\u003C\u002Fa>\n  \u003Cimg alt=\"Runs on Docker\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fruns%20on-Docker-2496ED.svg\">\n  \u003Cimg alt=\"Single binary control plane\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fcontrol%20plane-single%20Go%20binary-00ADD8.svg\">\n  \u003Cimg alt=\"Status: beta\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fstatus-beta-yellow.svg\">\n\u003C\u002Fp>\n\n---\n\n\u003Cimg width=\"1100\" height=\"816\" alt=\"sandboxd-demo\" src=\"https:\u002F\u002Fgithub.com\u002Fuser-attachments\u002Fassets\u002Ff794ff9b-8ffe-47e8-bd30-22541f870f09\" \u002F>\n\n\n## What is sandboxd? (start here)\n\nThink of the apps where you type *\"build me a todo app\"* and seconds later a\nworking website appears at its own link — like Lovable, Bolt, v0, or Replit.\n**sandboxd is the open-source backend that makes that possible**, running on\nyour own server.\n\nHere's what it does, in plain terms. You send it one HTTP request, and it:\n\n1. **Creates a sandbox** — a private, isolated Linux container (its own\n   filesystem, its own memory limits), so one user's code can never see or\n   break another's.\n2. **Runs an AI coding agent inside it** — you give it a prompt, and it writes\n   the code into that sandbox. (The OpenCode and Claude Code CLIs come\n   pre-installed.)\n3. **Gives the app a live URL** — the dev server running inside the sandbox is\n   instantly reachable at a shareable preview link.\n\n```\nPOST \u002Fsandbox          → a private, isolated container spins up\nPOST ...\u002Ftasks         → an AI agent writes an app inside it\nhttp:\u002F\u002F\u003Cid>.preview... → that app is live at its own URL\n```\n\nIt's also cheap to run: a sandbox **goes to sleep when nobody's using it**\n(freeing memory) and **wakes up the instant someone opens its link again** —\nfiles are saved on disk the whole time. So one ordinary server can hold many\nusers instead of needing one virtual machine each.\n\nUnder the hood it's deliberately small and easy to understand: **one Go program\nthat tells Docker what to do**, with **Traefik** handling the URLs and\n**SQLite** as the database. No Kubernetes, no separate database server, no\nmessage queue — you could read the whole thing in an afternoon.\n\n```\n            ┌──────────────── your host (just needs Docker) ────────────────┐\n browser ──▶│  Traefik  ──▶  sandbox  (coding agent + dev server :3000)      │\n            │     ▲              ▲   ▲                                        │\n API\u002FCLI ──▶│  sandboxd ─────────┘   └─ workspace dir (persists)             │\n            │     │  SQLite (source of truth) · idle→stop · request→wake      │\n            └─────┴────────────────────────────────────────────────────────-─┘\n```\n\n### Who's it for?\n\n**✅ Use it if** you're running **many sandboxes for other people** — an AI\napp-builder (\"describe an app → see it live\"), an agent platform, a coding\nplayground, per-user or per-branch preview environments, or multi-app hosting\nfor a team.\n\n**❌ Skip it if** you just need one or two containers for yourself — a shell\nscript, `docker run`, or [lxd](https:\u002F\u002Fcanonical.com\u002Flxd) is simpler. (More on\nthat [below](#why-not-just-a-shell-script).)\n\n## Why sandboxd?\n\nIf you're building an **AI app-builder, an agent platform, a coding playground,\nor a per-user preview product**, the hard part isn't the prompt — it's the\ninfrastructure underneath it:\n\n- **Multi-tenant isolation** so one user's code can't touch another's.\n- **Per-user preview URLs** with automatic routing and TLS.\n- **Cost control** — idle environments must release memory, or your bill explodes.\n- **Agent orchestration** — run a coding agent against a workspace, stream its\n  progress, capture the result.\n- **Persistence, wake-on-demand, reconciliation after a crash or reboot.**\n\nThat's months of platform work. sandboxd is that platform, distilled to one\ncommand:\n\n- ⚡ **One-command install.** `.\u002Finstall.sh` and you have a working API + previews.\n- 🧠 **Agents included.** The OpenCode and Claude Code CLIs ship in every sandbox;\n  hand a sandbox a prompt and it builds.\n- 💸 **Dense by design.** Stop-on-idle + wake-on-request means dozens of sandboxes\n  share one box instead of one VM each — the difference between a $20 server and\n  a $2,000 cluster.\n- 🔓 **Yours.** Self-hosted, MIT-licensed, no vendor lock-in. Own your data, your\n  margins, and your roadmap.\n- 🪶 **Boring on purpose.** SQLite + the `docker` CLI + Traefik. A reconciler\n  converges Docker back to the database on every boot. You can read the whole\n  control plane in an afternoon.\n\n## \"Why not just a shell script?\"\n\nFair question — and honestly: **if you need one or two long-lived containers for\nyourself, a shell script (or `docker run`, or [lxd](https:\u002F\u002Fcanonical.com\u002Flxd))\nis simpler. Use that.** We mean it. sandboxd is overkill for one-off projects.\n\nIt earns its keep the moment you're running **many** sandboxes for **other\npeople** — a team, or a product — because that's when the tidy little `docker\nrun` script quietly grows into all of this:\n\n- **URLs, not ports.** Every sandbox gets a clean preview URL with automatic\n  routing + TLS — no port bookkeeping, no collisions to manage.\n- **It sleeps and wakes itself.** Idle sandboxes stop to free RAM and restart\n  transparently on the next request (warming-up page, readiness probe, request\n  hold). That part alone is well past 100 lines — and it's the difference\n  between one cheap box and a rack of always-on VMs.\n- **It survives reboots.** SQLite is the source of truth; a reconciler\n  re-converges Docker to it on boot. A script forgets everything when the host\n  restarts.\n- **It's an API, not a CLI you shell into.** create \u002F exec \u002F stop \u002F destroy \u002F\n  write-files \u002F run-agent-task are real HTTP endpoints with auth — you call them\n  from your app backend, per user, at scale.\n- **One user can't take down the rest.** Per-sandbox memory\u002FPID limits + a\n  host-memory pressure reaper.\n- **Agents with a lifecycle.** Submit a prompt, stream progress (SSE), capture a\n  durable result — not just `opencode` fired inline.\n\nRebuild those as your script grows and you've rebuilt sandboxd. So: skip it for\none-offs; reach for it when \"just a script\" has started keeping you up at night.\n\n> **Prefer Kubernetes?** The control plane talks to the container runtime through\n> a thin `docker` CLI boundary, so a k8s Job\u002FPod backend is an interface swap,\n> not a rewrite — a great first contribution. Today it targets a single Docker\n> host (no k8s required), which is the sweet spot for teams who don't want to run\n> a cluster just for sandboxes.\n\n## Quick start\n\nRequirements: **Docker Engine + the Compose plugin**, on Linux. That's it.\n\n### 1. Install\n\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002Ftastyeffectco\u002Fsandboxd.git\ncd sandboxd\n.\u002Finstall.sh\n```\n\n`install.sh` checks Docker, writes a `.env`, builds the sandbox base image + the\ncontrol plane, and starts the stack. The API is then live at\n`http:\u002F\u002F127.0.0.1:9090` (verify: `curl http:\u002F\u002F127.0.0.1:9090\u002Fhealthz` → `ok`).\n\n### 2. Have an agent build an app\n\nThe base image already includes the **OpenCode** and **Claude Code** CLIs. Hand\na sandbox a prompt and watch it build (OpenCode runs on its free plan out of the\nbox; pass your own provider key via `env` to use your account):\n\n```bash\nAPI=http:\u002F\u002F127.0.0.1:9090\n\n# create a sandbox that will serve on port 3000\nID=$(curl -s -XPOST $API\u002Fsandbox -H 'content-type: application\u002Fjson' \\\n       -d '{\"ports\":[3000]}' | sed -E 's\u002F.*\"id\":\"([^\"]+)\".*\u002F\\1\u002F')\necho \"sandbox: $ID\"\n\n# spin a coding agent with a request — it works in ~\u002Fworkspace\u002Fapp\ncurl -s -XPOST $API\u002Fv1\u002Fsandboxes\u002F$ID\u002Ftasks -H 'content-type: application\u002Fjson' -d '{\n        \"prompt\":\"create a Vite app that shows a todo list and run it on port 3000\",\n        \"agent\":\"opencode\"\n     }'\n# -> {\"id\":\"\u003CtaskId>\",\"status\":\"running\",\"events_url\":\"\u002Fv1\u002Fsandboxes\u002F\u003Cid>\u002Ftasks\u002F\u003CtaskId>\u002Fevents\"}\n\n# stream the agent's progress (Server-Sent Events)\ncurl -N $API\u002Fv1\u002Fsandboxes\u002F$ID\u002Ftasks\u002F\u003CtaskId>\u002Fevents\n```\n\nTo use your own model account instead of the free plan, inject a key at create\ntime — it's available to the agent and any shell in the sandbox:\n\n```bash\ncurl -s -XPOST $API\u002Fsandbox -d '{\"ports\":[3000],\"env\":{\"ANTHROPIC_API_KEY\":\"sk-ant-...\"}}'\n```\n\n### 3. Open the live preview\n\nOnce the app serves on port 3000, it's reachable at its preview URL — the\nsandbox self-registered the route, nothing else to wire:\n\n```\nhttp:\u002F\u002Fs-\u003Cid>-3000.preview.localhost\n```\n\n`*.localhost` resolves to `127.0.0.1` in every modern browser, so it works\nlocally with zero DNS and zero certificates (add `:$HTTP_PORT` if you changed it\nfrom 80). The first request to a stopped sandbox **wakes it** automatically. On a\nreal domain you get `https:\u002F\u002Fs-\u003Cid>-3000.preview.yourdomain.com`\n(see [Production \u002F TLS](#production--tls)).\n\n> **Just want a shell, no agent?** Skip step 2 and run anything via the exec API:\n> `curl -XPOST $API\u002Fsandbox\u002F$ID\u002Fexec -d '{\"cmd\":[\"bash\",\"-lc\",\"cd ~\u002Fworkspace\u002Fapp && python3 -m http.server 3000\"]}'`\n> then open the same preview URL.\n\n## API\n\nBase URL = `http:\u002F\u002F127.0.0.1:9090` (set by `SANDBOXD_API_BIND`). Auth is **off\nby default** for local use; with `SANDBOXD_API_AUTH_DISABLED=false` +\n`SANDBOXD_API_TOKENS`, send `-H \"Authorization: Bearer \u003Csecret>\"`.\n\n| Method & path | Body | Purpose |\n|---|---|---|\n| `POST \u002Fsandbox` | `{\"ports\":[3000],\"env\":{...}}` | **create** — `id` optional (ULID auto); `env` injects vars (e.g. API keys) |\n| `GET \u002Fsandboxes` | — | list all sandboxes |\n| `GET \u002Fsandbox\u002F{id}` | — | get one (status, ports, container id…) |\n| `POST \u002Fsandbox\u002F{id}\u002Fexec` | `{\"cmd\":[\"bash\",\"-lc\",\"…\"]}` | run a command (non-interactive) |\n| `POST \u002Fsandbox\u002F{id}\u002Fkeepalive` | — | postpone the idle reaper |\n| `POST \u002Fv1\u002Fsandboxes\u002F{id}\u002Fstop` | — | stop now to free RAM (wakes on next preview hit) |\n| `DELETE \u002Fsandbox\u002F{id}` | — | destroy the container, **keep** the workspace |\n| `POST \u002Fsandbox\u002F{id}\u002Fpurge` | — | destroy **and delete** the workspace |\n| `POST \u002Fv1\u002Fsandboxes\u002F{id}\u002Ftasks` | `{\"prompt\":\"…\",\"agent\":\"opencode\"}` | run a coding agent headlessly |\n| `GET \u002Fv1\u002Fsandboxes\u002F{id}\u002Ftasks\u002F{taskId}` | — | task result |\n| `GET \u002Fv1\u002Fsandboxes\u002F{id}\u002Ftasks\u002F{taskId}\u002Fevents` | — | live task event stream (SSE) |\n| `GET\u002FPUT \u002Fv1\u002Fsandboxes\u002F{id}\u002Ffiles` | `{\"path\",\"content\",\"append\"}` | list \u002F read \u002F write workspace files |\n| `GET \u002Fhealthz`, `GET \u002Freadyz` | — | liveness \u002F readiness |\n\nA complete, copy-pasteable runbook (including driving it from your own agent) is\nin **[`AGENTS.md`](AGENTS.md)**.\n\n## How it works\n\n| Concern | Choice |\n|---|---|\n| Container runtime | Docker + hardened `runc` (cap-drop ALL, `no-new-privileges`, read-only rootfs) |\n| Workspace storage | one bind-mounted directory per sandbox under the data dir (persists) |\n| Edge \u002F preview | Traefik v3 Docker provider — sandboxes self-register their routes |\n| Idle management | stop-on-idle (`docker stop`) + wake-on-request; no warm pool |\n| State | SQLite (WAL); a reconciler converges Docker to the DB on boot |\n| Control plane | one Go binary, shells out to the `docker` CLI over the mounted socket |\n\nThe control plane runs in a container with the host Docker socket mounted and\nlaunches each sandbox as a sibling container on a shared network so Traefik can\nroute to it. Full design: [`ARCHITECTURE.md`](ARCHITECTURE.md).\n\n## Configuration\n\nEverything is in `.env` (created from [`.env.example`](.env.example) on install).\nThe defaults run a complete local stack. The knobs you'll touch most:\n\n| Variable | Default | What it does |\n|---|---|---|\n| `PREVIEW_DOMAIN` | `localhost` | domain preview URLs hang off |\n| `HTTP_PORT` | `80` | host port Traefik listens on |\n| `SANDBOXD_DATA_DIR` | `\u002Fvar\u002Flib\u002Fsandboxed` | where workspaces + state live |\n| `SANDBOXD_API_BIND` | `127.0.0.1:9090` | where the control-plane API is published |\n| `SANDBOXD_API_AUTH_DISABLED` | `true` | open API for local use; set `false` + tokens for prod |\n\n## Production \u002F TLS\n\nFor a public deployment on a real wildcard domain:\n\n1. Point `*.preview.yourdomain.com` at the host.\n2. In `traefik\u002Ftraefik.yml`, enable the `websecure` entrypoint and add a\n   certificate resolver (Let's Encrypt DNS-01 is ideal — one wildcard cert covers\n   every preview host, so you never hit per-host ACME limits).\n3. In `.env`: `PREVIEW_DOMAIN=yourdomain.com`, `PREVIEW_ENTRYPOINT=websecure`,\n   `PREVIEW_TLS=true`, and **enable auth** — `SANDBOXD_API_AUTH_DISABLED=false`\n   with `SANDBOXD_API_TOKENS=name:secret`.\n4. `docker compose up -d`.\n\n## Uninstall\n\n```bash\n.\u002Funinstall.sh            # stop the stack + remove all sandboxes + network (keeps your data)\n.\u002Funinstall.sh --images   # also remove the built Docker images\n.\u002Funinstall.sh --data     # also DELETE all workspaces + state (asks to confirm)\n.\u002Funinstall.sh --all      # full removal: images + data\n```\n\nSafe by default — it removes only what sandboxd created (containers labelled\n`sandboxd.managed=true`, the compose stack, the network) and **keeps your\nworkspaces** unless you pass `--data`\u002F`--all`.\n\n## Is this a good foundation for a startup?\n\nYes — that's exactly the point. If you want to ship an **AI app-builder or agent\nSaaS** without first spending months building multi-tenant isolation, preview\nrouting, idle\u002Fwake cost control, and agent orchestration, sandboxd gives you\nthat core on day one, on a single inexpensive server, with margins you control.\nIt's a **strong, honest starting point** — beta-quality, MIT-licensed, and built\nto be read and extended. Launch lean on it; harden as you grow (next section).\n\n## Before you scale hard: what's simple on purpose, and what to harden\n\nsandboxd v1 is tuned for \"**works anywhere with just Docker, in one command**.\"\nTo keep it that simple, a few things were left basic **on purpose**. None of\nthem affect the core loop (create → build → preview → sleep → wake → persist) —\nthey're the knobs to tighten once you have real users and real money on the line.\nPlain version:\n\n| Kept simple on purpose | Fine for | Do this when you're scaling \u002F serious |\n|---|---|---|\n| **Container isolation** (hardened Docker), not full VMs | your own users running their own code | running **untrusted strangers' code** → put each tenant on its own VM, or use gVisor \u002F Kata \u002F Firecracker |\n| **API auth is OFF by default** | local development | **turn it on** (`SANDBOXD_API_AUTH_DISABLED=false` + tokens) and never expose the API port unauthenticated |\n| **Preview links are public** (anyone with the URL) | demos, sharing | gate sensitive previews (the private-sandbox forward-auth hook) |\n| **Open, unlogged network egress** | most apps | add firewall \u002F egress rules + logging |\n| **Plain-directory workspaces**, no disk quota | a single server | add filesystem\u002Fvolume quotas; plan multi-host sharding |\n| **One server, one Docker socket** (the control plane is root-equivalent on the host) | starting out | treat the host as a trust boundary, keep it patched, isolate it, and don't co-locate unrelated secrets |\n\n**The short version for a fast-scaling company:** the three that matter most are\n(1) **stronger isolation** (VM-per-tenant) if you ever run untrusted code,\n(2) **turn on API auth** and lock down the host, and (3) **plan for more than one\nmachine**. Everything else above is a config change, not a rewrite. Start lean,\nrevisit these as you grow — and PRs are very welcome ([`CONTRIBUTING.md`](CONTRIBUTING.md)).\n\n## License\n\n[MIT](LICENSE). Use it, ship it, sell what you build on it.\n",2,"2026-06-11 04:11:48","CREATED_QUERY"]