See it in action
This page shows the Claxedo package family as one composable app stack: run terminal coding agents, expose them to users or teams, and keep the product surface stable while swapping harness, workspace, deployment, and extension backends underneath.
Full app in a few pieces
Section titled “Full app in a few pieces”| Piece | Responsibility |
|---|---|
| Product UI | Workspace/session/process/file/browser experience. |
| Product control plane | Auth, org policy, credentials, workspace routing, extension policy, audit, team access. |
| Workspace Runtime | Per-workspace execution host. |
| Agent Extensions | Package discovery, desired/lock state, policy, materialization, runtime replay. |
| Agent SDK Runtime | Runtime facade, harness factories, stores, turns, events, capability checks. |
| Agent Event Runtime | Canonical event model and projections. |
| Workspace Relay | Remote access to cloud or user-hosted runtime hosts. |
| Claxedo MCP | Tool layer for MCP clients to orchestrate runtime/server APIs. |
Compose a local runtime
Section titled “Compose a local runtime”Install the published packages
Terminal window npm install @claxedo/workspace-runtime @claxedo/agent-sdk-runtime @hono/node-server@hono/node-serverserves the runtime’s Hono app on a Node socket — the quickstart imports it directly.Start and configure a Workspace Host
Save this as
host.tsnext to the project directory the agent should work on. It boots the host, then applies the harness, model, auth, MCP config, and Agent Extension desired state in code viaruntime.host.apply():import { createWorkspaceRuntimeApp, loopbackWorkspaceRuntimeExposure } from "@claxedo/workspace-runtime"import { serve } from "@hono/node-server"const runtime = createWorkspaceRuntimeApp({exposure: loopbackWorkspaceRuntimeExposure(),})const server = serve({ fetch: runtime.app.fetch, port: 4096, hostname: "127.0.0.1" })runtime.injectWebSocket(server)await runtime.host.apply({version: 2,harnesses: [{ id: "codex", access: "native" }],model: "default",auth: {},mcp: {},agent_extensions: { version: 1, installs: [] },workspaceHarnessEnabled: true,})console.log("workspace-runtime ready on http://127.0.0.1:4096")Run it and verify
Terminal window npx tsx host.tsThen, in a second terminal, hit the health route:
Terminal window curl http://127.0.0.1:4096/api/wr/health{"ok":true,"status":"ready","service":"workspace-runtime","routeAuthBoundary":"loopback-only","serviceExposure":{"source":"loopback","access":"private"},"exposure":{"kind":"loopback"}}Create a session and send a prompt
Your UI calls one session surface. The host starts a turn through the
AgentRuntimefacade and streams normalized events back. Run these from any HTTP client or a second script (e.g.npx tsx session.ts):const session = await fetch("http://127.0.0.1:4096/session", {method: "POST",headers: { "content-type": "application/json" },body: JSON.stringify({ title: "Fix the failing tests" }),}).then((res) => res.json())await fetch(`http://127.0.0.1:4096/session/${session.id}/message`, {method: "POST",headers: { "content-type": "application/json" },body: JSON.stringify({parts: [{ type: "text", text: "Find and fix the failing tests." }],}),})Use the same host for processes, files, and events
await fetch("http://127.0.0.1:4096/api/wr/process/start-all", { method: "POST" })const files = await fetch("http://127.0.0.1:4096/file/all").then((res) => res.json())const events = new EventSource("http://127.0.0.1:4096/global/event")events.onmessage = (event) => console.log(JSON.parse(event.data))
Your UI does not need a separate streaming implementation for Claude ACP, Codex ACP, Cursor ACP, Claude SDK, Codex app-server, and OpenCode. When the harness config changes, the runtime disposes the old adapter and creates the matching one.
Attach through Relay
Section titled “Attach through Relay”When the runtime runs in a cloud VM or on a user’s machine behind a tunnel, attach it to Relay with env-driven options:
import { startServer } from "@claxedo/workspace-runtime"import { workspaceRelayRuntimeOptionsFromEnv } from "@claxedo/workspace-runtime/relay"
const port = Number(process.env.WORKSPACE_RUNTIME_PORT ?? 3002)
startServer(port, await workspaceRelayRuntimeOptionsFromEnv(process.env, port))See @claxedo/workspace-runtime for the full
relay-attachment env contract.