Skip to main content
The SDK is split into four packages with clean boundaries:
PackageWhenWhat
@usenaive-sdk/iacbuild-timeDeclarative naive.config.tsdefineConfig, cloud.*, business.*, agent, identity, skills (plus runtime.pool, defineModule). Run by naive up.
@usenaive-sdk/serverrun-time (your app)new Naive({ apiKey }), forUser(id).provision(role) → an AgentProfile with tools() / revoke(), runtime(pool).start(), plus the flat resource API (cards.create, comms.email.create).
@usenaive-sdk/runtimeinside a hosted agentagentProfile.tools() scoped to the current agentProfile.
@usenaive-sdk/cli (naive)terminal / CIlogin, init, up, agent profiles, revoke, module, env, and every primitive.
import { Naive } from "@usenaive-sdk/server";
const naive = new Naive({ apiKey: process.env.NAIVE_SECRET_KEY! });

// Provision a governed agent profile per tenant, then pull its tools / revoke it.
const op = await naive.forUser(tenant.id).provision("sdr", { idempotencyKey: `op:${tenant.id}` });
const tools = await op.tools();
// await op.revoke();
@usenaive-sdk/node is the previous package name. It still works and is the base that @usenaive-sdk/server re-exports, so existing imports keep functioning — but new code should import from @usenaive-sdk/server to get the agent profile surface.

Scoped clients — no polymorphic args

Top-level data-plane calls act on your default user:
await naive.cards.create({ spending_limit_cents: 25000 });
await naive.vault.put("instantly.api_key", "key_xyz");
naive.forUser(id) returns the same surface bound to a specific tenant user:
const client = naive.forUser(alice.id);
await client.cards.create({ spending_limit_cents: 25000 });
await client.vault.put("instantly.api_key", "key_xyz");
There is no userId | {args} overloading — vault.put(key, value) always means (key, value). The scope is fixed by which client you got the sub-client from.

Agent Profiles

forUser(id).provision(role) instantiates a governed agent profile for a tenant — its identity, card, comms, and policy as one unit — and returns an AgentProfile:
const op = await naive.forUser(tenant.id).provision("sdr", {
  idempotencyKey: `op:${tenant.id}`,          // retried webhook → same agent profile
  overrides: { identity: { legalName: tenant.company } },
});

op.status;                 // "provisioning" | "active" | "needs_action" | ...
const tools = await op.tools();   // governed toolset for your agent / Eve / LangGraph
await op.refresh();        // re-fetch status (provisioning is async)
await op.revoke();         // absolute: freeze card, halt sends, rotate, tear down
Run the agent wherever you like — naive.runtime("pool").start(op.id, { goal }) for Naïve-hosted microVMs, or pull op.tools() into your own runtime. Governance is constant either way (the governance gateway).

Control plane vs data plane

  • Control plane (naive.users, naive.accountKits, naive.plans, naive.toolkits, and forUser(id).provision / agent profile management) lives at company scope.
  • Data plane (cards, phone, trading, email, verification, formation, domains, social, connections, vault, logs, sessions, images, video, search, clips, llm, browser, profile, seo, aeo, cron, jobs, memory, billing, webhooks, plus the build primitives apps, database, storage, functions, auth) is available on both the root (default user) and on forUser(id).
The build primitives operate on a fullstack app’s managed backend — naive.apps.create({ name, type: "fullstack" }) first, then naive.database / naive.storage / naive.functions / naive.auth (own project), or naive.forUser(id).database for an end-user’s project.

When to use the SDK vs CLI vs MCP

  • SDK — embedding Naive in your multi-tenant SaaS backend.
  • CLI — you, a developer, using Naive from a terminal (acts on your default user).
  • MCP — handing tools to an MCP-native agent (Claude, Cursor).
The SDK is server-only in v1 (API keys are server secrets).