Policy-controlled sandboxes for AI coding agents — https://labgate.dev
Policy-controlled sandboxes for AI coding agents. Built for HPC clusters.
- Primary workflow: Claude (labgate claude)
- Primary runtime: Apptainer on HPC
- macOS runtime: Podman (best-effort fallback path)
- Secondary targets (best-effort): other agents
``bash`
npm i -g labgate
Note: LabGate uses node-pty only for the optional sticky footer. On minimal Linux installs, that dependency may fail to build without a compiler toolchain. If it fails, the install still works and LabGate falls back to non-sticky output.
LabGate prefers Apptainer for sandbox runtime and supports Podman as a fallback (especially on macOS).
`bash`
labgate init # create ~/.labgate/config.json
labgate claude # launch Claude Code in current dir
labgate codex /projects/my-analysis # launch Codex in a specific dir
LabGate runs your AI coding agent inside a sandboxed container with:
- Scoped filesystem — only your working directory and configured paths are visible
- Credential blocking — .ssh, .aws, .env, .gnupg, and other sensitive paths are hidden by defaulthost
- Network policy — configurable network modes (, filtered, none)ssh
- Command blocking — , curl, wget, and other commands are blocked by default~/.labgate/logs/
- Audit logging — session start/stop and mount configuration logged to AGENTS.md
- Dashboard instructions editor — view and update per-session / CLAUDE.md from the UI
- Session context injection — LabGate prepends a temporary sandbox-mapping instruction block during active sessions
- HPC ready — first-class Apptainer support for shared clusters
Edit ~/.labgate/config.json to customize:
`bash`
$EDITOR ~/.labgate/config.json
Or start fresh:
`bash`
labgate init --force
| Setting | Default | What it does |
|---------|---------|-------------|
| runtime | auto | auto, apptainer, or podman |image
| | node:20-slim | Container image |session_timeout_hours
| | 8 | Max session length |filesystem.blocked_patterns
| | .ssh, .aws, .env, ... | Hidden from sandbox |filesystem.extra_paths
| | [] | Additional mounts |network.mode
| | host | none, filtered, or host |commands.blacklist
| | ssh, curl, wget, ... | Blocked commands |
`bash`
labgate claude [workdir] # launch Claude Code
labgate codex [workdir] # launch Codex
labgate feedback # submit feedback (interactive or piped)
labgate status # list running sessions
labgate stop
labgate ui # start dashboard server (owner-only Unix socket by default)
labgate register
labgate license # show enterprise license status
labgate license install
labgate policy init [--institution ... --admin ...] # create policy template
labgate policy validate [file] # validate policy JSON
labgate logs [-n 20] # view recent audit events
labgate logs --follow # stream new audit events
labgate init [--force] # create/reset config
`bash`
labgate claude --dry-run # print the sandbox command without running
labgate claude --image my-image:tag # use a different container image
labgate claude --no-footer # disable the status footer line
labgate ui --port 7700 # localhost UI, URL includes required auth token
labgate ui --socket ~/.labgate/ui.sock # custom Unix socket path
labgate logs --lines 50 --follow # tail last 50 lines and keep following
Submit feedback from the CLI:
`bash`
labgate feedback
echo "This was great" | labgate feedback
labgate feedback "Short feedback message"
If LABGATE_FEEDBACK_URL is set, LabGate will POST feedback JSON to that URL.LABGATE_FEEDBACK_TOKEN
If is set, it will be sent as a Bearer token.~/.labgate/feedback.jsonl
If no URL is configured or the request fails, feedback is saved locally at .
Run tests:
`bash`
npm run setup # install dependencies
npm run verify:quick # build + unit tests
npm run verify # build + unit + integration tests
npm run dev:claude # start UI in background, then launch local labgate claude
npm run test:unit # fast unit tests
npm run test:integration # dashboard integration tests
npm run test:e2e:real # opt-in real runtime OAuth/browser smoke test
npm test # unit + integration
npm run release:check # verify + npm pack --dry-run
`bash1) Create a signed enterprise key (issuer side)
export LABGATE_LICENSE_SECRET='replace-with-your-signing-secret'
LICENSE_KEY="$(npx tsx scripts/generate-license.ts \
--institution 'Example University' \
--tier pro \
--expires 2099-12-31 2>/dev/null)"
Automated enterprise coverage:
`bash
npx vitest run -c vitest.integration.config.ts src/lib/cli.enterprise.integration.test.ts src/lib/ui.integration.test.ts
`CI automation runs
npm run verify on every push to main and on pull requests (.github/workflows/ci.yml).
npm run test:integration automatically rebuilds better-sqlite3 first to avoid Node ABI mismatch errors after Node upgrades.Dev launcher options:
`bash
LABGATE_UI_PORT=7711 npm run dev:claude -- /path/to/workdir # custom UI port + workdir
LABGATE_KEEP_UI=1 npm run dev:claude -- . # keep UI running after claude exits
`Coverage:
-
npm run test:unit covers config/runtime/container helpers
- npm run test:integration covers dashboard flow that:
1. Builds the CLI
2. Starts labgate ui on a temporary localhost port
3. Launches labgate claude and labgate codex with a mocked runtime
4. Verifies sessions appear in /api/sessions (dashboard data source)
5. Stops a session through POST /api/sessions/stop and verifies it disappears
6. Verifies UI port fallback when requested ports are occupied
7. Verifies /api/config accepts valid payloads and rejects invalid payloads without mutating config
8. Verifies labgate logs --follow prints tail output and streams newly appended events
9. Verifies dashboard activity inference for accessed files and websites from agent transcripts
10. Verifies GET/PUT /api/sessions/:id/instructions with conflict detection for AGENTS.md and CLAUDE.md
- npm run test:e2e:real runs a real runtime smoke test for OAuth/browser opening:
1. Launches real labgate claude (no mocked container runtime)
2. Waits for OAuth URL flow
3. Verifies host browser-open hook is triggered
4. Optional override: LABGATE_REAL_E2E_IMAGEHow it works
LabGate builds a sandboxed container from your config:
1. Detects Apptainer first, then Podman (or uses explicit runtime)
2. Mounts your working directory at
/work
3. Mounts persistent sandbox HOME at /home/sandbox (for npm cache, agent config)
4. Overlays blocked paths (.ssh, .aws, etc.) with empty mounts
5. Applies network isolation and capability restrictions
6. Installs the agent (if not cached) and runs it interactivelyOn macOS, LabGate syncs your Claude credentials from the system keychain so the agent can authenticate automatically.
Audit logs
Session events are logged to
~/.labgate/logs/YYYY-MM-DD.jsonl:`bash
cat ~/.labgate/logs/2025-02-05.jsonl | jq .
``- M0 CLI + sandbox engine + config + audit (this release)
- M1 Mount allowlists, network filtering, project-level config
- M2 SLURM proxy (submit/status/cancel from inside sandbox)
- M3 Web UI for config + audit viewer
- M4 Institutional mode (/etc/labgate/ policies, admin locks)
MIT