{"id":51604177,"url":"https://github.com/mlhiter/mbox","last_synced_at":"2026-07-12T00:30:26.767Z","repository":{"id":358779918,"uuid":"1239667102","full_name":"mlhiter/mbox","owner":"mlhiter","description":"Kubernetes-native sandbox and CI/CD control plane for runnable dev environments, pipelines, deployments, policies, and credentials.","archived":false,"fork":false,"pushed_at":"2026-05-29T03:18:10.000Z","size":487,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-29T05:13:19.502Z","etag":null,"topics":["automation","ci-cd","cloud-native","deployment","dev-environments","developer-tools","devops","go","kubernetes","network-policy","platform-engineering","postgres","rbac","sandbox","vite"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mlhiter.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-15T10:14:37.000Z","updated_at":"2026-05-29T03:18:13.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mlhiter/mbox","commit_stats":null,"previous_names":["mlhiter/mbox"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mlhiter/mbox","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mlhiter%2Fmbox","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mlhiter%2Fmbox/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mlhiter%2Fmbox/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mlhiter%2Fmbox/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mlhiter","download_url":"https://codeload.github.com/mlhiter/mbox/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mlhiter%2Fmbox/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35378722,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-11T02:00:05.354Z","response_time":104,"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":["automation","ci-cd","cloud-native","deployment","dev-environments","developer-tools","devops","go","kubernetes","network-policy","platform-engineering","postgres","rbac","sandbox","vite"],"created_at":"2026-07-12T00:30:25.975Z","updated_at":"2026-07-12T00:30:26.760Z","avatar_url":"https://github.com/mlhiter.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mbox\n\nmbox is a Kubernetes-native execution platform for programmable sandboxes, runtime sessions, previews, artifacts, and policy boundaries.\n\nThe product provides a web console and API for creating runnable development sandboxes, configuring environment templates, connecting runtime sessions, exposing previews, collecting execution outputs, and managing the policies that make those workflows safe in a shared Kubernetes cluster.\n\nThe project is independent at the product layer. Its core language is environment template, sandbox, runtime session, execution task, preview, artifact, policy, and credential boundary. External agents, IDEs, CI systems, release tools, and human operators are clients of the platform; mbox does not include an agent brain and is not primarily a CI/CD product.\n\nLong term, mbox should have several coordinated technical surfaces:\n\n- server side: Go API server, controllers, `agent-sandbox` integration, and Kubernetes resources\n- web app: human-facing operational console\n- CLI: scriptable operation for developers, CI, and platform users\n- API docs: published product API contract\n- SDK package: Node.js or Go package for automation clients\n\n## Product Shape\n\n- People can create and enter sandboxes through terminal, IDE, notebook, browser, or preview endpoints.\n- Platform users can define templates for language stacks, tools, startup commands, resources, storage, network access, and lifecycle rules.\n- External clients can run controlled sessions and tasks inside Kubernetes execution environments.\n- Previews and artifacts make runtime outputs inspectable without exposing direct Kubernetes access.\n- CI and deployment systems can be built as upper-layer clients after the lower-level runtime primitives are stable.\n- Operators can enforce quota, RBAC, network policy, credential boundaries, and cleanup rules.\n\n## Core Documents\n\n- [PRODUCT.md](PRODUCT.md): product direction, users, scope, and product limits.\n- [ARCHITECTURE.md](ARCHITECTURE.md): system layers, runtime design, security boundaries, and Kubernetes integration.\n- [ROADMAP.md](ROADMAP.md): staged execution plan from prototype to production platform.\n- [AGENTS.md](AGENTS.md): instructions for future coding agents working in this repo.\n- [docs/architecture.md](docs/architecture.md): short implementation architecture handoff for the current slice.\n- [docs/server-api.md](docs/server-api.md): currently implemented server routes, config, data model, and runtime projection.\n- [docs/web-console.md](docs/web-console.md): Vite console structure, local proxy behavior, UI scope, and verification.\n- [docs/runbook.md](docs/runbook.md): local startup, verification, runtime smoke, and troubleshooting commands.\n- [docs/ia.md](docs/ia.md): current web-console information architecture.\n- [docs/references.md](docs/references.md): runtime, Kubernetes, and frontend reference notes.\n- [docs/research-agent-sandbox.md](docs/research-agent-sandbox.md): notes about using `kubernetes-sigs/agent-sandbox` as the interactive sandbox runtime substrate.\n\n## Current Status\n\nThis repository now contains the first vertical slice: a Go API server backed by Postgres for mbox product records plus a separate Vite web console.\n\nImplemented resources:\n\n- `Project`\n- `EnvironmentTemplate`\n- `Sandbox`\n- TypeScript SDK package under `sdk/typescript` for external automation clients\n- Go CLI entrypoint under `cmd/mbox` for scriptable access to the public HTTP API\n- Vite console views for listing projects, creating/editing templates, and launching sandboxes\n- template library for ready-to-run environments, with user-facing runtime type, use case, entrypoints, resource preset, server-backed validation runs, and advanced image/command/policy fields\n- project-scoped launch policy that can gate sandbox launches by image prefix, runtime identity, and template secret reference names\n- project credential-reference registry for narrow Git, registry, Kubernetes, SSH, or generic secret references without storing credential values\n- read-only project usage summaries for product-record counts and declared active/running sandbox request totals across sandboxes, sessions, tasks, artifacts, templates, and credential references\n- read-only boundary summaries for templates and sandboxes, covering namespace, runtime identity, launch policy, secret references, project credential references, network policy projection, lifecycle policy projection, runtime access paths, and cleanup behavior\n- lifecycle `ttlSeconds` enforcement that automatically soft-deletes expired sandboxes and triggers the normal runtime cleanup path\n- runtime orphan audit plus explicitly confirmed one-resource cleanup for mbox-managed runtime resources whose labels no longer match product records\n- simplified sandbox launch that asks for project, template, and name while deriving slug, namespace, and ServiceAccount defaults\n- sandbox stop/start actions that pause and resume the projected runtime without deleting the product record\n- browser terminal, workspace storage, manually declared preview ports, asynchronous execution tasks with cancellation, artifact references with retained workspace-file or client-uploaded content, and lightweight logs/events for ready sandbox runtimes\n\nThis slice persists mbox product state in Postgres. When the runtime controller is explicitly enabled, it reconciles `Sandbox` records into `agent-sandbox` `SandboxTemplate` and `SandboxClaim` resources.\n\n## Local Development\n\nStart the full local development stack:\n\n```sh\n./scripts/dev.sh\n```\n\nThis starts local Postgres, the Go API server, and the Vite web console. Open `http://127.0.0.1:5174`.\n\nRuntime access is disabled by default so ordinary local startup does not write Kubernetes resources. To enable the `agent-sandbox` controller, terminal, execution tasks, logs, events, and preview proxy:\n\n```sh\nMBOX_KUBE_CONTEXT=kind-agent-sandbox ./scripts/dev.sh --runtime\n```\n\nIf you already have Postgres running, skip Docker Postgres:\n\n```sh\nDATABASE_URL='postgres://mbox:mbox@127.0.0.1:5432/mbox?sslmode=disable' ./scripts/dev.sh --no-docker\n```\n\nStart a local Postgres:\n\n```sh\ndocker run --name mbox-postgres \\\n  -e POSTGRES_USER=mbox \\\n  -e POSTGRES_PASSWORD=mbox \\\n  -e POSTGRES_DB=mbox \\\n  -p 5432:5432 \\\n  -d postgres:17\n```\n\nRun the API server:\n\n```sh\nDATABASE_URL='postgres://mbox:mbox@127.0.0.1:5432/mbox?sslmode=disable' go run ./cmd/mbox-server\n```\n\nThe server listens on `127.0.0.1:18080` by default. Override it with `MBOX_LISTEN_ADDR`.\n\nRun the Vite web console in a second shell:\n\n```sh\ncd web\nnpm install\nnpm run dev\n```\n\nOpen `http://127.0.0.1:5174`. During local development, Vite proxies `/healthz` and `/v1/*` to the API server at `127.0.0.1:18080`. If you override `MBOX_LISTEN_ADDR`, set `MBOX_API_PROXY_TARGET` before starting Vite:\n\n```sh\nMBOX_API_PROXY_TARGET=http://127.0.0.1:19080 npm run dev\n```\n\nIf the API server uses `MBOX_API_TOKEN`, start Vite with the same token in `MBOX_TOKEN` or `MBOX_API_TOKEN`; the dev proxy adds the bearer header server-side and does not expose it to frontend code.\n\nThe web dev port defaults to `5174` to avoid colliding with other local Vite projects. Override it with `MBOX_WEB_PORT`.\n\nThe runtime controller is disabled by default so local API development does not write to a Kubernetes cluster. Enable it explicitly when you want mbox to reconcile `Sandbox` records into `agent-sandbox` resources:\n\n```sh\nexport MBOX_RUNTIME_CONTROLLER_ENABLED=true\nexport MBOX_RUNTIME_ACCESS_ENABLED=true\nexport MBOX_KUBECONFIG=\"$HOME/.kube/config\"\nexport MBOX_KUBE_CONTEXT=\"\u003ccontext-name\u003e\"\ngo run ./cmd/mbox-server\n```\n\nOptional runtime settings:\n\n- `MBOX_RUNTIME_RECONCILE_INTERVAL`: reconcile loop interval, for example `5s`.\n- `MBOX_RUNTIME_ACCESS_ENABLED`: enables terminal, task execution, logs, events, and runtime target routes when set to `true`.\n- `MBOX_AGENT_SANDBOX_WARM_POOL`: `agent-sandbox` warm pool policy, for example `none` or `default`.\n\nWhen enabled, mbox ensures the sandbox namespace exists, creates a scoped sandbox ServiceAccount with token automount disabled, creates or updates a `SandboxTemplate`, and creates a `SandboxClaim` in that namespace. The generated pod template uses the configured sandbox ServiceAccount and also disables token automount. If the template has `storageRequest`, mbox projects a `workspace` PVC template and mounts it at the template working directory, defaulting to `/workspace`. The mbox Postgres record remains the product source of truth; Kubernetes resources are the runtime projection.\n\nStopping a sandbox pauses the projected runtime by scaling the resolved `agent-sandbox` `Sandbox` to zero replicas. This releases the Pod and running processes while keeping the mbox record and runtime reference. Workspace data is preserved only when it lives on the persistent workspace PVC; files written to container-local paths can be lost during stop/start. Starting a stopped sandbox marks it `pending` and scales the runtime back to one replica.\n\n`MBOX_RUNTIME_ACCESS_ENABLED=true` enables `/v1/sandboxes/{id}/terminal`, `/tasks`, `/runtime`, `/logs`, `/events`, and `/ports`. The terminal route is a WebSocket proxy from the browser to Kubernetes `pods/exec`; execution tasks enqueue non-interactive `pods/exec` commands, persist output records, and can be canceled while running on the current API server; declared TCP preview ports are proxied through the mbox API server to the resolved runtime Pod. Artifact reference routes and client content uploads do not require direct runtime access, while workspace content read/capture routes do. Artifact content is retained server-side for small `workspace://` file captures or direct client uploads; external URLs and object-store bytes are still references only. Project credential records store only Secret references and metadata, not secret values, and ordinary sandbox pods still do not receive broad Kubernetes credentials.\n\nRetained artifact bytes default to the `postgres` backend for local compatibility. Set `MBOX_ARTIFACT_CONTENT_BACKEND=filesystem` and optionally `MBOX_ARTIFACT_CONTENT_DIR=/path/to/artifacts` to keep captured bytes out of Postgres while leaving artifact metadata and provider keys in the product database. For remote durability, `MBOX_ARTIFACT_CONTENT_BACKEND=s3` writes retained bytes to an explicitly configured S3-compatible endpoint and bucket while Postgres remains the metadata index.\n\nProject deletion is guarded while sandbox cleanup is pending. Delete sandboxes first, let the reconciler clear their `runtimeRef` after deleting the projected `SandboxClaim`, then delete the project. This keeps Postgres from cascading away the product rows that the controller needs for runtime cleanup.\n\nThe runtime orphan audit is read-only and intended for operators:\n\n```sh\ngo run ./cmd/mbox --api-url http://127.0.0.1:18080 runtime resources\ngo run ./cmd/mbox --api-url http://127.0.0.1:18080 runtime resources --summary\ngo run ./cmd/mbox --api-url http://127.0.0.1:18080 runtime resources --namespace mbox-smoke-20260529\ngo run ./cmd/mbox --api-url http://127.0.0.1:18080 runtime resources --project-id \u003cproject-id\u003e --kind SandboxClaim\ngo run ./cmd/mbox --api-url http://127.0.0.1:18080 runtime resources --kind SandboxClaim\ngo run ./cmd/mbox --api-url http://127.0.0.1:18080 runtime orphans\ngo run ./cmd/mbox --api-url http://127.0.0.1:18080 runtime orphans --namespace mbox-smoke-20260529\ngo run ./cmd/mbox --api-url http://127.0.0.1:18080 runtime orphans --project-id \u003cproject-id\u003e\ngo run ./cmd/mbox --api-url http://127.0.0.1:18080 runtime orphans --kind SandboxTemplate\n```\n\nThe resource inventory lists mbox-managed `SandboxClaim` and `SandboxTemplate` objects reported by the runtime auditor, with a live summary by kind, namespace, label-derived owner, and observed workload shape. Use `runtime resources --summary` when you only need that filtered summary object. For `SandboxClaim` rows, inventory also includes a best-effort runtime observation: resolved runtime sandbox, selected Pod phase, Pod counts, container readiness, restart count, summed Pod requests/limits, and workspace PVC state when available. The inventory and orphan audit can be scoped by namespace, project owner label, kind, or a combination of those filters. The `--project-id` filter matches mbox-managed runtime resources that carry `mbox.dev/project-id`; it is mainly useful for project-owned `SandboxClaim` rows and should not be read as a full RBAC or quota boundary. The orphan audit compares that inventory with product records and reports resources whose labels no longer line up cleanly, including cleanup-pending soft-deleted sandboxes. The workload rollup is not metrics-server utilization, quota, billing, or product-record usage; it is only the current runtime auditor view.\n\nCleanup is deliberately gated and one-resource-at-a-time:\n\n```sh\ngo run ./cmd/mbox --api-url http://127.0.0.1:18080 runtime cleanup-orphan \\\n  --adapter agent-sandbox \\\n  --kind SandboxClaim \\\n  --namespace mbox-old \\\n  --name old-claim \\\n  --reason missing-sandbox-record \\\n  --confirm delete-orphan-runtime-resource\n```\n\nThe server re-runs the audit first and deletes only when the resource is still reported as an orphan with the requested reason.\n\nRun tests:\n\n```sh\ngo test ./...\ngo run ./cmd/mbox --help\n./scripts/smoke-cli.sh\ncd web \u0026\u0026 npm run build\ncd sdk/typescript \u0026\u0026 npm install \u0026\u0026 npm run build\n```\n\nPostgres integration tests are opt-in because they write to the configured test database:\n\n```sh\nexport MBOX_TEST_DATABASE_URL='postgres://mbox:mbox@127.0.0.1:5432/mbox_test?sslmode=disable'\ngo test ./internal/postgres\n```\n\n## API Smoke Test\n\nCreate a project:\n\n```sh\ncurl -sS -X POST http://127.0.0.1:18080/v1/projects \\\n  -H 'content-type: application/json' \\\n  -d '{\n    \"name\": \"Demo Project\",\n    \"repositoryUrl\": \"https://github.com/example/demo\",\n    \"defaultNamespace\": \"mbox-demo\"\n  }'\n```\n\nCreate a Node.js workspace template:\n\n```sh\ncurl -sS -X POST http://127.0.0.1:18080/v1/templates \\\n  -H 'content-type: application/json' \\\n  -d '{\n    \"name\": \"Node.js Workspace\",\n    \"image\": \"node:22-bookworm-slim\",\n    \"startupCommand\": [\"sh\", \"-c\", \"mkdir -p /workspace \u0026\u0026 cd /workspace \u0026\u0026 echo mbox node sandbox ready \u0026\u0026 tail -f /dev/null\"],\n    \"workingDir\": \"/workspace\",\n    \"cpuRequest\": \"250m\",\n    \"memoryRequest\": \"512Mi\",\n    \"storageRequest\": \"2Gi\",\n    \"exposedPorts\": [\n      {\"name\": \"web\", \"port\": 3000, \"protocol\": \"TCP\"}\n    ],\n    \"metadata\": {\n      \"runtimeType\": \"Node.js\",\n      \"useCase\": \"Web app preview\",\n      \"resourcePreset\": \"Small\",\n      \"validationStatus\": \"not_tested\"\n    }\n  }'\n```\n\nCreate a sandbox by using the returned project and template IDs:\n\n```sh\ncurl -sS -X POST http://127.0.0.1:18080/v1/sandboxes \\\n  -H 'content-type: application/json' \\\n  -d '{\n    \"projectId\": \"\u003cproject-id\u003e\",\n    \"templateId\": \"\u003ctemplate-id\u003e\",\n    \"name\": \"Demo Sandbox\"\n  }'\n```\n\nIf a project has `defaultTemplateId`, sandbox creation can use project defaults:\n\n```sh\ncurl -sS -X PATCH http://127.0.0.1:18080/v1/projects/\u003cproject-id\u003e \\\n  -H 'content-type: application/json' \\\n  -d '{\"defaultTemplateId\":\"\u003ctemplate-id\u003e\"}'\n\ncurl -sS -X POST http://127.0.0.1:18080/v1/sandboxes \\\n  -H 'content-type: application/json' \\\n  -d '{\n    \"projectId\": \"\u003cproject-id\u003e\",\n    \"name\": \"Demo Sandbox\"\n  }'\n```\n\nIn these paths, mbox derives the slug from the name when `slug` is omitted, uses the project `defaultNamespace`, and defaults the sandbox ServiceAccount to `mbox-sandbox`.\n\nList resources:\n\n```sh\ncurl -sS http://127.0.0.1:18080/v1/projects\ncurl -sS http://127.0.0.1:18080/v1/templates\ncurl -sS http://127.0.0.1:18080/v1/sandboxes\n```\n\n## CLI\n\nThe first CLI lives at `cmd/mbox`. It is a thin HTTP client over the same public API used by the web console and SDK. It does not talk directly to Postgres or Kubernetes, and it does not add agent or CI workflow semantics.\n\nRun it locally:\n\n```sh\ngo run ./cmd/mbox --api-url http://127.0.0.1:18080 health\ngo run ./cmd/mbox --api-url http://127.0.0.1:18080 info\ngo run ./cmd/mbox context current\ngo run ./cmd/mbox projects list\ngo run ./cmd/mbox projects usage \u003cproject-id\u003e\ngo run ./cmd/mbox sandboxes create --project-id \u003cproject-id\u003e --template-id \u003ctemplate-id\u003e --name \"Demo Sandbox\"\ngo run ./cmd/mbox tasks create \u003csandbox-id\u003e --arg sh --arg -lc --arg 'pwd \u0026\u0026 echo ok'\ngo run ./cmd/mbox tasks run \u003csandbox-id\u003e --require-success -- sh -lc 'pwd \u0026\u0026 echo ok'\ngo run ./cmd/mbox tasks wait \u003ctask-id\u003e --timeout 2m\ngo run ./cmd/mbox tasks wait \u003ctask-id\u003e --timeout 2m --require-success\ngo run ./cmd/mbox tasks watch \u003ctask-id\u003e\ngo run ./cmd/mbox tasks artifacts \u003ctask-id\u003e\ngo run ./cmd/mbox sessions list \u003csandbox-id\u003e\ngo run ./cmd/mbox artifacts upload \u003cartifact-id\u003e --file report.txt --content-type text/plain\n```\n\nFor a local CLI/API smoke test:\n\n```sh\n./scripts/smoke-cli.sh\n```\n\nConfiguration:\n\n- `MBOX_API_URL`: API base URL, defaults to `http://127.0.0.1:18080`.\n- `MBOX_API_TOKEN`: optional server-side shared API token. When set on the API server, private routes require bearer authentication while `/healthz` and `/v1/info` stay public.\n- `MBOX_TOKEN`: optional CLI bearer token sent as `Authorization: Bearer \u003ctoken\u003e`.\n- `MBOX_REQUEST_ID`: optional request correlation id sent as `X-Mbox-Request-ID`; the server echoes it and records it in audit metadata for write events.\n- `MBOX_CONTEXT`: optional context name selected from the CLI config file.\n- `MBOX_CONFIG`: optional CLI config file path, defaulting to `~/.mbox/config.json` when that file exists.\n\nCLI contexts are client-side only. They select API URL, token, and audit labels for scripts without changing server state:\n\n```json\n{\n  \"currentContext\": \"local\",\n  \"contexts\": {\n    \"local\": {\n      \"apiUrl\": \"http://127.0.0.1:18080\",\n      \"tokenEnv\": \"MBOX_TOKEN\",\n      \"auditActor\": \"local-operator\",\n      \"auditSource\": \"mbox-cli\"\n    }\n  }\n}\n```\n\nCreate and use a context with:\n\n```sh\ngo run ./cmd/mbox context set local \\\n  --api-url http://127.0.0.1:18080 \\\n  --token-env MBOX_TOKEN \\\n  --audit-actor local-operator \\\n  --audit-source mbox-cli \\\n  --current\n\ngo run ./cmd/mbox --context local projects list\ngo run ./cmd/mbox --context local context current\ngo run ./cmd/mbox --context local context check --require-capability execution-tasks\ngo run ./cmd/mbox context list\n```\n\nUse `context check` as a script preflight for health, `/v1/info`, and CLI/server compatibility before a longer run. It prints redacted diagnostic JSON and can require capabilities such as `execution-tasks`; it is not a login, whoami, RBAC, or token-validity proof. Use `context use \u003cname\u003e` to switch the default context and `context remove \u003cname\u003e` to delete a local context entry. Prefer `--token-env` for reusable configs so token values stay outside the JSON file.\n\nUse `--request-id \u003cid\u003e` when a script needs to line up a command with API logs and `audit_events.metadata.requestId`. Use `--filter-request-id \u003cid\u003e` on `audit-events` reads to retrieve the matching product audit events, `--operation \u003coperation\u003e` to narrow typed metadata such as `policy.denied` operation values, and RFC3339 `--since` / `--until` windows to inspect a known run interval. Request IDs are correlation labels, not auth claims or idempotency keys.\n\nRun a controlled task after the sandbox reaches `running` with runtime access enabled:\n\n```sh\ncurl -sS -X POST http://127.0.0.1:18080/v1/sandboxes/\u003csandbox-id\u003e/tasks \\\n  -H 'content-type: application/json' \\\n  -d '{\n    \"command\": [\"sh\", \"-lc\", \"pwd \u0026\u0026 ls -la\"],\n    \"timeoutSeconds\": 60\n  }'\n\ncurl -sS http://127.0.0.1:18080/v1/sandboxes/\u003csandbox-id\u003e/tasks\n\ncurl -sS -X POST http://127.0.0.1:18080/v1/tasks/\u003ctask-id\u003e/cancel\n\ncurl -sS -X POST http://127.0.0.1:18080/v1/sandboxes/\u003csandbox-id\u003e/artifacts \\\n  -H 'content-type: application/json' \\\n  -d '{\n    \"taskId\": \"\u003ctask-id\u003e\",\n    \"kind\": \"report\",\n    \"name\": \"Test report\",\n    \"uri\": \"workspace:///workspace/reports/test.json\",\n    \"contentType\": \"application/json\"\n  }'\n```\n\n## TypeScript SDK\n\nThe first SDK package lives in `sdk/typescript`. It is a thin client for the public HTTP API, aimed at agents, IDE integrations, CI scripts, release tools, and other external callers. It does not run an agent loop inside mbox; it only makes the platform primitives easier to call.\n\nBuild it locally:\n\n```sh\ncd sdk/typescript\nnpm install\nnpm run build\nnpm run smoke\n```\n\nRun a task and register a referenced artifact:\n\n```ts\nimport { MboxClient, createMboxClientFromEnv } from \"@mbox/sdk\"\n\nconst mbox = new MboxClient({ baseUrl: \"http://127.0.0.1:18080\" })\nconst envMbox = createMboxClientFromEnv()\n\nconst info = await mbox.info()\nconsole.log(info.apiVersion, info.capabilities)\n\nawait mbox.assertCompatibility({\n  requiredCapabilities: [\"execution-tasks\", \"task-events\", \"artifact-client-upload\"],\n})\n\nconst task = await mbox.createExecutionTask(\"\u003csandbox-id\u003e\", {\n  command: [\"sh\", \"-lc\", \"npm test -- --reporter=json \u003e /workspace/reports/test.json\"],\n  timeoutSeconds: 300,\n  metadata: { caller: \"external-agent\" },\n})\n\nconst finished = await mbox.waitForTask(task.id, { requireSuccess: true })\n\nawait mbox.createArtifact(\"\u003csandbox-id\u003e\", {\n  taskId: finished.id,\n  kind: \"report\",\n  name: \"Test report\",\n  uri: \"workspace:///workspace/reports/test.json\",\n  contentType: \"application/json\",\n})\n\nawait mbox.captureArtifactContent(\"\u003cartifact-id\u003e\")\nawait mbox.uploadArtifactContent(\"\u003cartifact-id\u003e\", new Blob([\"client report\"], { type: \"text/plain\" }), {\n  headers: { \"content-type\": \"text/plain\" },\n})\n```\n\nWhen the API server is started with `MBOX_API_TOKEN`, pass the matching client token:\n\n```ts\nconst mbox = new MboxClient({\n  baseUrl: \"http://127.0.0.1:18080\",\n  token: process.env.MBOX_TOKEN,\n})\n```\n\nFor scripts that follow the CLI environment convention, `createMboxClientFromEnv()` reads `MBOX_API_URL`, `MBOX_TOKEN` or `MBOX_API_TOKEN`, `MBOX_REQUEST_ID`, `MBOX_AUDIT_ACTOR`, and `MBOX_AUDIT_SOURCE`. It does not read CLI context files.\n\nRetained artifact metadata includes `retainedContent.storageProvider`, currently `postgres`, `filesystem`, or `s3`, so clients can tell where retained bytes are backed without changing the content download route. `captureArtifactContent` reads from a running sandbox workspace, while `uploadArtifactContent` attaches client-provided bytes directly to the artifact.\n\nFor a disposable local API database, `npm run smoke:api` exercises the SDK against a live server without enabling runtime/Kubernetes access. It creates and cleans up a temporary project, template, sandbox, session record, and client-uploaded artifact.\n\nFor a running runtime-enabled API and sandbox, `npm run smoke:runtime` exercises SDK task execution, successful task waiting, task-scoped artifact listing, workspace content capture, and retained content reads. `scripts/smoke-agent-sandbox.sh` calls this SDK runtime smoke after it launches a sandbox, and uses `mbox sandboxes wait --require-runtime-ref` before runtime actions, so the cluster smoke covers API, CLI, and SDK runtime paths without making the SDK create or clean up Kubernetes resources directly.\n\nFor scriptable template checks, `mbox templates validate-run \u003ctemplate-id\u003e --project-id \u003cproject-id\u003e -- sh -lc '...'` creates a validation sandbox, waits for runtime readiness, runs one task, and writes a passed/failed validation decision. It is a CLI convenience over existing mbox primitives, not a server-side pipeline engine.\n\nThe SDK also exports the current audit-event action types, `PolicyDeniedAuditMetadata`, and `isPolicyDeniedAuditEvent()` for safely rendering selected policy/quota denial audit events. Audit metadata includes `requestId` when a request writes an event, and audit list helpers accept `requestId`, `operation`, `since`, and `until` to filter feeds for one request, script run, typed denial operation, or known time window. Audit events are still best-effort product records, not authentication claims or a strong transactional audit log.\n\n## Runtime Smoke Test\n\nWith the server running and both `MBOX_RUNTIME_CONTROLLER_ENABLED=true` and `MBOX_RUNTIME_ACCESS_ENABLED=true`, run the cluster smoke test against a kubeconfig context that already has `agent-sandbox` installed:\n\n```sh\nexport MBOX_API_URL=http://127.0.0.1:18080\nexport MBOX_KUBECONFIG=\"$HOME/.kube/config\"\nexport MBOX_KUBE_CONTEXT=kind-agent-sandbox\n./scripts/smoke-agent-sandbox.sh\n```\n\nThe smoke test creates a project, a BusyBox terminal template, and a sandbox through the mbox API. It then verifies the generated `SandboxClaim`, resolved `Sandbox`, ready Pod, disabled ServiceAccount token automount, pod logs, workspace exec, API status mapping, task output capture, CLI `tasks run --require-success`, retained artifact content, delete cleanup path, and a clean runtime orphan audit after cleanup.\n\n## Node Preview Smoke\n\nWith runtime mode enabled, launch a sandbox from the Node.js workspace template and wait for it to reach `running`. The Runtime Workspace shows a starting panel while the `SandboxClaim` and Pod are still pending, then enables Terminal, Logs, Events, Storage, Preview, and Tasks.\n\nIn the terminal tab, start a service in the background:\n\n```sh\ncat \u003e server.js \u003c\u003c'EOF'\nconst http = require('http')\nhttp.createServer((req, res) =\u003e {\n  res.end('hello from mbox node preview')\n}).listen(3000, '0.0.0.0')\nEOF\n\nnode server.js \u003e server.log 2\u003e\u00261 \u0026\n```\n\nOpen the Preview tab, make sure port `3000` is declared as `web`, and use `Open` after the sandbox is running. If the template did not declare the port, add it in the Preview tab; this saves the sandbox `ports` field through `PATCH /v1/sandboxes/{id}`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmlhiter%2Fmbox","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmlhiter%2Fmbox","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmlhiter%2Fmbox/lists"}