@claxedo/workspace-runtime
@claxedo/workspace-runtime is the per-workspace host service — one process per workspace. It owns workspace host wiring around the runner adapters (which live in @claxedo/agent-sdk-runtime), the PTY and process managers, the file/diff/git surface, and the relay-host tunnel to @claxedo/workspace-relay. UI never imports this package directly; browsers talk to the control plane, which proxies to a runtime instance.
Install
Section titled “Install”npm install @claxedo/workspace-runtimepnpm add @claxedo/workspace-runtimebun add @claxedo/workspace-runtimeQuickstart
Section titled “Quickstart”Every deployment shape requires an explicit exposure declaration. The simplest is a loopback runtime over a directory:
import { startServer, loopbackWorkspaceRuntimeExposure,} from "@claxedo/workspace-runtime"
await startServer(4200, { exposure: loopbackWorkspaceRuntimeExposure(),})To back the runtime’s relay boundary with a custom identity provider, pass a TokenVerifier to the relay-host middleware:
import { Hono } from "hono"import { createStaticTokenVerifier, type RelayHostVerifierClaims,} from "@claxedo/workspace-relay-protocol"import { createRelayHostAuthMiddleware, type RelayHostAuthOptions,} from "@claxedo/workspace-runtime/relay"
// `key` is the relay's JWT verification key (a PEM public key or a JWKS// resolver). The options type requires it, but it is bypassed whenever// `verifier` is set.declare const relayKey: RelayHostAuthOptions["key"]
const now = Math.floor(Date.now() / 1000)
const verifier = createStaticTokenVerifier<RelayHostVerifierClaims>({ tokens: { "tok-tenant-1": { subject: "u1", scopes: ["workspace:write"], // The middleware re-validates the verifier's claims against the // relay-host token contract. Every field below is required — a // missing or mismatched one rejects the request. claims: { iss: "workspace-relay", // fixed relay-host token issuer aud: "workspace-host-service", // fixed relay-host token audience sub: "u1", org_id: "org_1", workspace_id: "ws_1", // must equal the middleware's workspaceId host_id: "host_1", // must equal the middleware's hostId access: "cloud", // "cloud" + "cloud-vm", or backing: "cloud-vm", // "user-hosted" + "local-worktree" exp: now + 60, iat: now, jti: "jti-1", }, }, },})
const app = new Hono()app.use("*", createRelayHostAuthMiddleware({ key: relayKey, workspaceId: "ws_1", hostId: "host_1", verifier,}))The verifier is only the crypto/introspection authority. The middleware still validates its output into RelayHostTokenClaims — issuer, audience, sub, org_id, workspace_id, host_id, the access/backing pair, exp, iat, and jti are all mandatory, and the workspace/host ids must match the middleware’s own. Note that role is not a relay-host claim (it belongs to the relay’s Runtime Access Token).
Key capabilities
Section titled “Key capabilities”- Supported shapes — loopback, private-VM, relay-attached, embedded Hono app, and low-level host object. They share the
/api/wr/*route surface but not the same trust boundary. - Subpaths —
/client,/host,/exposure,/relay,/config,/routes,/testingfor focused, lower-level helpers. - Routes — health, capabilities, config apply, events, files, diff/git, PTY (WebSocket), and process surfaces, each gated by exposure-dependent runtime auth.
- Durability —
RuntimeStoretreats per-session JSONL journals as the source of truth with SQLite as a derived projection. - Path containment — session/file/PTY routes are pinned to the workspace target; absolute paths,
..escapes, null bytes, and out-of-workspace symlinks are rejected.
The root surface is checked against docs/api-manifest.json and does not export control-plane clients or agent-extension materializers — those compose outside the OSS runtime boundary.
Full API
Section titled “Full API”See the README on GitHub for the full public-surface table, route table, event contract, relay-attachment env vars, and lifecycle sequence.