Skip to main content
@usenaive-sdk/iac is the build-time, declarative half of the SDK. You author a naive.config.ts, and naive up sets it up. It is side-effect free — it issues no per-tenant resources; agents are stamped out at run time with forUser(id).provision(role).
npm install @usenaive-sdk/iac
naive init        # scaffold a starter naive.config.ts

The shape

A config has two halves:
  • infrastructure — set up once for the whole project: cloud (web, database, storage) and business (the real-world programs agents draw from).
  • agents — a blueprint per role. naive.forUser(id).provision(role) stamps out a fresh, isolated, governed copy per user.
import { defineConfig, cloud, business, agent, identity, skills } from "@usenaive-sdk/iac";

export default defineConfig({
  project: "faceless-ugc",

  // ── infrastructure: set up ONCE for the whole project ────────────────
  infrastructure: {
    // Cloud — one instance, everyone shares it. Naïve auto-injects secrets
    // (DATABASE_URL, bucket creds…) into the runtime.
    cloud: {
      website:  cloud.web({ framework: "nextjs", dir: "." }),
      database: cloud.postgres({ size: "serverless" }),
      storage:  cloud.bucket(), // generated videos + thumbnails
    },

    // Business — the real-world "programs" each agent draws from. Turning one ON
    // registers the shared PARENT; each agent then gets its OWN email / number /
    // card under it, via `has` below.
    business: {
      identity: business.entity({ form: "llc", verify: "kyb" }),       // mint LLCs + EINs
      email:    business.email({ domain: "creators.facelessugc.com" }), // verified sender
      phone:    business.phone({ a2p: { brand: "Faceless UGC" } }),     // A2P-registered brand
      cards:    business.cards({ funding: "balance" }),                 // card program
    },
  },

  // ── agents: a blueprint per ROLE ─────────────────────────────────────
  // Naïve stamps out a fresh, isolated copy per creator:
  //   naive.forUser(creatorId).provision("ugc")
  agents: {
    ugc: agent({
      is: identity.agent(),
      //   → make it a real, monetizable business later:
      //   is: identity.business(),   // (requires infrastructure.business.identity)

      // Each copy gets its OWN instance of an enabled program above.
      // You can only `has` what infrastructure.business turned on.
      has: {
        email: true,              // own address under the verified domain
        phone: { voice: false },  // own A2P number, SMS only
        // cards: omitted — content-only creator, no money to move
      },

      can: [
        skills.llm, skills.images, skills.video, skills.clips, skills.media,
        skills.social, skills.search, skills.seo, skills.aeo,
      ],

      limits: {
        budget: "$200/mo",                // alerts at 80%, hard-denies at cap
        approve: [skills.social.publish], // human OK before anything posts
      },
    }),
  },
});
naive up
#  cloud · website + database + storage  → provisioned
#  business · email + phone + cards      → registered
#  agents · ugc                          → ready
# Zero per-tenant resources. No issuing / KYB / carrier calls until provision().

Builders

BuilderPurpose
defineConfig({ project, infrastructure?, runtime?, agents?, systems? })The project root.
cloud.web / cloud.postgres / cloud.bucketShared cloud — web hosting, managed Postgres, object storage. Names are optional (derived from the project).
business.entity / business.email / business.phone / business.cardsThe shared real-world programs. Turning one on registers the parent each agent draws from.
agent({ is, has, can, limits })An agent blueprint (a role), stamped out per user.
identity.agent() / identity.business()The agent’s identity — lightweight, or a real legal entity.
skills.*The capability catalog (e.g. skills.llm, skills.social.publish, skills.compute, skills.mobile). Pass to can / limits.approve.
runtime.pool({ source, isolation, autoscale })A microVM pool for hosted agents (optional; omit for BYO-runtime).
system({ root, members, topology, budget })A multi-agent system composed from agent roles.

The agent block

FieldTypeMeaning
isidentity.agent() | identity.business()Lightweight agent identity, or a real legal entity (needs business.entity).
has{ email?, phone?, cards? }Per-agent instances of enabled business programs. phone accepts { voice?, sms? }; cards accepts { limit? }.
canSkill[]The skills this agent may use. Becomes the allowlist on its policy.
limits.budget"$200/mo" (or { amount, period })Combined cost ceiling — alerts at 80%, hard-denies at cap.
limits.approveSkill[]Skills that require a human OK before they run (e.g. skills.social.publish).

How it’s enforced (not just declared)

When you provision(role), the blueprint is translated into a dedicated AccountKit for that agent and the agent is bound to it:
  • can → an allowlist: only those skills are enabled; the governance gateway refuses anything else with 403.
  • limits.approveescalate-only human-in-the-loop gates on the listed skills (a matching action parks for approval; a non-match never removes a built-in default).
  • limits.budget → a real combined cost ceiling at the gateway. It caps BOTH real-world spend (card limits, top-ups, trading notional) AND platform usage (LLM, search, compute, hosted runtime), summed for the window. A hard cap returns 403 budget_exceeded (race-safe — reserved under a lock before execution); a soft cap routes to human approval; the alert threshold emits a budget.alert event. A multi-agent system shares one cap across all its agents. If a hard cap (or the company’s credit balance) is exhausted, the agent’s hosted runtime is auto-stopped so you stop incurring cost.
So an agent whose can omits skills.trading returns 403 on forUser(id).trading.*, and a budget of $1 (hard) makes a $250 card return 403 budget_exceeded — both verified end-to-end.
For fine-grained control you can still drop to the lower-level agentTemplate({ identity, wallet, comms, policy }) + policy({ allow, deny, approvals, autoApprove, network }) builders under agentProfiles — the agent({...}) DSL compiles down to exactly that.

Multi-agent systems

A system(...) composes a parent/manager agent (which holds the shared budget) with sub-agents, each in its own isolated runtime. Instantiate at run-time:
import { Naive } from "@usenaive-sdk/server";
const naive = new Naive({ apiKey: process.env.NAIVE_SECRET_KEY! });

await naive.runtime("pool").startSystem({
  system: "content", // a standing team declared under `systems` in naive.config.ts
});
Spend aggregates against the parent’s cap at the gateway; revoke(parent) kills the whole system.

How naive up sets up infrastructure

naive up is a plan → apply lifecycle backed by a Naïve-managed executor (no Terraform/Pulumi for you to operate). Each resource maps to a managed backend, which Naïve provisions and keeps reconciled for you:
  • cloud.bucket → a private object-storage bucket.
  • cloud.postgres → a managed Postgres database (created async; the pooled DATABASE_URL is returned as an output once healthy).
  • cloud.webweb hosting. naive up uploads the resource’s dir and triggers a production deployment; env is auto-injected from sibling outputs (the Postgres DATABASE_URL, the bucket name).
  • business.* → the shared real-world programs (entity/email/phone/cards); each agent draws its own instance from them at provision() time.
Resources provision in dependency order (db + storage before web), are advanced idempotently, and reconciled in the background — exactly like agent provisioning.
naive up --plan     # preview the diff (creates / updates / deletes) — read-only
naive up            # apply (+ deploy cloud.web source; --no-deploy to skip)
naive status        # deployment status + resolved outputs (DATABASE_URL, WEB_URL)
naive down          # tear down (previews first; --yes to confirm — destructive)
Credit-gated. Infrastructure scales with what you can pay for: when your credits are exhausted you can’t provision more, and running infrastructure is shut down (web disabled, runtime/compute stopped; database/storage data persists).