Package Exports
- @nimbus-sh/worker
- @nimbus-sh/worker/auth
- @nimbus-sh/worker/package.json
- @nimbus-sh/worker/public/_assets/cirrus-plugin-react.bundle.js
- @nimbus-sh/worker/public/_assets/esbuild-0.24.2.wasm
- @nimbus-sh/worker/public/_assets/real-vite-bundle.js
- @nimbus-sh/worker/public/_assets/rollup.wasm
- @nimbus-sh/worker/public/favicon.svg
- @nimbus-sh/worker/public/index.html
- @nimbus-sh/worker/public/s/index.html
- @nimbus-sh/worker/router
- @nimbus-sh/worker/runtime-sync-helper
Readme
@nimbus-sh/worker
The Nimbus runtime package: Durable Object, router, assets, VFS, runtime manager, and facet machinery.
Application code should import the deploy-time API through
@nimbus-sh/sdk/worker. This package is still installed because it carries
the runtime implementation and static assets used by the SDK entrypoint.
Install
npm install @nimbus-sh/sdk @nimbus-sh/worker @nimbus-sh/config
# or
bun add @nimbus-sh/sdk @nimbus-sh/worker @nimbus-sh/configQuickstart
src/index.ts:
import {
NimbusSession,
SupervisorRPC,
NimbusAssetsRPC,
NimbusLoaderRPC,
NimbusLoadedWorker,
NimbusLoadedEntrypoint,
NimbusDurableObjectNamespace,
NimbusDOStub,
CirrusHmrRPC,
createNimbusHandler,
} from '@nimbus-sh/sdk/worker';
import { defineNimbusConfig } from '@nimbus-sh/config';
// Re-export the DO + every RPC class so wrangler's `class_name` lookup +
// `enable_ctx_exports` find them in your Worker's main-module exports.
export {
NimbusSession,
SupervisorRPC,
NimbusAssetsRPC,
NimbusLoaderRPC,
NimbusLoadedWorker,
NimbusLoadedEntrypoint,
NimbusDurableObjectNamespace,
NimbusDOStub,
CirrusHmrRPC,
};
const nimbusConfig = defineNimbusConfig({
sandboxes: {
default: {
root: '/home/user',
runtimes: { preinstall: ['python'], onDemand: true },
tools: { namespace: 'sandbox', kind: 'sandbox' },
},
},
});
export default createNimbusHandler({
sdk: {
remote: true,
config: nimbusConfig,
},
});wrangler.jsonc (use @nimbus-sh/config to generate, or adapt
apps/hosted-demo/wrangler.jsonc):
{
"name": "my-nimbus",
"main": "src/index.ts",
"compatibility_date": "2026-04-01",
"compatibility_flags": ["nodejs_compat"],
"placement": { "mode": "smart" },
"assets": {
"directory": "node_modules/@nimbus-sh/worker/public",
"binding": "ASSETS",
"run_worker_first": ["/api/*", "/s/*", "/new"]
},
"alias": {
"@lifo-sh/ui": "./node_modules/@nimbus-sh/worker/dist/stubs/lifo-ui.js",
"clean-git-ref": "clean-git-ref/lib/index.js",
"is-git-ref-name-valid": "is-git-ref-name-valid/index.js",
"crc-32": "crc-32",
"sha.js": "sha.js",
"pako": "pako", "pify": "pify", "diff": "diff", "diff3": "diff3",
"ignore": "ignore", "readable-stream": "readable-stream",
"simple-get": "simple-get", "minimisted": "minimisted"
},
"durable_objects": {
"bindings": [{ "name": "NIMBUS_SESSION", "class_name": "NimbusSession" }]
},
"migrations": [
{ "tag": "nimbus-v1", "new_sqlite_classes": ["NimbusSession"] }
],
"worker_loaders": [{ "binding": "LOADER" }],
"r2_buckets": [
{ "binding": "NPM_TARBALL_CACHE", "bucket_name": "my-nimbus-npm-cache" },
{ "binding": "NPM_PACKUMENT_CACHE", "bucket_name": "my-nimbus-npm-packument-cache" },
{ "binding": "NIMBUS_RUNTIME_CACHE", "bucket_name": "nimbus-runtime-cache-public" }
]
}Then:
CLOUDFLARE_ACCOUNT_ID=<account-id> npx @nimbus-sh/cli setup cloudflare --name my-nimbus
npx wrangler secret put JWT_SECRET # 32+ hex chars
npx wrangler deployIf setup reports Cloudflare R2 error 10042, enable R2 in the
Cloudflare Dashboard once for the account, then rerun the setup command.
JWT_SECRET is required for token-enforced deployments. Legacy-public
single-tenant demos can set NIMBUS_LEGACY_PUBLIC=1 and rely on URL
possession instead.
Composable API
createNimbusHandler(options) accepts:
{
auth?: { mode?: 'auto' | 'enforce' | 'legacy'; legacyPublic?: boolean };
hooks?: {
onSessionStart?: (ctx) => void | Promise<void>;
onSessionEnd?: (ctx) => void | Promise<void>; // reserved v0.2
};
routes?: (request, env, ctx) => Response | null | Promise<Response | null>;
sdk?: {
remote?: boolean | { enabled?: boolean; basePath?: string; allowLegacy?: boolean };
config?: NimbusConfig;
};
}Custom routes
Routes that return non-null short-circuit Nimbus's router. Use them
for a token-mint endpoint, /healthz, SDK smoke tests, or backend
sandbox jobs.
import { issueNimbusToken } from '@nimbus-sh/sdk/token';
export default createNimbusHandler({
routes: async (req, env) => {
if (new URL(req.url).pathname === '/api/auth/mint' && req.method === 'POST') {
const { tenant, sub } = await req.json();
const token = await issueNimbusToken(env, { tn: tenant, sub });
return Response.json({ token });
}
return null;
},
});Programmatic sandbox route:
import { Nimbus } from '@nimbus-sh/sdk';
export default createNimbusHandler({
routes: async (req, env) => {
const url = new URL(req.url);
if (url.pathname === '/api/run-python') {
const nimbus = Nimbus.fromEnv(env, {
endpoint: url.origin,
sandboxes: {
default: {
root: '/home/user',
runtimes: { preinstall: ['python'], onDemand: true },
},
},
});
const box = nimbus.sandbox('api-job-1', { tenant: 'api', subject: 'python' });
const result = await box.runCode('print(2 + 2)', {
language: 'python',
install: 'ifMissing',
});
return Response.json(result);
}
return null;
},
});Remote SDK API:
export default createNimbusHandler({
sdk: {
remote: true,
config: nimbusConfig,
},
});Remote calls use POST /api/nimbus/v1/sandboxes/<id>/rpc internally.
Applications normally call it through Nimbus.connect({ endpoint, token, config }). The route requires a valid Nimbus JWT and sandbox:use scope.
For long-running app servers, start an explicit long-running process and expose the virtual port:
await box.files.write('/home/user/app/server.js', serverSource);
await box.startProcess('node --watch /home/user/app/server.js');
const port = await box.ports.expose(3000);Session Agent
The bundled session shell includes an Agent surface inside the editor
workspace. The route lives inside the session Durable Object under
/api/agent/*; the stable Cloudflare OAuth callback is
/api/nimbus/oauth/callback.
The agent can use the same session tools as the SDK: shell exec, files, runtime installs, long-running processes, logs, and preview ports. Model calls use the AI SDK with Cloudflare Workers AI's OpenAI-compatible endpoint and an optional AI Gateway name.
For user-owned quota, create a Cloudflare OAuth client with response type
Code, grant type Authorization Code, token authentication method None,
and redirect URL https://<your-nimbus-host>/api/nimbus/oauth/callback.
Nimbus uses PKCE and stores user OAuth tokens only in encrypted HttpOnly,
Secure, SameSite=Lax browser cookies scoped to the session URL.
Non-secret values can be generated with @nimbus-sh/config or written as
vars:
| Var | What |
|---|---|
NIMBUS_CF_OAUTH_CLIENT_ID |
Cloudflare OAuth client ID. |
NIMBUS_CF_OAUTH_SCOPES |
Space-delimited Cloudflare OAuth scope IDs. |
NIMBUS_CF_OAUTH_REDIRECT_URI |
Optional callback override; default is <origin>/api/nimbus/oauth/callback. |
NIMBUS_CLOUDFLARE_ACCOUNT_ID |
Owner-token fallback account ID. |
NIMBUS_AGENT_MODEL |
Workers AI model, default @cf/moonshotai/kimi-k2.6. |
NIMBUS_AGENT_GATEWAY_ID |
AI Gateway name, default default. |
Secrets stay in Workers secret storage:
npx wrangler secret put NIMBUS_AGENT_COOKIE_SECRET
npx wrangler secret put NIMBUS_CLOUDFLARE_API_TOKENHooks
export default createNimbusHandler({
hooks: {
onSessionStart: ({ sessionId, tenantSegment, request }) => {
console.log(`[${tenantSegment}] session ${sessionId} attached from ${request.headers.get('cf-connecting-ip')}`);
},
},
});Auth modes
| Mode | Meaning |
|---|---|
'auto' (default) |
Verify token when JWT_SECRET is set AND NIMBUS_LEGACY_PUBLIC is unset. Otherwise legacy-public. |
'enforce' |
Always verify token; fail closed if JWT_SECRET is missing. |
'legacy' |
Never verify; all requests route to the single legacy:public:_ tenant. Use only for single-tenant demos. |
Subpath exports
| Subpath | What |
|---|---|
@nimbus-sh/sdk/worker |
Public Worker embedder API: NimbusSession, RPC classes, createNimbusHandler, auth helpers. |
@nimbus-sh/worker |
Runtime implementation package used by the SDK entrypoint. |
@nimbus-sh/worker/router |
Runtime router implementation and hook types. |
@nimbus-sh/worker/auth |
Runtime auth implementation re-exported by @nimbus-sh/sdk/token. |
Required bindings
Every binding is load-bearing — see apps/hosted-demo/wrangler.jsonc or
@nimbus-sh/config for the canonical set:
NIMBUS_SESSION(Durable Object) — per-session SQLite stateLOADER(Worker Loader) — dynamic-isolate spawning for npm + vite + facetsNPM_TARBALL_CACHE+NPM_PACKUMENT_CACHE+NIMBUS_RUNTIME_CACHE(R2)ASSETS— serves the xterm shell + lazy-loaded WASM/JS blobsJWT_SECRET(secret) — HS256 signing key for token-enforced deployments
Status
v0.1 — first public release. SemVer not yet stable; expect breaking changes through v0.x. Issues + PRs welcome.
MIT. © Ashish Kumar Singh + contributors.