oncell.ai

Documentation

Ship your coding agent to every customer. Each customer gets an isolated cell with their repo cloned, indexed, and ready. Your agent codes inside their cell. Their source code never leaves it.

Quickstart

Get from zero to a deployed coding agent in under 5 minutes. Your customers will each get their own isolated cell with their repo, index, and agent runtime.

1. Install the CLI

npm install -g oncell
oncell login

2. Write your agent

import { Agent, Context } from "oncell";

export class CodingAgent extends Agent {

    cell = { compute: "4cpu-8gb", storage: "50gb" };

    async setup(ctx: Context) {
        await ctx.shell("color:#5cdb7f">`git clone ${ctx.config.repoUrl} /work`);
        await ctx.index("/work");
    }

    async task(ctx: Context, instruction: string) {
        const files = await ctx.search(instruction);
        const plan = await ctx.llm(instruction, { context: files });

        for (const step of plan.steps) {
            await ctx.shell(step.command);
            const result = await ctx.shell("npm test");
            if (result.failed) {
                const fix = await ctx.llm("color:#5cdb7f">`Fix: ${result.error}`);
                await ctx.shell(fix.command);
            }
        }

        await ctx.shell("git add -A && git commit -m '" + instruction + "'");
        await ctx.shell("git push");
        return { status: "done" };
    }
}

3. Deploy

Terminal
oncell deploy

That's it. Your coding agent is live. Each customer who connects gets their own cell — repo cloned, codebase indexed, agent ready to code.

Core Concepts

OnCell has three primitives: Agents, Cells, and Customers.

Agent
Your coding agent. Clones repos, edits code, runs tests, pushes PRs.
Cell
An isolated environment per customer. Their repo, index, and runtime inside.
Customer
An end-user of your product. Gets their own cell with their codebase.
CodingAgent (your code)
  ── deployed to oncell
        ── Customer connects
              ── Cell created
                    ── Repo cloned to local NVMe
                    ── Codebase indexed for search
                    ── Agent starts coding inside the cell

Cells

A cell is the atomic unit of oncell. For coding agents, each cell contains the customer's cloned repo on NVMe, a vector index of their codebase, a durable agent runtime, and an isolated test environment. One cell per customer.

Cell configuration

export class MyAgent extends Agent {
    cell = {
        compute: "4cpu-8gb",         // CPU and RAM allocation
        storage: "50gb",              // NVMe storage per cell
        gpu: "L4",                    // Optional GPU(L4, A10G)
        packages: ["nodejs", "python3", "git"],  // System packages
        idleTimeout: "30m",           // Auto-pause after inactivity
        network: {
            egress: "blocked",        // Default: no outbound
            allow: [                  // Allowlisted domains
                "api.openai.com",
                "github.com",
                "registry.npmjs.org"
            ]
        }
    };
}

Available sizes

SizeCPURAMBest for
2cpu-4gb24 GBSmall repos, simple agents
4cpu-8gb48 GBMost coding agents (recommended)
8cpu-16gb816 GBLarge repos, heavy test suites
8cpu-32gb832 GBMonorepos, parallel test runs
8cpu-32gb+L48+GPU32 GBLocal model inference + coding

Cell lifecycle

Cell states:

  CREATING    ACTIVE    PAUSING    PAUSED
                                        
                  └──── WAKING ←─────────┘

  ACTIVE:   Agent running. Full compute allocated.    $0.05/hr
  PAUSED:   Agent idle. Only storage persists.        $0.001/hr
  WAKING:   Resuming from pause.                      ~200ms

Automatic transitions:
  Active  Paused:  after idle_timeout (default: 30 min)
  Paused  Active:  on next API call (automatic, ~200ms)

Agents

An agent is a class that extends Agent. It defines what the cell looks like (cell), and what the agent does (setup and your custom methods).

Agent lifecycle

import { Agent, Context } from "oncell";

export class MyAgent extends Agent {

    cell = { compute: "2cpu-4gb", storage: "10gb" };

    async setup(ctx: Context) {
        // Called ONCE when a new customer is created.
        // State persists across all future calls.
        await ctx.shell("npm install pandas");
        await ctx.upload("data/", { fromUrl: ctx.config.dataUrl });
        await ctx.index("data/");
    }

    async analyze(ctx: Context, question: string) {
        // Called every time the customer sends a request.
        const relevant = await ctx.search(question);
        const code = await ctx.llm("color:#5cdb7f">`Write code to answer: ${question}`, { context: relevant });
        const result = await ctx.shell("color:#5cdb7f">`node -e '${code}'`);
        return { answer: result.stdout };
    }
}

Every public method (except setup) becomes an API endpoint that customers can call.

Context API

The ctx object is passed to every agent method. It's your interface to the cell's capabilities.

ctx.shell(cmd)Run a shell command inside the cell
ctx.llm(prompt, opts?)Call an LLM (OpenAI, Anthropic, or local)
ctx.search(query, topK?)Vector search over indexed data
ctx.index(path)Index files for vector search
ctx.upload(dest, opts)Download files into the cell
ctx.configCustomer-specific configuration object
ctx.memoryPersistent key-value store per customer
ctx.stateCurrent agent state (serializable)

ctx.shell()

Execute shell commands inside the cell.

const result = await ctx.shell("npm test");

result.stdout;     // Standard output
result.stderr;     // Standard error
result.exitCode;   // Exit code(0 = success)
result.failed;     // true if exitCode !== 0

ctx.llm()

Call any LLM. Routes to OpenAI, Anthropic, or a local model on the cell's GPU. Response is automatically checkpointed.

// Simple call
const response = await ctx.llm("Explain this code", { context: files });

// With model selection
const response = await ctx.llm("Explain this code", {
    model: "claude-sonnet-4-20250514",
    context: files,
    temperature: 0.2
});

// With tool calls
const response = await ctx.llm("Fix the failing test", {
    tools: [ctx.shell, ctx.search]  // Agent can call these
});

ctx.memory

Persistent key-value store scoped to each customer. Survives cell pause/resume and crashes.

// Store
ctx.memory.set("lastTask", instruction);
ctx.memory.set("preferences", { language: "typescript" });

// Retrieve
const last = ctx.memory.get("lastTask");
const prefs = ctx.memory.get("preferences", { default: {} });

// List keys
const keys = ctx.memory.keys();

// Delete
ctx.memory.delete("oldKey");

Storage

Each cell has NVMe-backed local storage. Files persist across agent calls, pause/resume, and crash recovery. Read speed: 7 GB/s.

# Write files
await ctx.shell("echo 'hello' > /work/output.txt")

# Read files
result = await ctx.shell("cat /work/output.txt")

# Upload from URL
await ctx.upload("/work/data/", from_url="">https://example.com/dataset.csv")

# Storage is scoped to the cell — Customer A's files
# are physically separate from Customer B's files.

Built-in vector search, stored locally on NVMe. No external vector database needed.

// Index a directory
await ctx.index("/work/src/", { glob: "**/*.{ts,py,go,md}" });

// Search
const results = await ctx.search("authentication middleware", { topK: 10 });

for (const result of results) {
    console.log(result.path);      // /work/src/auth/middleware.ts
    console.log(result.content);   // File content(or relevant chunk)
    console.log(result.score);     // Similarity score(0-1)
}

// Re-index after changes (incremental)
await ctx.index("/work/src/");

Durability

Every await in your coding agent is a durable checkpoint. If the cell crashes mid-test-run, the agent resumes from the last passing step — not from git clone.

Coding agent executes "Add dark mode":
  Step 1: ctx.search("dark mode")   ✓ done (result saved)
  Step 2: ctx.llm("plan changes")   ✓ done (tokens spent, result saved)
  Step 3: ctx.shell("edit theme.ts") ✓ done (file written)
  Step 4: ctx.shell("edit settings") ✓ done (file written)
  Step 5: ctx.shell("npm test")      ✓ done (tests passed)
  Step 6: ctx.shell("edit toggle")   ✓ done (file written)
  Step 7: ctx.shell("npm test")      ⟳ running...

  ──── HOST REBOOTS ────

  Cell restarts on new host.
  Replays journal:
    Steps 1-6: return cached results (not re-executed)
    Step 2: LLM tokens NOT re-spent
    Step 7: re-execute from here  resumes npm test

  Customer never noticed. PR still gets created.

Side effects (PRs created, commits pushed) are not re-executed on replay. Only the interrupted step is retried.

Isolation

Each customer's source code runs in a gVisor sandbox. Customer A's repo physically cannot be accessed by Customer B's cell — different processes, different filesystems, different network namespaces.

Isolation for coding agents:

  ✓ Separate filesystem     Customer A's repo invisible to Customer B
  ✓ Scoped git credentials  Each cell has its own git token
  ✓ Separate process space  npm test runs in complete isolation
  ✓ Network egress blocked  Default: no outbound except allowlisted
  ✓ Allowlisted domains     github.com, registry.npmjs.org, LLM APIs
  ✓ gVisor syscall filter   Only ~68 host syscalls (vs ~350 in Docker)
  ✓ Resource limits          CPU, RAM, storage capped per cell

Customer source code never leaves the cell. Not separated by IAM policies — physically isolated at the kernel level. SOC2 and HIPAA compliant by architecture.

Deployment

oncell deploy

Terminal
$ oncell deploy

Building agent image...
✓ Image built (8s)
✓ Cell template created (compute: 4cpu-8gb, storage: 50gb)
✓ Endpoint live: https://your-agent.oncell.run

Dashboard: "color:#7dd3fc">https://console.oncell.ai/your-agent

Environments

Terminal
oncell deploy --env staging
oncell deploy --env production
oncell promote staging production

Logs

Terminal
oncell logs --customer acme-corp --follow
oncell cells list
oncell cells inspect acme-corp

Customer API

Manage customers from your existing backend.

import { OnCell } from "oncell";

const oncell = new OnCell();

// Create a customer (provisions a cell, runs setup())
const customer = await oncell.customers.create({
    id: "acme-corp",
    config: {
        repoUrl: "https://github.com/acme/webapp",
        language: "typescript"
    }
});

// Run a task
const result = await oncell.agents.run({
    customer: "acme-corp",
    method: "task",
    input: { instruction: "Add dark mode to settings page" }
});

// Stream results
for await (const event of oncell.agents.stream({
    customer: "acme-corp",
    method: "task",
    input: { instruction: "Fix the auth bug" }
})) {
    console.log(event);
}

// Pause / Resume / Delete
await oncell.customers.pause("acme-corp");
await oncell.customers.resume("acme-corp");   // ~200ms
await oncell.customers.delete("acme-corp");

REST API

POST   /v1/customers                Create customer
GET    /v1/customers/:id            Get customer
DELETE /v1/customers/:id            Delete customer
POST   /v1/customers/:id/pause      Pause cell
POST   /v1/customers/:id/resume     Resume cell

POST   /v1/agents/:method           Run agent method
POST   /v1/agents/:method/stream    Stream agent method

Configuration

LLM configuration

oncell.yaml
llm:
  default: openai
  providers:
    openai:
      api_key: $OPENAI_API_KEY
      model: gpt-4o
    anthropic:
      api_key: $ANTHROPIC_API_KEY
      model: claude-sonnet-4-20250514
    local:
      model: meta-llama/Llama-3-8B
      gpu: required

Network

oncell.yaml
network:
  egress: blocked
  allow:
    - api.openai.com
    - api.anthropic.com
    - github.com
    - "*.amazonaws.com"

Secrets

Terminal
oncell secrets set OPENAI_API_KEY=sk-...
oncell secrets set GITHUB_TOKEN=ghp_...

Pricing

Active compute
$0.05/hr
Per cell while running
Paused storage
$0.001/hr
Per cell while idle
GPU (L4)
$0.50/hr
Per cell with GPU
GPU (A10G)
$1.20/hr
Per cell with GPU
LLM calls
Pass-through
At provider cost

Free tier: 3 cells, 100 compute hours/month, 5 GB storage per cell.

Examples

Real-world coding agent patterns. Each example is production-ready — deploy with oncell deploy.

Full-Stack Coding Agent

Clones the customer's repo, indexes their codebase, plans and implements changes, runs tests, and pushes a PR.

import { Agent, Context } from "oncell";

export class CodingAgent extends Agent {
    cell = { compute: "4cpu-8gb", storage: "50gb", packages: ["nodejs", "git"] };

    async setup(ctx: Context) {
        await ctx.shell("color:#5cdb7f">`git clone ${ctx.config.repoUrl} /work`);
        await ctx.index("/work");
    }

    async task(ctx: Context, instruction: string) {
        const files = await ctx.search(instruction);
        const plan = await ctx.llm(instruction, { context: files });
        for (const step of plan.steps) {
            await ctx.shell(step.command);
            await ctx.shell("npm test");
        }
        await ctx.shell("git add -A && git commit -m '" + instruction + "' && git push");
        return { status: "done" };
    }
}

Code Review Agent

Reviews PRs automatically — checks for bugs, security issues, and style violations in the customer's codebase.

import { Agent, Context } from "oncell";

export class ReviewAgent extends Agent {
    cell = { compute: "4cpu-8gb", storage: "50gb", packages: ["git"] };

    async setup(ctx: Context) {
        await ctx.shell("color:#5cdb7f">`git clone ${ctx.config.repoUrl} /work`);
        await ctx.index("/work");
    }

    async reviewPR(ctx: Context, prNumber: number) {
        await ctx.shell("color:#5cdb7f">`cd /work && git fetch origin pull/${prNumber}/head:pr`);
        const diff = await ctx.shell("cd /work && git diff main...pr");
        const context = await ctx.search(diff.stdout);

        const review = await ctx.llm("Review this PR for bugs and security issues", {
            context: [...context, { content: diff.stdout }]
        });

        return { review, approved: !review.includes("CRITICAL") };
    }
}

Migration Agent

Upgrades dependencies, migrates APIs, and refactors code across the entire codebase with test verification.

import { Agent, Context } from "oncell";

export class MigrationAgent extends Agent {
    cell = { compute: "8cpu-16gb", storage: "50gb", packages: ["nodejs", "git"] };

    async setup(ctx: Context) {
        await ctx.shell("color:#5cdb7f">`git clone ${ctx.config.repoUrl} /work`);
        await ctx.index("/work");
    }

    async migrate(ctx: Context, from: string, to: string) {
        const files = await ctx.search("color:#5cdb7f">`import.*${from}`);
        const plan = await ctx.llm(
            "color:#5cdb7f">`Migrate all usages of ${from} to ${to}`,
            { context: files }
        );

        for (const step of plan.steps) {
            await ctx.shell(step.command);
            const tests = await ctx.shell("npm test");
            if (tests.failed) {
                const fix = await ctx.llm("color:#5cdb7f">`Tests failed after migration step. Fix:`, {
                    context: [{ content: tests.stderr }]
                });
                await ctx.shell(fix.command);
            }
        }

        await ctx.shell("color:#5cdb7f">`git add -A && git commit -m 'Migrate ${from} to ${to}'`);
        await ctx.shell("git push");
        return { status: "done", filesChanged: plan.steps.length };
    }
}

Security Scanner (Air-Gapped)

Scans customer codebases for vulnerabilities with zero internet access. Source code never leaves the cell.

import { Agent, Context } from "oncell";

export class SecurityAgent extends Agent {
    cell = {
        compute: "4cpu-8gb",
        storage: "20gb",
        network: { egress: "blocked" }  // No internet access
    };

    async setup(ctx: Context) {
        await ctx.shell("color:#5cdb7f">`git clone ${ctx.config.repoUrl} /work`);
        await ctx.index("/work");
    }

    async scan(ctx: Context) {
        const files = await ctx.search("password secret key token auth credential");
        // LLM runs locally on GPU — no data leaves the cell
        const findings = await ctx.llm("Find security vulnerabilities", {
            context: files, model: "local"
        });
        return { findings };
    }
}

Questions? Reach out on Discord or GitHub.