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

@mitosislabs/sdk

v0.16.0

Published

Mitosis — persistent AI agents that remember, replicate, and coordinate

Readme

Mitosis SDK

npm node

Persistent AI agents that remember, replicate, and coordinate.

@mitosislabs/sdk is the official TypeScript SDK and mi CLI for the Mitosis platform. It gives you typed access to every office-manager API endpoint, OAuth API-key authentication (plus per-agent secp256k1 signing for agents), a managed XMTP session protocol for talking to agent pods, and a local keystore so you never paste secrets at a prompt.

import { MitosisClient } from '@mitosislabs/sdk';

// Authenticate once with `mi login` (browser OAuth — issues a personal API key),
// then the SDK picks it up from ~/.os1 automatically:
const mi = await MitosisClient.fromConfig();

const offices  = await mi.offices.list();
const agents   = await mi.employees.list(offices[0].id);
const balance  = await mi.credits.balance(offices[0].id);

Naming: the client class is MitosisClient. It was previously called OS1AdminClient (after the internal "OS-1" codename); that name is still exported as a deprecated alias for backward compatibility and will be removed in a future major version. New code should import MitosisClient.


Table of contents

  1. Install
  2. Quickstart
  3. Authentication
  4. The MitosisClient
  5. API surface
  6. XMTP — talking to agents
  7. The mi CLI
  8. Keystore
  9. Errors
  10. TypeScript types
  11. Recipes
  12. FAQ & troubleshooting
  13. Repo layout

Install

# Library + CLI
npm install @mitosislabs/sdk

# CLI only (one-off use)
npx -p @mitosislabs/sdk mi --help

# Global CLI
npm install -g @mitosislabs/sdk
mi --help

Requirements: Node.js 18+. The package ships ESM ("type": "module"). Public TypeScript types are bundled.


Quickstart

1. Sign in once

mi login --endpoint https://mitosislabs.ai

This opens your browser for OAuth, issues a personal API key, and writes it to ~/.os1/config.json (chmod 0600). The key is scoped to your account — it authenticates as you and can't act on anyone else's behalf.

2. Verify

mi whoami
# → logged in as [email protected] (API key mi_…)

3. Drive it

mi offices list
mi agents list  --office <officeId>
mi agents hire  --office <officeId> --name aria --role researcher --model sonnet
mi tasks  create --office <officeId> --title "Audit Q1 revenue" --assign aria
mi chat   <officeId> aria

Use it as a library

import { MitosisClient } from '@mitosislabs/sdk';

const mi = await MitosisClient.fromConfig();      // reads ~/.os1
const offices = await mi.offices.list();
console.log(offices.map(o => `${o.name} (${o.id})`));

Where rows land (CLA-904)

mi offices create and mi agents hire go through the dashboard, not office-manager directly. This ensures the canonical offices row gets the dashboard-only columns (office_secret, manager_url, office_type, created_by) and that the agent appears in the user's /dashboard view.

The transport derives the dashboard host from the configured endpoint:

| endpoint | derived dashboardEndpoint | |---|---| | https://m.mitosislabs.ai | https://mitosislabs.ai | | https://m.dev.mitosislabs.ai | https://dev.mitosislabs.ai | | http://localhost:8080 | http://localhost:3000 |

Override via dashboardEndpoint in ClientConfig for non-standard envs. All other API calls (list/get/fire/etc.) target office-manager directly.

Creating a colony when you already own one

The dashboard's POST /api/offices route deduplicates per user: if you already own a non-archived colony, it returns that one with existing: true and ignores the requested name. This is intentional — onboarding flows can call create idempotently without producing duplicates.

$ mi colonies create -n hello-text
note: you already own a colony named "willow-bend-15c6ff0e" (33f5682c-…) — returning that one.
      the requested name "hello-text" was ignored.
      to create a second colony, re-run with --force.
{
  "id": "33f5682c-…",
  "name": "willow-bend-15c6ff0e",
  "existing": true
}

To explicitly create a second colony, pass --force (CLI) or forceCreate: true (SDK). This mirrors what the dashboard's office-selector UI does for its "create new colony" button.

mi colonies create -n hello-text --force
await mi.offices.create({ name: 'hello-text', forceCreate: true });

For LLM agents: when existing: true is in the response, the user already has a colony and the name they asked for was discarded. Do not pretend you created what they requested. Surface the existing colony, ask whether they want to keep using it or create a second one, and only retry with forceCreate after explicit confirmation.


Authentication

API key (OAuth) — this is the one you want

Run mi login once. It does browser OAuth and persists a personal API key (mi_…) to ~/.os1/config.json. The SDK sends it as Authorization: Bearer mi_…; office-manager validates it server-side and resolves it to your user. The key is scoped to your account and cannot impersonate anyone else.

// after `mi login`:
const mi = await MitosisClient.fromConfig();

// or pass the key explicitly (e.g. in CI — store it as a secret):
const mi = new MitosisClient({
  endpoint: 'https://m.mitosislabs.ai',
  apiKey: process.env.MITOSIS_API_KEY,   // a mi_… key from the dashboard
});

Generate keys for CI/headless use from the dashboard (user menu → Copy API Key), or mi login --token mi_… to paste one on a remote host.

secp256k1 (act as a specific agent)

ECDSA over the canonical request payload:

{unix_timestamp}\n{HTTP_METHOD}\n{path_with_query}

Hash is SHA-256, signature is 64-byte compact r||s hex. Office-manager also accepts DER. Timestamps older than 60 seconds are rejected.

const mi = await MitosisClient.asAgent('office-uuid', 'aria');

// or explicitly
import { MitosisClient } from '@mitosislabs/sdk';
const mi = new MitosisClient({
  endpoint: 'https://m.mitosislabs.ai',
  agent: { agentId: 'aria', signingKey /* Uint8Array(32) */ },
});

Which mode to use

| Mode | Sign with | Identity | Who uses it | |---------------|-----------------------|------------|--------------------------------------| | API key | mi_… OAuth key | you | everyone — apps, scripts, CI | | secp256k1 | per-agent private key | the agent | agents calling the API on their own |

⚠️ First-party / internal only — HMAC JWT. The office-manager also accepts tokens signed with its shared JWT_SECRET (the ClientConfig.jwt option). That secret is a master key: anyone holding it can mint a token for any user. It exists solely for first-party services that already run with the office-manager secret (the dashboard itself, internal CI). Do not use it as an application or end-user — use an API key. If you don't already operate the office-manager, you should never see JWT_SECRET.


The MitosisClient

class MitosisClient {
  constructor(config: ClientConfig);

  // Static constructors
  static fromConfig(): Promise<MitosisClient>;
  static asAgent(officeId: string, agentName: string,
                 endpoint?: string): Promise<MitosisClient>;

  // Convenience
  health(): Promise<boolean>;
  verifyAuth(): Promise<{ ok: boolean; method: string; error?: string }>;
  close(): Promise<void>;          // closes XMTP sessions

  // Subsystems (each is a typed class — see § API surface)
  readonly offices, employees, tasks, files, credits;
  readonly xmtpApi, integrations, extensions;
  readonly events, callbacks, backups, env, delegates;
  readonly messages, workspace, roles, transfer, llmPing;
  readonly whatsapp, chromium, capabilities, proxy;
  readonly xmtp;             // high-level XMTPChannel
  readonly transport;        // raw HTTP transport
  readonly keystore;         // local Keystore
}

ClientConfig:

interface ClientConfig {
  endpoint: string;                     // e.g. https://m.mitosislabs.ai
  apiKey?: string;                      // mi_… OAuth key — the normal auth path
  agent?: { agentId: string; signingKey: Uint8Array };  // act as an agent
  jwt?:   { jwtSecret: string; userId?: string };        // ⚠️ first-party only (master secret)
  timeout?: number;                     // ms, default 30000
}

API surface

Every endpoint on office-manager has a typed wrapper. Group → class on the client → backing route prefix.

| Group | client.<member> | Route prefix | |-----------------|-----------------------|-------------------------------------------------| | Offices | offices | /api/v1/offices | | Employees | employees | /api/v1/offices/:id/employees | | Tasks | tasks | /api/v1/offices/:id/tasks | | Files | files | /api/v1/offices/:id/files | | Credits + usage | credits | /api/v1/offices/:id/{credits,usage,quota,…} | | XMTP | xmtpApi | /api/v1/offices/:id/xmtp | | Integrations | integrations | /api/v1/offices/:id/{provider-models,integrations} | | Extensions | extensions | /api/v1/offices/:id/extensions + /marketplace | | Events | events | /api/v1/offices/:id/events | | Callbacks | callbacks | /api/v1/offices/:id/callbacks | | Backups | backups | /api/v1/offices/:id/backups | | Env vars | env | /api/v1/offices/:id/env | | Delegates | delegates | /api/v1/offices/:id/delegates | | Messages bus | messages | /api/v1/offices/:id/messages | | Workspace exec | workspace | /api/v1/offices/:id/workspace | | Roles | roles | /api/v1/offices/:id/roles | | Agent transfer | transfer | /api/v1/offices/:id/agents/{prepare,install,…} | | LLM ping | llmPing | /api/v1/offices/:id/llm-ping | | WhatsApp | whatsapp | /api/v1/offices/:id/whatsapp + per-agent | | Chromium | chromium | /api/v1/offices/:id/chromium | | Capabilities | capabilities | /api/v1/offices/:id/capabilities/self | | Code/Codex pxy | proxy | /api/v1/offices/:id/{code,codex}-proxy |

For exhaustive method-by-method documentation see llms-full.txt. A few highlights:

// Offices
await mi.offices.create({ name: 'acme', owner_id: userId });
await mi.offices.suspend(officeId);
await mi.offices.resume(officeId);
await mi.offices.kubeconfig(officeId);

// Hire / manage agents
await mi.employees.hire(officeId, { name: 'aria', role: 'researcher', modelTier: 'sonnet' });
await mi.employees.promote(officeId, 'aria', { modelTier: 'opus' });
await mi.employees.setSkills(officeId, 'aria', { add: ['github'] });
await mi.employees.logs(officeId, 'aria', { tail: 200 });
await mi.employees.activity(officeId, 'aria', { limit: 50, category: 'task' });

// Tasks
await mi.tasks.create(officeId, { title: 'Triage inbox', assigned_to: 'aria' });
await mi.tasks.stats(officeId);

// Files (shared drive)
await mi.files.upload(officeId, 'report.md', Buffer.from('...'));
const list = await mi.files.list(officeId);
const resp = await mi.files.download(officeId, 'report.md');

// Credits & usage
await mi.credits.balance(officeId);
await mi.credits.add(officeId, { amount: 100, reason: 'topup' });
await mi.credits.usageSummary(officeId);
await mi.credits.llmUsageSummary(officeId);

// Integrations
await mi.integrations.listProviderModels(officeId);
await mi.integrations.ensureSecret(officeId, 'github', 'ghp_...');
await mi.integrations.toggleAgent(officeId, 'github', 'aria', true);

XMTP — talking to agents

The SDK ships a session-aware XMTP layer that bypasses the dashboard and talks directly to the agent's chat-server presence.

const session = await mi.xmtp.negotiateSession(officeId, 'aria');
console.log(session.sessionId, session.capabilities);

const handle = mi.xmtp.getSession(officeId, 'aria')!;
await handle.send('Summarise yesterday and propose three tasks for today.');

for await (const msg of handle.stream(/* pollIntervalMs */ 2000)) {
  console.log(`[${msg.from_agent}] ${msg.content}`);
}

Session protocol

  1. SDK fetches existing conversations from office-manager.
  2. Sends a control message: { "type": "__SESSION_START__", "session_id": "<uuid>", "capabilities_request": true }
  3. Waits up to timeoutMs (default 30s) for a __SESSION_ACK__ carrying capabilities. If none arrives the session falls back to plain messaging.
  4. send(content) posts plain content to the conversation; receive() pulls only newer messages from the target agent and filters out control frames; stream() yields them as an async generator.
  5. close() posts __SESSION_END__ (best-effort) and tears the session down.

XMTPChannel is the per-client manager — it deduplicates by {officeId, agentName}, so calling openSession twice returns the same handle.


The mi CLI

The published binary is mi (formerly os1-admin).

mi --help
mi <command>

  login                              sign in via OAuth (persists an API key)
  whoami                             show who you're logged in as
  init                               configure endpoint (~/.os1)
  keys generate -o <office> -a <agent>
  keys list      -o <office>
  keys pubkey   -o <office> -a <agent>

  offices list
  offices create  -n <name> -u <ownerId>
  offices status  <officeId>
  offices delete  <officeId>

  agents list     -o <office>
  agents hire     -o <office> -n <name> [-r role] [-m model]
  agents get      <office> <name>
  agents logs     <office> <name> [-t tail]
  agents activity <office> <name> [-l limit] [-c category]
  agents fire     <office> <name>

  chat <office> <agent>              interactive XMTP session
  send <office> <agent> "<msg>"      one-shot message

  tasks list   -o <office>
  tasks create -o <office> -t <title> [-d desc] [-k kind] [-a agent]
  tasks stats  -o <office>

  files ls       -o <office>
  files upload   <office> <localPath>   [-n remoteName]
  files download <office> <filename>    [-o outputPath]

  credits balance -o <office>
  credits add     -o <office> -a <amount> -r <reason>

  api <METHOD> <path> [-d '<json>']     [--agent <name> --office <id>]

Every command has --help for full details. The api subcommand is an escape hatch for endpoints the typed wrappers haven't grown a method for yet.


Keystore

~/.os1/
├── config.json                    # SDK config (endpoint, default office)
├── keys/
│   ├── jwt.key                    # HMAC secret (chmod 0600)
│   └── <officeId>/
│       └── <agent>.key            # secp256k1 private key (chmod 0600)
└── sessions/                      # active session state

Programmatic access:

import { Keystore, generateKeyPair } from '@mitosislabs/sdk';

const ks = new Keystore();
const kp = await ks.generateAndStore(officeId, 'aria');   // public + private
const pub = await ks.getPublicKey(officeId, 'aria');
const list = await ks.listAgentKeys(officeId);

The keystore creates directories with 0700, files with 0600. Custom roots are supported via new Keystore({ basePath: '/custom/path' }).


Errors

All non-2xx responses raise OS1Error:

import { OS1Error } from '@mitosislabs/sdk';

try {
  await mi.employees.hire(officeId, { name: 'aria' });
} catch (err) {
  if (err instanceof OS1Error) {
    console.error(err.status, err.code, err.message);
    if (err.status === 402) /* office is out of credits */;
  } else {
    throw err;
  }
}

Common statuses: 401 invalid auth · 402 no credits · 403 forbidden · 404 missing resource · 409 name conflict · 429 rate limit (e.g. agent-hire is capped at 3 per 10 min per office).


TypeScript types

Every domain object is exported. The most commonly used shapes:

import type {
  // Auth
  ClientConfig, JWTAuthConfig, AgentAuthConfig, JWTPayload, KeyPair,

  // Office + agent
  Office, ClusterStatus,
  Employee, EmployeeChannels, EmployeeResources, EmployeeStatus,
  HireRequest, UpdateEmployeeRequest, PromoteRequest, SkillsRequest,
  AgentKitConfig, AgentKitOwner,

  // Tasks / files
  Task, CreateTaskRequest, TaskStats,
  FileInfo, FileChange, FileChangesResponse, FilePermission,

  // Money
  CreditBalance, AddCreditsRequest, CreditHistoryEntry,
  UsageSummary, LLMUsageSummary, Quota, SetQuotaRequest,

  // XMTP
  XMTPConversation, XMTPGroup, XMTPMessage,
  SendXMTPMessageRequest, CreateGroupRequest, SessionNegotiation,

  // Activity / events
  ActivityEvent, ActivityQuery, ChatSession,
  PodCallback, PodEventRequest,

  // Misc
  Extension, MarketplaceItem, WhatsAppStatus, ChromiumInstance,
  Delegate, ExecRequest, ExecResponse, Backup,
  TransferStatus, Role, EnvVar, ModelInfo, IntegrationSecret,
  PingResult,
} from '@mitosislabs/sdk';

Helpers are also exported:

import {
  MitosisClient,            // main client
  Transport,                 // raw HTTP transport (rare)
  Keystore,                  // local secret storage
  XMTPChannel, XMTPSession,  // session-aware messaging
  generateJWT, verifyJWT, authorizationHeader,
  generateKeyPair, publicKeyFromPrivate,
  signRequest, verifySignature,
  OS1Error,
} from '@mitosislabs/sdk';

Recipes

List every agent in every office

const mi = await MitosisClient.fromConfig();
for (const office of await mi.offices.list()) {
  const agents = await mi.employees.list(office.id);
  console.log(`[${office.name}] ${agents.length} agents`);
  for (const a of agents) console.log(`  - ${a.name} (${a.status.phase})`);
}
await mi.close();

Stream live messages from an agent

const handle = await mi.xmtp.openSession(officeId, 'aria');
await handle.negotiate(15_000);
for await (const m of handle.stream()) {
  if (m.content.includes('done')) break;
  console.log(m.from_agent, m.content);
}
await handle.close();

Act as an agent (secp256k1) for a single call

const agentClient = await MitosisClient.asAgent(officeId, 'aria');
await agentClient.callbacks.podEvent(officeId, { type: 'ready' });

Tail logs in real time-ish

let lastSeen = '';
setInterval(async () => {
  const { logs } = await mi.employees.logs(officeId, 'aria', { tail: 200 });
  if (logs !== lastSeen) {
    process.stdout.write(logs.slice(lastSeen.length));
    lastSeen = logs;
  }
}, 5_000);

Raw API call with the typed transport

const result = await mi.transport.request<MyType>(
  'POST',
  `/api/v1/offices/${officeId}/custom/route`,
  { body: { foo: 'bar' } },
);

FAQ & troubleshooting

401 / not logged in Run mi login to sign in via OAuth and persist your API key, then retry. Check status with mi whoami.

403 you do not own this office Your API key authenticates as you, but the office belongs to another account. You can only act on offices you own.

429 Too Many Requests on employees.hire Mitosis caps agent creation at ~3 per 10 minutes per office. Wait or use mi tasks create to queue work for an existing agent.

Session negotiation hangs forever The agent pod isn't running, or it's an older agent that doesn't speak the session protocol. The SDK times out after timeoutMs (default 30s) and returns a session with empty capabilities; messages still send fine, you just won't get capability discovery.

Can I use this from a browser? No. The SDK uses node:crypto, node:fs/promises, node:os, and the commander CLI library. It's a Node-only package.


Repo layout

src/
├── index.ts                  # public exports
├── client.ts                 # MitosisClient
├── transport.ts              # authenticated fetch + SSE
├── auth/
│   ├── index.ts
│   ├── jwt.ts                # HS256 generate/verify (mirrors office-manager)
│   ├── secp256k1.ts          # ECDSA sign/verify (mirrors pubkey_auth.go)
│   └── keystore.ts           # ~/.os1 secret storage
├── api/
│   ├── offices.ts            # OfficesAPI
│   ├── employees.ts          # EmployeesAPI
│   ├── tasks.ts              # TasksAPI
│   ├── files.ts              # FilesAPI
│   ├── credits.ts            # CreditsAPI (credits + usage + quota)
│   ├── xmtp.ts               # XMTPAPI (DMs, groups, messages)
│   ├── integrations.ts       # IntegrationsAPI
│   ├── extensions.ts         # ExtensionsAPI + marketplace
│   └── events.ts             # Events / Callbacks / Backups / Env /
│                             #   Delegates / Messages / Workspace /
│                             #   Roles / Transfer / LLMPing / WhatsApp /
│                             #   Chromium / Capabilities / Proxy
├── xmtp/
│   ├── channel.ts            # XMTPChannel — multi-session manager
│   └── session.ts            # XMTPSession — negotiate / send / stream
├── cli/index.ts              # `mi` binary
└── types/index.ts            # all public TypeScript types
tests/                        # vitest — auth, client, session, integration
scripts/list-employees.mjs    # standalone usage example
llms-full.txt                 # exhaustive reference for LLM agents
SDK.md                        # original architecture writeup
CLAUDE.md                     # internal contributor notes

License

MIT © Mitosis Labs

Links

  • Website: https://mitosislabs.ai
  • Docs: https://mitosislabs.ai/docs
  • Issues / questions: open an issue on the monorepo
  • Architecture deep-dive: SDK.md
  • LLM-friendly reference: llms-full.txt