Realm
Canonical, vendor-neutral instructions for AI coding agents and human contributors. CLAUDE.md imports this file.
Project
Realm is the agent sandbox component of the GSD-Core USSR Stack (Ultrathink, Substrate, Swarm, Realm). Its tagline is "Realm, the home of AI Generated Code" (README.md).
Realm runs an agent's execution and file mutations inside a locked-down sandbox. The layering is settled in docs/integration/runtime-decision.md (S-08): the OpenShell gateway runs on the host; its Podman driver creates one rootless, digest-pinned sandbox container per session; AgentOS runs as the sandbox workload; and Anda Engine runs as a separate service, reached over HTTP from the TypeScript client. Nothing nests OpenShell inside the Realm container, and nothing runs privileged.
Realm ships three things over one tool contract:
- an Omp plugin that autostarts per session;
- a standalone CLI,
realm, with a long-running local daemon; - MCP and ACP surfaces, so other agent hosts use the same sandbox.
Core guarantee, under the fail-closed policy: every file mutation either lands inside the realm under policy or fails closed, and the user can always see whether the realm is active or disconnected for the session. In the default advisory mode the Omp guard warns and allows host write and edit calls while the realm is disconnected; containment requires opting into fail-closed.
Status (README.md and .planning/PROJECT.md):
- v1.0 is provisional and fail-closed.
realm uprefuses withAGENTOS_NOT_CONFIGUREDuntil an AgentOS driver is bound; that driver is deferred to a follow-up milestone. - Linux is the only verified platform. macOS and Windows are out of v1 scope unless verified later. Bun is unverified and not assumed.
- Podman-gated and host-gated checks await verification on a Podman 5.x host.
- Licence: AGPL-3.0-only (
LICENSE).
Commands
Requires Node.js 22.13.0 or later (engines in package.json). CI runs Node 22.x and 24.x (.github/workflows/ci.yml). Realm does not install or upgrade Podman.
npm ci: installs frompackage-lock.json.npm run typecheck:tsc -p tsconfig.json --noEmit.npm run lint:eslint ., configured byeslint.config.js.npm test: compiles with tsc, then runsnode:testover every compiled test underdist/test/. That glob includesdist/test/integration/, so the Podman-gated suites also run here and skip when Podman 5.x is absent.npm run test:integration: compiles, then runsdist/test/integration/*.test.js. Podman-gated tests skip with a stated reason:PODMAN_UNSUPPORTED_VERSIONwhen Podman is older than 5.x, orPODMAN_MISSINGwhen Podman is absent.npm run test:scripts: runsnode:testoverscripts/**/*.test.mjs.npm run check:docs: scans the published docs for host-local absolute paths, then runs the AGENTS.md and CLAUDE.md sync check.npm run build: compiles withtsc -p tsconfig.jsonintodist/.
Every gate must pass before a change is reviewed (CONTRIBUTING.md).
Layout
src/: strict TypeScript.npm run buildemits it todist/src/.cli/main.ts: entry for therealmCLI.daemon/: control socket (channel.ts), client, daemon,ensure.ts(starts the daemon once and waits for it), andmain.ts, the daemon entry.omp/: Omp plugin logic (plugin.ts) and its entry (extension.ts).mcp/: MCP stdio server (server.ts).acp/: ACP agent (agent.ts) and its stdio entry (stdio.ts).realm/: composition root (compose.ts) that wires the adapters into the controller and dispatcher.lifecycle/:controller.ts(the lifecycle controller) andmutation-gate.ts.tools/: the single shared tool dispatcher (dispatch.ts) and the workspace file handlers (workspace.ts).runtime/: Podman probe and version check, libpod client and routes, OpenShell adapter, hardening verifier, egress rules, session execution, the AgentOS port (no concrete driver is bound yet), and runtime config.session/: session record store, state-directory paths, and the startup reaper (reap.ts).anda/: Anda Engine HTTP bridge (client.ts) and the version-shape check (shape.ts).fs/: canonical paths, root allowlist, credential-path denial, advisory write locks, atomic writes, and read, list, glob, and write.audit/: redacted JSONL audit log.doctor/: prerequisite checks behindrealm doctor.contract/: tool and session-record schemas and the schema validator (validate.ts).core/: frozen shared contracts: states and the state machine, status labels, policy loading withpolicy.schema.json, the typed error catalogue (errors.ts), the event bus, ports, backoff, andwithTimeout(timeout.ts).
test/:node:testsuites by area, largely mirroringsrc/.test/integration/holds the Podman-gated suites, andtest/support/holds shared fakes.scripts/: plain ESM.mjsusing Node built-ins only.scripts/check/backsnpm run check:docsandnpm run test:scripts.scripts/release/backs the release job (next-version.mjs,sync-version.mjs,changelog.mjs).docs/:integration/(integration and decision notes, such asruntime-decision.mdandanda-decision.md),hosts/snippets/(host config snippets),policy-reference.md, andspecs/realm-spec.xml(the product spec)..planning/: GSD-managed planning state. See Planning artifacts.release/milestone.json: the milestone and its minor number, which set the release line.assets/brand/: logo and banner artwork..github/:workflows/ci.yml(verify and release jobs),PULL_REQUEST_TEMPLATE.md, andISSUE_TEMPLATE/.- Repository root:
package.json,package-lock.json,tsconfig.json,eslint.config.js,README.md,CHANGELOG.md,CONTRIBUTING.md,SECURITY.md,LICENSE, andNOTICE.dist/,node_modules/, andcoverage/are git-ignored build and install output.
Conventions
- TypeScript in strict mode, ESM only (
"type": "module").tsconfig.jsonenablesstrict,noUncheckedIndexedAccess,exactOptionalPropertyTypes, andnoUnusedLocals. Public APIs are typed and documented. - Tests use
node:testand assert observable behaviour. No source-text tests: a test must not assert on the text of a module. - Errors are
RealmErrorvalues (src/core/errors.ts). Each carries a machine-readablecodefromERROR_CODES, a human-readablereason, and aretryableflag. An optionalcauseCodeis itself a catalogue code, so raw runtime text never enters an error. - Every async boundary has a timeout (
withTimeout,src/core/timeout.ts). - No silent catch blocks, except the named exceptions under QUAL-01 in
.planning/REQUIREMENTS.md. ESLint'sno-emptyrule rejects empty catch blocks. process.envis read only at the entry edges:src/cli/main.ts,src/daemon/main.ts, andsrc/omp/extension.ts. Other modules take their environment as an argument.- No suppression comments.
eslint.config.jsbans@ts-ignore,@ts-expect-error, and@ts-nocheck; fix the cause instead. - No new npm dependency unless the pull request records a justification, a licence check, and a maintenance check (
CONTRIBUTING.md). Scripts use Node built-ins only. - Commit subjects start with a Conventional Commit type (
feat,fix,perf,refactor,docs,test,build,ci,chore, orsecurity), with an optional scope. The changelog groups entries by type. - No host-local absolute paths in committed files: no home-directory, temporary-directory, or Users-directory paths.
npm run check:docsenforces this for the published docs. - Settled runtime decisions (
docs/integration/runtime-decision.md). Change them only through a new recorded decision:- The OpenShell gateway runs on the host, and its Podman driver creates the session container. Do not nest OpenShell inside the Realm container.
- One container per session. The daemon owns sessions. A surface attaches by connecting to the control socket and calling
up, which is idempotent. There is no attach or detach protocol. - The sandbox lasts until
realm down. A host shutdown closes that host's client and never sendsdown. - The OpenShell CLI is pinned to the 0.1.2 verbs. Re-verify the pin on any upgrade.
- Anda consumes Realm over MCP (
docs/integration/anda-decision.md, section 7). Realm reaches Anda over its HTTP API, with no shim.
Versioning and release
- The release line is
0.<milestone minor>.<part>.release/milestone.jsonholds the minor: v1.0 is minor 1, so its line is0.1.x. - Every green push to
mainpublishes the next part:0.1.0first, then0.1.1, and so on.scripts/release/next-version.mjsderives the next part from the latestv0.*tag. A milestone minor that is behind the latest tag fails the release. - A new milestone starts in a pull request that sets the next minor number in
release/milestone.json. Its first release is<minor>.0. - The release job owns the version in
package.json, the version inpackage-lock.json, andCHANGELOG.md. Pull requests never edit those three. - The release job skips a version whose tag already exists on origin. Otherwise it tags
v<version>, packs the npm tarball, and creates the GitHub release (.github/workflows/ci.yml).
Merge and release flow
- Branch from
main. Changes reachmainthrough a pull request; the release job is the only other writer, pushing its release commit and tag. - Open a pull request into
main. Complete.github/PULL_REQUEST_TEMPLATE.md: requirement IDs, the gate checklist, and risk and rollback. ci.ymlmust be green. Its verify job runs every gate on Node 22.x and 24.x.- The Greptile review must reach 5 out of 5 with no open comments before merge.
- Merge only through the ultrathink ship flow. Never run
gh pr mergefrom a shell. - Never force-push
main. Never rewrite history without an explicit user decision. - A green push to
mainruns the release job after verify. See Versioning and release.
Planning artifacts
.planning/is managed by the GSD workflow. Change it only through GSD commands, never by hand.- Start file-changing work through a GSD command (
.agents/GEMINI.md):/gsd-quickfor small fixes, documentation updates, and ad-hoc tasks;/gsd-debugfor investigation and bug fixing;/gsd-execute-phasefor planned phase work. Do not make repository edits outside a GSD workflow unless the user explicitly asks you to bypass it. .planning/REQUIREMENTS.mdholds the requirement IDs (for exampleCORE-05orFS-04) that a pull request names..planning/PROJECT.mdholds constraints and status,.planning/ROADMAP.mdthe phases, and.planning/STATE.mdthe workflow state.- The documentation site publishes
.planning/read-only.
Documentation and site
- The published entry points are
README.mdandCHANGELOG.md. The npm package ships them withLICENSE,NOTICE, anddist/src(filesinpackage.json). - Documentation is published as a GitHub Pages site (
homepageinpackage.json;CHANGELOG.md). After a release, the release job dispatches.github/workflows/pages.ymlif that file exists (ci.yml). - Integration notes under
docs/integration/cite each official source's URL and read date. Read the official documentation and record it there before writing integration code against it. Record anything unverified as an open question, not as a fact. docs/specs/realm-spec.xmlis the authoritative product spec. It is read-only: do not modify it.- Update the docs in the same pull request as the change they describe.
Progressive updates
- Update this file in the same pull request when a convention, command, or layout changes. A new or moved path is a layout change.
- CI runs
npm run check:docs. It fails unless the Commands, Versioning and release, and Merge and release flow headings each appear exactly once in this file, and unless CLAUDE.md contains the@AGENTS.mdline and no Commands heading. - Keep all ten
##headings.CHANGELOG.mdrefers to "Versioning and release" by name.
Safety and high-risk paths
- Human review is required before merge for
.github/workflows/**,release/**,scripts/release/**,LICENSE, andNOTICE. - The sandbox is a security boundary. Policy violations fail closed when the policy mode is fail-closed, and a file-mutating tool must never run outside the realm when the active policy requires the realm. The default mode is advisory, with a visible warning; fail-closed is the documented opt-in for containment deployments.
- No host secrets are injected into the sandbox by default, and no secrets belong in the repository, images, or logs. There is no telemetry that sends data off the machine.
- Podman runs rootless only. Never use privileged containers, and never mount a host Docker or Podman socket into a container.
- The control socket is user-only: its directory is mode 0700 and the socket is mode 0600.
- Report suspected vulnerabilities privately through GitHub private vulnerability reporting (
SECURITY.md). Do not open a public issue, pull request, or discussion for one, and do not put secrets in the report. Only the 0.1.x line is supported. .envand.env.*files are git-ignored (.gitignore).