@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
| Builder | Purpose |
|---|
defineConfig({ project, infrastructure?, runtime?, agents?, systems? }) | The project root. |
cloud.web / cloud.postgres / cloud.bucket | Shared cloud — web hosting, managed Postgres, object storage. Names are optional (derived from the project). |
business.entity / business.email / business.phone / business.cards | The 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
| Field | Type | Meaning |
|---|
is | identity.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? }. |
can | Skill[] | 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.approve | Skill[] | 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.approve → escalate-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.web → web 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).