claude-worker

Reference

Server

createWorkerServer options, queue options, and the full route table.

@claude-worker/server is the gateway: HTTP + WebSocket over node:http + ws, a session registry, and optional job-queue routes. Node ≥ 22, real filesystem, no serverless — see Deployment.

createWorkerServer(options)

Returns a WorkerServer: { server, registry, queue?, listen(port, host?), close() }server is the underlying node:http server, queue is set when queue options were provided.

WorkerServerOptions

OptionDefaultEffect
authenticate(req: IncomingMessage) => unknown | Promise<unknown>. Return a truthy principal to accept, null/undefined to reject with 401. Required unless allowUnauthenticated: true — the worker must never be exposed bare. Covers every route including WS upgrades. A principal object may carry allowedProfiles: string[] to scope which profiles the caller can use, and canManageProfiles: true to allow profile create/edit/delete (which also needs profileStore).
allowUnauthenticatedfalseExplicit opt-in to run without auth (local dev only). Without it and without authenticate, createWorkerServer throws.
allowedCwdRootsoffSession cwd (and job session.cwd) must resolve inside one of these roots, else 403. Also constrains the dir of /sdk-sessions (which becomes required). Strongly recommended.
profilesauto-detectWhat sessions run as ({ name, configDir?, engine?, provider?, description?, defaults? }[]). A claude profile’s configDir becomes the session’s CLAUDE_CONFIG_DIR; an engine: 'provider' profile runs the model-agnostic engine instead and needs createEngineRunner. More than one declared → creates must name a profile; exactly one → implicit. Unset: a default profile is auto-created from $CLAUDE_CONFIG_DIR/~/.claude when present; [] disables. See Profiles.
profileStorePersistence for dashboard-managed profiles; setting it mounts POST /profiles and PATCH/DELETE /profiles/:name. createMemoryProfileStore() and createFileProfileStore(path) are bundled; the type is a three-method seam for anything else. Profiles declared in profiles are never stored and never editable over HTTP.
allowedConfigDirRootsoffConfig-dir roots a managed Claude profile may point at (mirrors allowedCwdRoots). Unset means the management routes create provider profiles only — naming a config directory is choosing which credential store a session runs on.
createEngineRunner(ctx: { config, profile, bridge }) => Runner | Promise<Runner> — build the runner for an engine: 'provider' profile. Required if any is declared (the server refuses to start otherwise). Kept as a host hook so the server imports no model SDK and never resolves provider credentials itself; may be async for assembly that has to await (a per-session MCP connect).
buildRunnerConfigidentity(req: CreateSessionRequest) => SessionRunnerConfig — map/patch the incoming request into the runner config (inject env, tool policy, per-skill constraints). Applied to client sessions and queue jobs alike.
basePath'/v1'URL prefix for all routes.
maxBodyBytes1 MiBMax JSON body size.
disableBypassPermissionsfalseServer-wide bypass policy: session/job creates requesting permissionMode: 'bypassPermissions' are rejected (403); the allowDangerouslySkipPermissions pre-authorization is stripped from requests, and the WS set_permission_mode command refuses the mode. Mirrors Claude Code’s permissions.disableBypassPermissionsMode.
requireApiKeyfalseFail closed on subscription credentials: a session initializing with apiKeySource: 'oauth' is terminated with a session_error. Recommended for services and unattended use; off, the server logs a one-time notice instead. See Auth.
listSdkSessionsSDK listSessionsInjectable lister for GET /sdk-sessions (tests).
parkingin-memory storeDeferred execution: { store?, parkDelayMs?, expiredGraceMs?, onError? }. A session that parks on an execution nothing here is running is snapshotted, its runner torn down, and its state kept in the SessionStore. Two ship: MemorySessionStore (default — a park survives a disconnect, not a restart) and createFileSessionStore({ dir }) (one JSON file per park, adopted on listen()). parkDelayMs (2000) is the grace after the last client detaches; expiredGraceMs (60000) is the boot grace for a deadline that lapsed while the process was down. See Deployment and Job queue.
queueoffEnable the job queue routes — see below.

QueueServerOptions

All JobQueue options (minus createRunner/buildRunnerConfig, which the server wires itself — job sessions are ordinary registry sessions and go through the same config hook and auth-provenance watcher as client sessions):

OptionDefaultEffect
maxConcurrency1Concurrent job sessions.
sessionTokenLimitoffToken cap per job session (input+output+cache); exceeding it kills the run.
dailyTokenLimitoffGlobal job-token budget per UTC day; queued jobs held once exhausted.
maxJobDurationMsoffWall-clock cap per run — the watchdog against stuck CLIs. Time parked on a deferred execution doesn’t count: the run isn’t stuck, it’s waiting.
maxParkedDurationMsoffCap on time parked, across all parks of one run. The execution’s own deadline usually fires first and lets the agent adapt; this one fails the job.
killGraceMs5000Grace between interrupting a killed run and force-closing it.
retentionkeep forever{ maxAgeMs, sweepIntervalMs? } — expire terminal jobs (the in-memory adapter otherwise grows unboundedly).
adapterin-memoryQueueAdapter backend. The bundled adapter is single-process, non-persistent.
webhookAttempts3Delivery attempts per webhook event, exponential backoff.
webhookRetryDelayMs500Base delay between webhook delivery retries.
onEventLocal observer for every JobEvent, in addition to per-job webhooks.

See Job queue for semantics.

Routes

Default basePath: '/v1'; every route goes through authenticate.

RouteWhat it does
GET /v1/sessionsList sessions (SessionInfo[]).
POST /v1/sessionsCreate a session (CreateSessionRequest; cwd required, 403 outside allowedCwdRoots; profile required when several are declared, 403 outside the caller’s allowedProfiles). 201 with the SessionInfo.
GET /v1/sessions/:idSession info. A parked session answers from its snapshot, with status: 'parked'.
DELETE /v1/sessions/:idClose and remove the session — including a parked one, whose stored state is dropped so a late execution result can no longer wake it.
GET /v1/sessions/:id/files / …/files/<path>List the session’s scratch-filesystem deliverables (ListSessionFilesResponse) / download one (attachment disposition, nosniff). 404 for engines without a VFS (Claude sessions). Served from the snapshot while parked.
POST /v1/executions/:executionId/resultDeliver a deferred execution’s result (SubmitExecutionResultRequest). Wakes the parked session, applies it to the agent loop, answers { applied, sessionId }. Idempotent by executionId — a duplicate, or one racing the watchdog, answers applied: false. 404 = unknown id, or a session outside the caller’s allowedProfiles.
WS /v1/sessions/:id/ws?afterSeq=nAttach: attached frame (protocol version + snapshot), replay of events past n, then live events; accepts SessionCommand frames.
POST /v1/sessions/:id/permissions/:requestIdResolve a pending approval over REST (ResolvePermissionRequest). 404 = unknown, already resolved, or expired.
GET /v1/profilesList profiles (ListProfilesResponse), filtered to the caller’s allowedProfiles. Store-backed ones carry managed: true; canManage says whether this caller may create more.
POST /v1/profilesCreate a managed profile (CreateProfileRequest). 404 without a profileStore, 403 without canManageProfiles on the principal, 409 if the name is taken, 400 if the profile is one startup would have refused.
PATCH /v1/profiles/:nameMerge into a managed profile (UpdateProfileRequest). The name is the route — profiles cannot be renamed, since sessions and jobs are pinned to it. 403 for a startup-declared profile.
DELETE /v1/profiles/:nameDelete a managed profile (204). 403 for a startup-declared one.
GET /v1/profiles/:nameOne profile plus a fresh view-only config snapshot (GetProfileResponse: settings.json highlights, memory/skills/agents/commands — env var names only, never values). Same allowedProfiles scoping.
GET /v1/sdk-sessions?dir=…&limit=…&offset=…List the Agent SDK’s on-disk sessions to offer resume. With allowedCwdRoots set, dir is required and must be inside the roots.
GET /v1/jobs / POST /v1/jobsList jobs / schedule one (CreateJobRequest; session.cwd + session.prompt required; session.profile follows the same rules as session creation). Queue-configured servers only, else 404.
GET /v1/jobs/:id / DELETE /v1/jobs/:idJob info / cancel.
GET /v1/queueQueue stats (QueueStats).
WS /v1/queue/wsOne-way live stream: queue_attached, then job_event + refreshed queue_stats frames. No replay — re-list jobs on (re)connect.

Anthropic credentials

The server implements no Anthropic auth: the SDK/CLI resolves credentials from the operator’s environment (ANTHROPIC_API_KEY, Bedrock/Vertex, or a personal claude login). Each session’s provenance surfaces as apiKeySource on SessionInfo and the system_init event — the full posture, including requireApiKey and the contributor red lines, is in Auth & Anthropic’s terms.