Skip to content

About

No description, website, or topics provided.

Resources

Stars

24 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

1 Commit

Folders and files

Repository files navigation

Naive

Naive Starter

πŸ€– An AI-native, multi-tenant SaaS starter template

Every end-user signs up and gets their own AI assistant that connects third-party apps, manages encrypted credentials, and runs native business primitives β€” all isolated per user and governed by an Account Kit.


License Next.js SDK Anthropic

Quick start Β· How it works Β· Deploy Β· Customize


✨ What you get

Page What it shows
πŸ’¬ Chat A streaming agent loop powered by agentTools() β€” searches/connects apps, runs capabilities, and calls native primitives.
πŸ’³ Cards Per-user virtual payment cards (client.cards).
πŸ“¬ Email Per-user inboxes on a Naive domain (client.email).
πŸ”Œ Connections Connect third-party apps (Gmail, GitHub, Slack, …) per user.
πŸ” Credentials A per-user, KMS-encrypted vault (client.vault).
βœ… Approvals Human-in-the-loop queue for sensitive agent actions.

Cards & Email are sample primitive pages β€” the same client.<primitive> pattern extends to domains, verification, formation, and social.

πŸ€” Why this template

Wiring an AI agent into a real product takes more than a chat box. You need:

  • πŸ‘₯ Per-user identity β€” each app user maps 1:1 to a Naive tenant_user.
  • πŸ”’ Isolation β€” one server-side API key; every call scoped via naive.forUser(id).
  • 🌐 Reach β€” the agent can use ~1000 third-party apps and native primitives.
  • πŸ›‘οΈ Governance β€” sensitive actions are gated by each user's Account Kit and surface as approvals.

This repo shows the entire integration in a small, readable codebase you can clone and ship.

🧱 Tech stack

  • ⚑ Next.js 15 (App Router) β€” UI + API routes
  • πŸ”‘ BetterAuth β€” email/password auth
  • πŸ—„οΈ Drizzle ORM + libSQL/SQLite β€” zero-infra local DB
  • 🧠 Anthropic Claude β€” the chat model
  • 🧩 @usenaive-sdk/node β€” multi-tenant business infrastructure

πŸš€ Deploy your own

Deploy with Vercel

⚠️ Point repository-url at your own repo/fork. Production needs a hosted database β€” see Deployment.


⚑ Quick start

Prerequisites

1. Get your Naive credentials

  • πŸ“ Sign up at the Naive dashboard.
  • πŸŽ›οΈ (Optional) Create an Account Kit β€” allowlist apps (gmail, github, …) and enable primitives (cards, email, …). Copy its id; blank uses your default kit.
  • πŸ”‘ Create a workspace API key (Settings β†’ API Keys). Copy it.

2. Configure environment

cp .env.example .env

Fill in the values (see Environment variables). Minimum: ANTHROPIC_API_KEY, NAIVE_API_KEY, BETTER_AUTH_SECRET.

3. Install, migrate, run

npm install
npm run db:push     # create the local SQLite tables
npm run dev         # β†’ http://localhost:3400

4. Try it β€” sign up, then in the chat:

  • πŸ’¬ "What can you do for me?" β€” lists apps + primitives
  • πŸ”Œ "Connect my GitHub" β€” third-party app lane (OAuth link)
  • πŸ’³ "Issue a $50 virtual card" β€” native primitive (may need approval)

🧩 How it works

The entire Naive integration lives in three files β€” read these:

  • 1️⃣ Provision on signup β†’ lib/auth.ts: a BetterAuth create.after hook calls naive.users.create({ external_id }) and stores the id on user.naiveUserId.
  • 2️⃣ Scope to the user β†’ lib/naive.ts: requireNaiveUser() resolves the session to naive.forUser(naiveUserId).
  • 3️⃣ Give the agent tools β†’ app/api/chat/route.ts: client.agentTools() returns Anthropic tool defs + a handle() dispatcher, run in a streaming loop.
flowchart LR
  signup["Signup (BetterAuth)"] -->|create hook| provision["naive.users.create()"]
  user["End user"] --> chat["/api/chat"]
  chat --> claude["Anthropic (tool-use)"]
  claude -->|tool_use| tools["naive.forUser(id).agentTools()"]
  tools --> api["Naive API"]
  api -->|kit-gated| ext["Third-party apps + built-in primitives"]
Loading

πŸ‘₯ Multi-tenancy

  • πŸ”‘ One secret API key lives on the server only.
  • 🎯 naive.forUser(id) pins every request to /v1/users/{id} β€” no method ever takes a userId.
  • 🧱 Connections, vault, cards, and every primitive are isolated per user and enforced by that user's Account Kit.
flowchart TB
  key["One workspace API key (server-side)"]
  key -->|"forUser(A)"| sa["tenant_user A β†’ Account Kit A"]
  key -->|"forUser(B)"| sb["tenant_user B β†’ Account Kit B"]
Loading

πŸ› οΈ The agent's tools (two lanes, not 1000s of schemas)

  • 🌐 Third-party apps β€” naive_search_apps, naive_list_connections, naive_connect_app, naive_list_capabilities, naive_run_capability. Reaches ~1000 external OAuth apps and all their capabilities.
  • 🧩 Built-in primitives β€” naive_search_primitives (discover primitives + methods + arg schemas) and naive_run_primitive (execute, e.g. primitive='cards', method='create'). Covers cards, email, domains, vault, KYC, formation, social, approvals.

πŸ” Same search β†’ run pattern for both lanes. naive_search_apps is third-party only. Sensitive methods return pending_approval and surface in the Approvals tab.

πŸ“‘ Streaming

  • /api/chat streams newline-delimited JSON (text, tool, pending, done, error).
  • The client renders replies token-by-token; conversations persist in localStorage; "New chat" clears them.

πŸ—‚οΈ Project structure

.
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ api/                 # Server routes β€” ALL Naive calls happen here
β”‚   β”‚   β”œβ”€β”€ chat/route.ts    # πŸ’¬ streaming agent loop (agentTools)
β”‚   β”‚   β”œβ”€β”€ cards/route.ts   # πŸ’³ cards primitive
β”‚   β”‚   β”œβ”€β”€ email/route.ts   # πŸ“¬ email primitive
β”‚   β”‚   β”œβ”€β”€ connections/     # πŸ”Œ third-party app connections
β”‚   β”‚   β”œβ”€β”€ vault/route.ts   # πŸ” credentials vault
β”‚   β”‚   β”œβ”€β”€ approvals/       # βœ… human-in-the-loop queue
β”‚   β”‚   └── auth/[...all]/    # πŸ”‘ BetterAuth handler
β”‚   β”œβ”€β”€ app/                 # Authenticated UI (chat + primitive pages)
β”‚   β”œβ”€β”€ login/ Β· signup/     # Auth pages
β”‚   └── layout.tsx Β· globals.css Β· page.tsx
β”œβ”€β”€ components/              # Shared UI (ui.tsx, auth-ui.tsx)
β”œβ”€β”€ db/                      # Drizzle schema + libSQL client
β”œβ”€β”€ lib/
β”‚   β”œβ”€β”€ naive.ts             # ⭐ SDK wiring: provisioning + requireNaiveUser()
β”‚   β”œβ”€β”€ auth.ts              # BetterAuth config + provisioning hook
β”‚   β”œβ”€β”€ auth-client.ts       # Client-side auth helpers
β”‚   └── api-utils.ts         # Error β†’ response helper
β”œβ”€β”€ .env.example
└── drizzle.config.ts

πŸ”‘ Environment variables

Variable Required Description
ANTHROPIC_API_KEY βœ… Anthropic API key β€” the chat LLM.
NAIVE_API_KEY βœ… Workspace API key (Naive dashboard β†’ Settings β†’ API Keys).
BETTER_AUTH_SECRET βœ… Session-signing secret. openssl rand -base64 32.
BETTER_AUTH_URL βœ… prod App base URL. http://localhost:3400 in dev; your deployed URL in prod.
NAIVE_API_URL βž– Naive API base. Defaults to https://api.usenaive.ai.
NAIVE_ACCOUNT_KIT_ID βž– Account Kit for new users. Blank = workspace default.
DATABASE_URL βž– libSQL/SQLite URL. Defaults to file:./dev.db.
DATABASE_AUTH_TOKEN βž– Auth token for a hosted libSQL/Turso database.

βœ… Testing & quality

npm run typecheck   # tsc --noEmit
npm run build       # production build

Manual QA (sign up first, then chat):

  • πŸ’¬ "What can you do for me?" β†’ describes apps + primitives
  • πŸ”Œ "Connect my GitHub" β†’ OAuth link; shows on Connections
  • πŸ“¬ "Create an inbox called support" then "send an email from it" β†’ Email updates
  • 🌐 "Is example.com available?" β†’ domain check (no purchase)
  • πŸ” "Store my OpenAI key as openai.key" β†’ appears in Credentials
  • πŸ’³ "Issue a $50 virtual card" β†’ if gated, shows in Approvals; approve to run

☁️ Deployment

Standard Next.js app β€” deploys anywhere. For Vercel:

  1. ⬆️ Push to GitHub and import into Vercel (or use the Deploy button).
  2. πŸ—„οΈ Use a hosted database β€” serverless filesystems are ephemeral, so file:./dev.db won't persist. Create a Turso DB and set DATABASE_URL + DATABASE_AUTH_TOKEN. (Or switch the dialect to Postgres in drizzle.config.ts + db/index.ts.)
  3. 🧱 Apply the schema once: DATABASE_URL=… DATABASE_AUTH_TOKEN=… npm run db:push.
  4. πŸ”‘ Set all environment variables in Vercel; set BETTER_AUTH_URL to your deployed URL.
  5. πŸš€ Deploy.

🎨 Customizing

  • 🏷️ Rebrand β€” "Acme AI" + avatar live in app/app/nav.tsx and components/auth-ui.tsx; theme tokens in app/globals.css.
  • βž• Add a primitive page β€” copy a route in app/api/<primitive>/route.ts (thin pass-through to client.<primitive>) + a page under app/app/<primitive>/. The agent already reaches every primitive via naive_run_primitive.
  • πŸ›‘οΈ Control agent permissions β€” configure each user's Account Kit in the dashboard (allowed apps, enabled primitives, what needs approval).
  • πŸ—„οΈ Swap the database β€” point at Turso, or change the Drizzle dialect for Postgres.

πŸ›Ÿ Troubleshooting

  • πŸ€– Agent says a built-in feature "isn't available" β†’ ensure @usenaive-sdk/node is ^0.3.0+ and restart npm run dev (Next caches resolved deps).
  • ⏳ A sensitive action never runs β†’ it's waiting in Approvals (gated by the Account Kit). Approve it, or relax the kit policy.
  • πŸ” Auth redirect loops in production β†’ set BETTER_AUTH_URL to your exact deployed origin.
  • πŸ—„οΈ db:push fails on Vercel β†’ run it against the hosted DB with the production DATABASE_URL/DATABASE_AUTH_TOKEN.

πŸ“š Learn more


Built with Naive Β· MIT licensed

About

No description, website, or topics provided.

Resources

Stars

24 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages