agent sandbox - #1
Merged
Merged
Conversation
Two-user (app/agent) filesystem permission model inside a single container, supervisor-managed process lifecycle with crash-loop auto-revert, auto-commit on agent edits, and a split AGENTS.md (immutable rules + agent-editable knowledge base) to teach the agent its environment. Scope is the runtime sandbox only; broader hardening (CI, prod start scripts, dependency pinning) is orthogonal and tracked separately.
15 tasks across branch setup, repo reshuffle, infra consolidation, supervisor implementation (TDD per module), AGENTS.md files, Dockerfile rewrite with two users + healthcheck, and end-to-end revert smoke test. Fallback priv-drop approach; coarse supervisor-watcher auto-commit; clean-slate assumption (no existing-volume migration). Phase-2 polish (OpenCode plugin auto-commit, ops-channel notifications, salvage logic, migration) deferred.
Debian has predictable glibc, setpriv, and addgroup behavior; alpine's busybox utilities are inconsistent for user/permission setup we're about to add.
Groundwork for the agent sandbox. src/ will be the agent-editable tree; everything outside it will be off-limits to the agent.
Moves Dockerfile, compose.yml, and entrypoint.sh under infra/. Updates paths to reference src/website and src/discordbot. Tighter .dockerignore. Repo-root compose.yml is a symlink for convenience.
Bun project under infra/supervisor with a typed loadConfig() reading env vars with defaults. Test-driven.
ensureWorkspaceRepo is idempotent; commitAll uses per-commit author env so agent vs supervisor attribution is preserved; hardResetTo and a private refs/supervisor/good ref track the last known good commit.
Sliding window over recent non-zero exits; once threshold hit within window the process is marked bricked and stops auto-restarting. clearCrashes() resets so the orchestrator can unbrick after a revert.
Spawns opencode, website, and bot; watches src/ for changes; debounced auto-commits as 'agent'; debounced restarts; periodic tick updates the good ref when revertables have been healthy, and auto-reverts bricked revertables to the good ref with a supervisor-authored revert commit. Halts recovery after 3 consecutive failed reverts.
Adds allowEmpty option to commitAll so the orchestrator can record supervisor-initiated revert events as explicit git commits even when the working tree matches the target sha. Also fixes four strict-mode typecheck errors uncovered by running tsc --noEmit over the package: Bun server.port is number|undefined (assert), Response.json() returns unknown (cast), and a let+assign split in the batcher's IIFE to satisfy control-flow analysis.
infra/AGENTS.md is the source of truth for what the agent is allowed to do; entrypoint will concatenate it with AGENTS.md.tmpl to produce /workspace/AGENTS.md on first boot.
- Seeds /workspace on first boot without leaking .git/.github/Dockerfile. - Regenerates /workspace/AGENTS.md top section from infra/AGENTS.md on every boot; salvages previous editable content if sentinel missing. - Sets ownership so agent user can write src/ and .git/ but not infra/. - Installs deps if missing (first-boot volume). - Drops to 'app' user and execs the supervisor.
- Renames the default bun user (uid 1000) to 'app' so we keep the UID. - Adds 'agent' user at uid 1001 and puts app in the agent group. - Installs git, util-linux (setpriv), curl. - Pre-installs supervisor deps into the seed. - HEALTHCHECK pings supervisor at :3002. - Removes :4096 exposure; OpenCode is internal-only. - compose.yml: paths relativized to infra/, restart: unless-stopped, DISCORD_BOT_PORT var respected, OPENCODE_URL to loopback.
Five real issues surfaced by the first end-to-end smoke test: 1. The opencode binary copied from ghcr.io/anomalyco/opencode:latest is musl-linked for alpine; on debian it fails with 'libc.musl-*.so.1 => not found'. Switched to the official opencode.ai/install script which picks the correct glibc build. Adds ca-certificates and tar to the apt install list. 2. cp -a of the seed included every src/node_modules, which ballooned seed time to ~40s and made 'git add -A' in the workspace repo glacial. Switched to rsync with --exclude node_modules/dist and ship a workspace.gitignore so the workspace git repo never tracks node_modules. 3. The website ManagedProcess spawned 'bun run src/server.tsx' directly, which skips the build:css step. The old setup used 'bun run dev' which built CSS first. Wrap the cmd in 'bash -c build:css && exec bun run src/server.tsx' so CSS is built before the server starts. 4. oven/bun:1 ships a pre-existing user at uid 1000; our 'app' useradd collided. Rename the existing bun user to app rather than creating a new one (preserves the uid). 5. Bind-mounting ./volumes/clawscibois_data on macOS uses grpcfuse which does not enforce Linux uid/perm semantics — root-owned 755 dirs become writable by non-root users. Switched to a Docker-managed named volume (ext4 inside the VM) so perms are real. Fix is also preferable on Linux for isolation. Also: supervisor no longer lives in the workspace volume — it runs from /opt/workspace-seed/infra/supervisor (root-owned, image-baked). That removes the chicken-and-egg 'chown then su app bun install' ordering problem and keeps supervisor code fully out of the agent-editable surface. Verified end-to-end: - opencode, website, supervisor all boot cleanly - discordbot correctly crash-loops on missing real Discord env (expected) - curl http://localhost:3000 serves the React SSR page - docker exec -u agent cannot write to /workspace/infra/ (EACCES) - docker exec -u agent cannot modify /workspace/infra/AGENTS.md - docker exec -u agent cannot touch /opt/workspace-seed/ - docker exec -u agent CAN write to /workspace/src/ and /workspace/AGENTS.md - file change triggers: watch event -> restart website -> auto-commit as agent author, all with the expected debounces.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.