Programmatic SDK Guide
(Available from v0.2.0)
@nogoo9/no-crd provides a composable, type-safe SDK for developers to manage containerized workspaces programmatically in Bun, Deno, or Node.js.
Unlike the MCP server entry point, importing the SDK does not trigger automatic server runs or side effects, making it perfect for custom microservices, pipeline agents, or orchestration control loops.
⚙️ Initializing the Context
Every SDK function requires a K8sContext instance, which encapsulates the Kubernetes client configuration and API endpoints.
import { KubeConfig } from "@kubernetes/client-node";
import { initK8sContext } from "@nogoo9/no-crd";
// Load default local/cluster configuration
const kc = new KubeConfig();
kc.loadFromDefault();
// Initialize the API context
const k8sCtx = initK8sContext(kc);You can pass a custom KubeConfig (for instance, to dynamically authenticate EKS or GKE cluster endpoints based on request headers) or instantiate a pre-configured context using your own Kubernetes configuration details.
🛠️ Spawning Workspaces
The SDK exports the spawnWorkspace function, which replicates the spawner tool lifecycle: resolving ConfigMap templates, validating context requirements, and submitting the workspace pod.
import { spawnWorkspace } from "@nogoo9/no-crd";
const result = await spawnWorkspace(k8sCtx, {
id: "agent-session-42",
templateRef: "nogoo9/default-agent-workspace", // Format: namespace/name or name
namespace: "nogoo9",
context: {
"S3_BUCKET": "my-agent-bucket",
"S3_FOLDER": "session-42"
}
});
console.log(`Successfully spawned pod: ${result.podName}`);⏹️ Stopping Workspaces
To delete and clean up a running workspace, use stopWorkspace:
import { stopWorkspace } from "@nogoo9/no-crd";
const result = await stopWorkspace(k8sCtx, {
id: "agent-session-42",
namespace: "nogoo9"
});
console.log(`Teardown status: ${result.status}`); // Returns 'terminating'📋 Listing Workspaces
To query all active agent workspaces running within a target namespace:
import { listWorkspaces } from "@nogoo9/no-crd";
const result = await listWorkspaces(k8sCtx, {
namespace: "nogoo9"
});
for (const ws of result.workspaces) {
console.log(`- ID: ${ws.id}, Pod: ${ws.name}, Status: ${ws.status}`);
}🌐 Building a Custom HTTP Spawner API (Hono Example)
Below is a complete, production-ready example of how to wrap the Programmatic SDK inside a Hono microservice running on Bun or Node.js:
import { Hono } from "hono";
import { KubeConfig } from "@kubernetes/client-node";
import {
initK8sContext,
spawnWorkspace,
stopWorkspace,
listWorkspaces
} from "@nogoo9/no-crd";
const app = new Hono();
// Load client configurations
const kc = new KubeConfig();
kc.loadFromDefault();
const k8sCtx = initK8sContext(kc);
// GET /api/workspaces - List active workspaces
app.get("/api/workspaces", async (c) => {
try {
const list = await listWorkspaces(k8sCtx, {
namespace: "nogoo9"
});
return c.json(list);
} catch (err: any) {
return c.json({ error: err.message }, 500);
}
});
// POST /api/workspaces/spawn - Spawn a new agent workspace
app.post("/api/workspaces/spawn", async (c) => {
const body = await c.req.json();
const { workspaceId, templateName, s3Folder } = body;
if (!workspaceId || !templateName) {
return c.json({ error: "Missing workspaceId or templateName" }, 400);
}
try {
const result = await spawnWorkspace(k8sCtx, {
id: workspaceId,
templateRef: templateName,
namespace: "nogoo9",
context: {
"S3_FOLDER": s3Folder || `session-${workspaceId}`,
"S3_BUCKET": "my-agent-workspaces"
}
});
return c.json({
success: true,
message: `Workspace spawned successfully`,
podName: result.podName
});
} catch (err: any) {
return c.json({ error: err.message }, 500);
}
});
// POST /api/workspaces/stop - Stop and delete a workspace sandbox
app.post("/api/workspaces/stop", async (c) => {
const { workspaceId } = await c.req.json();
if (!workspaceId) {
return c.json({ error: "Missing workspaceId" }, 400);
}
try {
const result = await stopWorkspace(k8sCtx, {
id: workspaceId,
namespace: "nogoo9"
});
return c.json({
success: true,
message: `Workspace stopped successfully`,
status: result.status
});
} catch (err: any) {
return c.json({ error: err.message }, 500);
}
});
export default {
port: 8080,
fetch: app.fetch
};