Skip to main content
naive.forUser(id).agentTools() (or naive.agentTools() for the default user) returns a ready-to-use meta-toolset: a small set of tools as Anthropic tool-use definitions plus a handle(name, input) dispatcher. It’s the fastest way to give an agent real-world abilities — connect third-party apps, run their capabilities, and use Naive’s own built-in primitives — all bounded by the user’s Account Kit.

Why meta-tools (not 1000s of schemas)

Naive exposes thousands of capabilities across third-party apps and its own primitives. Instead of dumping every schema into the model’s context, agentTools() gives the agent a small core of discover → run meta-tools across two lanes.

Third-party apps lane (external integrations)

ToolDoes
naive_search_appsSearch the catalog of ~1000 connectable apps (Gmail, GitHub, Slack, …)
naive_list_connectionsWhat the user has already connected
naive_connect_appStart an OAuth connection (returns a link)
naive_list_capabilitiesList a connected app’s tools + schemas
naive_run_capabilityExecute a capability (gated by the Account Kit)
Flow: search_appsconnect_applist_capabilitiesrun_capability.

Built-in primitives lane (Naive’s own platform features)

ToolDoes
naive_search_primitivesDiscover Naive’s built-in primitives + their methods & arg schemas
naive_run_primitiveExecute a built-in method, e.g. primitive:"cards", method:"create"
Flow: search_primitivesrun_primitive. The primitives surfaced (when their client is available) are cards, trading (brokerage stocks/options/crypto via OAuth — naive_run_primitive(primitive:"trading", method:"create_order", arguments:{ symbol, side, notional })), email, domains, vault, verification (KYC), formation, social, approvals, browser (cloud browser sessions + autonomous signup/login), llm (OpenRouter chat completions across 300+ models — naive_run_primitive(primitive:"llm", method:"chat", arguments:{ model, messages })), profile (read/set the user’s own email — e.g. point it at a provisioned inbox before signup), the build primitives apps (provision a Vercel + optional Supabase app) plus database / storage / functions / auth (operate on a fullstack app’s Supabase backend — e.g. naive_run_primitive(primitive:"database", method:"query", arguments:{ sql })), and the growth primitives seo (keyword volume, rank tracking, backlinks, competitors — naive_run_primitive(primitive:"seo", method:"search_volume", arguments:{ keywords })) and aeo (AI-search / GEO visibility across ChatGPT, Claude, Gemini, Perplexity). For example, the agent drives the browser with naive_run_primitive(primitive:"browser", method:"signup", arguments:{ service, url }). Execution stays AccountKit-gated server-side, so the kit you configure bounds what the agent can do; sensitive methods (issue a card, buy a domain, KYC, formation, browser signup) may resolve to a pending_approval payload the model should relay to the user.

Usage with the Anthropic SDK

import Anthropic from "@anthropic-ai/sdk";
import { Naive } from "@usenaive-sdk/node";

const naive = new Naive({ apiKey: process.env.NAIVE_API_KEY! });
const anthropic = new Anthropic();

const kit = naive.forUser(userId).agentTools();

let messages = [{ role: "user", content: "Connect my GitHub and open an issue in acme/web" }];
while (true) {
  const res = await anthropic.messages.create({
    model: "claude-sonnet-4-5",
    max_tokens: 1024,
    tools: kit.tools,            // <- Naive tools, Anthropic format
    messages,
  });
  messages.push({ role: "assistant", content: res.content });

  const calls = res.content.filter((b) => b.type === "tool_use");
  if (calls.length === 0) break;

  const results = [];
  for (const call of calls) {
    const out = await kit.handle(call.name, call.input as Record<string, unknown>);
    results.push({ type: "tool_result", tool_use_id: call.id, content: JSON.stringify(out) });
  }
  messages.push({ role: "user", content: results });
}
See the full working app in the naive-example repo (/api/chat).