npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@oncell/sdk

v0.6.2

Published

OnCell SDK — per-user sandboxed environments with persistent storage for AI agents

Downloads

1,134

Readme

@oncell/sdk

TypeScript client for oncell.ai — the cloud where AI agents live.

npm install @oncell/sdk

The model

Two objects, and one you never touch.

| | What it is | |---|---| | Project | Owns model credentials and quota. Many agents share one. | | Agent | The unit you address. Identity + tools + skills. | | Cell | The running instance. Created and recycled by the platform; its ID is internal and you never handle it. |

An agent is a definition; a cell is that definition running. You describe the agent and operate on the agent — the platform decides when an instance needs to exist.


Quick start

import { OnCell } from "@oncell/sdk";

const oncell = new OnCell({ apiKey: process.env.ONCELL_API_KEY });

// A project owns the credentials your agents draw on.
const project = await oncell.projects.create({ name: "prod" });
await oncell.projects.addCredential(project.projectId, {
  value: process.env.ANTHROPIC_TOKEN!,
  label: "seat-1",
});

// An agent: identity, the tools it can touch, the skills it knows.
const agent = await oncell.agents.create({
  name: "builder",
  projectId: project.projectId,
  identity: { instructions: "You build and ship web apps." },
  capabilities: ["workspace", "shell", "git"],
});

// Run it.
await oncell.agents.start({ agentId: agent.agentId });
await oncell.agents.startService(agent.agentId, { cmd: "node server.js" });

const { stdout } = await oncell.agents.exec(agent.agentId, { cmd: "npm test" });

Agents

Defining

await oncell.agents.create({ name, projectId, identity, capabilities, skills });
await oncell.agents.list();
await oncell.agents.get(agentId);
await oncell.agents.update(agentId, { identity });  // new version; running instances keep theirs
await oncell.agents.destroy(agentId);               // removes the agent AND its state

Identity is the base prompt, model, and budgets. Capabilities are what the agent may touch — prebuilt names (memory, db, files, shell, secrets, ask_human, agents, cells, schedule) or presets (workspace, git). Skills are a prompt for specific work plus the tools that work uses, loaded when relevant.

Capabilities and skills are fields on an agent, not resources — there is nothing to CRUD.

Running

await oncell.agents.start({ agentId, tier, snapshotKey });
await oncell.agents.status(agentId);
await oncell.agents.pause(agentId);

start() is idempotent: if the agent is already running you get it back, and if it is dormant an instance is materialised from its latest snapshot. There is no resume() — a paused agent has no instance to resume, so you simply start it again.

pause() snapshots and ends the instance. It is routine and non-destructive. destroy() is the permanent one — it removes the snapshots too.

Operating

// Shell — no network here; installs belong in a service command
await oncell.agents.exec(agentId, { cmd, timeoutMs, idempotencyKey });

// The one long-lived process, and what the agent's URL serves
await oncell.agents.startService(agentId, { cmd, env });
await oncell.agents.getService(agentId);
await oncell.agents.stopService(agentId);
await oncell.agents.serviceLogs(agentId, 200);   // first stop when it won't boot

// Files and key-value
await oncell.agents.writeFile(agentId, path, content);
await oncell.agents.readFile(agentId, path);
await oncell.agents.listFiles(agentId, dir);
await oncell.agents.dbSet(agentId, key, value);
await oncell.agents.dbGet(agentId, key);

// Snapshots — build once, start many
const snapshot = await oncell.agents.snapshot(agentId);
await oncell.agents.snapshots(agentId);
await oncell.agents.fork(agentId, "builder-staging");

// Observability — journal and logs work with no live instance
await oncell.agents.journal(agentId);
await oncell.agents.logs(agentId, 100);
await oncell.agents.metrics(agentId);            // live counters; needs a running instance

// Wake later
await oncell.agents.setWake(agentId, new Date(Date.now() + 3_600_000));
await oncell.agents.cancelWake(agentId);

Invariants that will bite you

Enforced by the platform, not this SDK. Each fails in a way that looks like something else.

A service must bind $PORT on 0.0.0.0. The port is injected, never chosen. A hardcoded port or a loopback-only bind is unreachable and reads as "never became ready".

It has ~30 seconds to accept a connection. A cold npm install takes minutes, so an install-then-serve command gets killed. Bind a placeholder on $PORT first, install behind it, then hand off.

exec has no network. Only the service context does. An npm install from exec doesn't error — it hangs, then times out.

Environments are bare. node and npm only: no git, curl, wget, or python. Fetch with node's own fetch.

Your app owns every path. Nothing at the top level is reserved.

Preview traffic is not authenticated by the platform. Apps bring their own auth.


Projects and model credentials

Bind an agent to a project and its service starts with gateway credentials in its env. Coding agents read those natively, so an unmodified agent inside the sandbox can call a model — and it never holds a vendor key.

await oncell.projects.create({ name, authMode, provider });
await oncell.projects.addCredential(projectId, { value, label });
await oncell.projects.credentials(projectId);   // metadata + window counters
await oncell.projects.deleteCredential(projectId, credentialId);

Credentials are write-only — no endpoint returns the secret. To rotate, add the replacement and delete the old one.

Add more than one and the pool earns its keep: the gateway spreads calls across them and routes around whichever is rate-limited. When all are parked you get a retryable 429 with code POOL_EXHAUSTEDqueue and retry; do not surface it as a failure.


Errors

import { OnCellError } from "@oncell/sdk";

try {
  await oncell.agents.exec(agentId, { cmd: "ls" });
} catch (err) {
  if (err instanceof OnCellError && err.status === 429) {
    // retryable — back off
  }
}

Scope failures return 403 with { error: { code: "INSUFFICIENT_SCOPE", required_scope } }.


API keys and scopes

Authenticate with Authorization: Bearer oncell_sk_... (or set ONCELL_API_KEY). Keys created with a scopes array are deny-by-default:

agents:read · agents:write · agents:run · projects:read · projects:write · usage:read · keys:manage · domains:manage · secrets:manage

A key created without a scopes array has full access — always set scopes at creation.


Changelog

0.5.0 — breaking

The client now matches the platform's entity model: project → agent, with the running instance internal.

  • oncell.cells is gone. Cell IDs are internal to the platform, so there was no caller-visible subject for a cells resource. Every operation moved to oncell.agents.* and is addressed by agent ID.
  • Added oncell.agentscreate, list, get, update, destroy for the definition, plus every run-time operation.
  • Removed the customer dimension. customer_id was a business assumption no caller matched: real consumers passed agent-group slugs and project IDs, not customers. The agent is the address.
  • Removed resume(). A paused agent has no instance to resume; start() is idempotent and restores from the latest snapshot.
  • pause() returns void — the instance is gone, so there is nothing to describe.

0.4.0

  • Removed six entity-CRUD methods (dbCreate, dbQuery, dbGetAll, dbGetById, dbUpdate, dbDeleteRecord) that mapped to host RPCs which never existed — every call returned 400 METHOD_UNKNOWN.
  • Removed image, agent, secrets from create; the API silently ignored them, so environments came up bare while looking configured.
  • Added exec, service control, snapshots, fork, wake, and observability — all shipped in the API but absent from this client.

Links

License

Apache-2.0