novo agents
the complete agent · one api

The most capable agents in your stack.
None of the complexity.

Novo runs complete agents behind your product and streams every step into your UI as it happens. Pick a band from fast to frontier. Novo handles the harness, sandboxes, and model routing, and meters every run.

import { NovoAgents } from "novoagents";

const novo = new NovoAgents({
  apiKey: process.env.NOVO_AGENTS_API_KEY,
});

// the complete agent: web, browser, documents included
const agent = await novo.agents.create({
  context: "You are the research agent inside our product.",
  band: "core", // a capability tier that stays at the frontier
  workspace: { type: "managed" },
  capabilities: { web: true, browser: true },
});

// one call in, every step streams back live
const thread = await novo.threads.create({ agentId: agent.id });
const stream = await novo.threads.stream(thread.id, {
  input: "research our top competitors' pricing pages" +
    " and draft a comparison deck",
});

for await (const chunk of stream) {
  if (chunk.type === "data-novo-terminal") break;
}
live stream
01the difference

The whole agent, behind one API.

An agent that actually works is months of plumbing before it does anything useful. Novo is that plumbing, already running.

a model api
Returns text. Tools, loops, sandboxes, budgets, and safety become your roadmap.
a lab's hosted agent
Runs their loop, on their models only. Capable today, captive tomorrow.
novo
The complete agent behind one API. It runs on whichever frontier is best, contained in your infrastructure, metered per run.
what "build it around a model api" actually means
  • · an orchestration harness that plans, delegates, and retries
  • · sandboxed browser and workspace infrastructure
  • · document pipelines for office files, pdf, and export
  • · web research with untrusted-content fencing
  • · per-run metering, budgets, receipts
  • · pause and resume for human approval
  • · and re-tuning all of it every time the models change
call it instead
await novo.threads.stream(thread.id, { input: task });
The glue layer is Novo's product, so it never decays into yours.
02what the agent can do

Every capability, included.

use the web
Research across the live web: search, fetch, and read sources, with outside content kept fenced from instructions.
search · fetch
drive a browser
Click through real websites in a hosted browser: navigate, act, read, screenshot. Nothing for you to run.
navigate · act · read · screenshot
work with documents
Read, create, and edit Office files and PDFs, then export finished versions your users can open.
office · pdf · export
write and run code
A real workspace with files, a shell, and live previews, hosted by Novo or registered on your side.
filesystem · shell · previews
ship to github
Read issues, write branches, open pull requests. Credentials never enter the workspace.
issues · branches · pull requests
make media
Generate images, video, speech, music, and sound effects from the same loop that does the work.
image · video · speech · music
ask a human
Pause for an approval or a missing answer, then pick the thread back up where it stopped.
approvals · questions
bring your tools
Attach your own MCP or OpenAPI tools, with skills to teach the agent when to use them.
mcp · openapi · skills
03current

Pick a band. Novo keeps it at the frontier.

Models churn every few months. A band is a stable envelope of capability and cost that stays at the frontier as the underlying models move. Your API, your prompts, and the shape of your bill stay put.

lite
Everyday, well-defined work at the lowest cost per run.
band: 'lite'
core
The default. Depth where the task needs it, efficiency everywhere else.
band: 'core'
frontier
Maximum intelligence, with a second opinion on consequential decisions.
band: 'frontier'
how a band stays current

Behind each band, an orchestrator routes every task to advisors for judgment and workers for execution, spending stronger routes only where they matter. When better models land, the routing improves under the same band name. GET /v1/bands is the whole contract.

04contained

Runs in our cloud. Contained in yours.

01 · your app
Start a run
Call the SDK and stream results back to your app as they happen.
02 · novo
Run the agent
Novo runs the agent: planning, tools, pauses, retries, and usage tracking.
03 · your adapters
Your data stays yours
Filesystem, shell, MCP, result, and event calls route to endpoints you control.
The full data-flow story: signed adapters, strict data handling, retention → security
05metered

Every run comes with a receipt.

Per-run cost in fractional cents. Hard budgets that stop a run before it overspends. Usage grouped by API key, so you can pass costs straight through to your own customers.

see pricing
RUN RECEIPT
usage.costCents4.21
budgetCents500 · enforced
terminalReasonbudget_exceeded
group byapi key · thread · band · day
06proof

Novo North runs on this API.

Our own AI workspace, Novo North, ships its agents on Novo Agents: every step streams into its UI, consequential actions wait on its approval hooks, and every run lands on a budget and a receipt. Both are Novo Industries products, and the workspace is the platform's first customer.

running in productionagents · streamed UIapproval hooks · result handlersbudgets · receipts
07for coding agents

Building with a coding agent? Paste this.

Copy the setup skill into Claude Code, Cursor, or whatever you build with. Your agent reads it, asks you a few questions, and wires Novo into your project end to end.

SETUP.MD
---
name: novo-setup
description: Wire Novo Agents into a project end to end: install the novoagents SDK, configure the API key, create an agent, add a streaming route, and verify a live run. Use when the user wants to add a Novo agent to their product or start a new integration. Do NOT use to debug an existing integration; read https://novoagents.ai/docs/troubleshooting instead.
---

# Set up Novo Agents in this project

You are a coding agent adding a hosted Novo agent to the user's product. Interview first, then wire it up. Novo runs the complete agent (planning, tools, browser, documents, pauses, retries, metering) behind one API; this project only sends tasks and consumes the stream.

## Facts (do not guess these)

- Install: `npm install novoagents` (or the project's package manager). No peer dependencies.
- The SDK is **server-only**. Constructing it in browser-bundled code throws `NovoConfigurationError` with code `browser_runtime`. Never import it in client components.
- Auth: the SDK reads `NOVO_AGENTS_API_KEY` from the environment. Keys start with `novo_ag_`. **Never ask the user to paste the key into this conversation.** They add it to the env file themselves.
- API base is `https://api.novoagents.ai` (SDK default; no config needed).
- A run is finished when the stream yields the `data-novo-terminal` chunk, **not** when the HTTP stream ends. EOF without a terminal chunk means the connection dropped, not that the run stopped. `stream.streamToCompletion()` handles this: it reconnects until the terminal chunk arrives and returns `{ text, usage, status, terminalReason }`.
- `stream.toResponse()` returns a Web `Response` (SSE) for proxying to a browser. `stream.runId` / `threadId` / `agentId` are available synchronously.
- `band` defaults to `'core'`. Bands are capability tiers, not model names; `novo.bands.list()` reports what is offered, including strict-data-handling availability.
- On Vercel, any route that proxies the stream needs `export const maxDuration = 300` (or your plan's max) or the platform cuts the stream mid-run.
- Runs cost real money from the workspace's prepaid credits. New workspaces get starter credits. Cap any run with `budgetCents`.

## Step 1: Interview the user

Ask in one batch; skip anything the repo already answers:

1. What's your product, and what should the agent do for your users? (This becomes the agent's `context`.)
2. Where should it run: inside this app (detect the framework yourself), or a standalone script first?
3. Which abilities does it need: web search/fetch · a real browser · files and shell · documents (Office/PDF) · media generation · GitHub · your internal APIs?
4. Should it pause for human approval or questions before consequential actions?
5. Is strict data handling (verified zero-data-retention inference routes) required? Default is standard.
6. Rough budget per run? Default cap 500 cents.

Success: you can state the `context` sentence, the band, the capabilities object, and where the route goes. Restate the plan in two sentences and get a yes before writing code.

## Step 2: Map answers to config

| Answer | Config |
|---|---|
| web search/fetch | `capabilities: { web: true }` |
| real browser | `capabilities: { browser: true }` |
| files, shell, documents | `workspace: { type: 'managed' }` (documents are on by default; add `shell: true` for commands) |
| human approval / questions | `capabilities: { userInteraction: true }` |
| media generation | `capabilities: { media: true }` (or per-modality; see docs) |
| GitHub | register a connection first: https://novoagents.ai/docs/api/github-connections |
| internal APIs | register MCP/HTTP tools first: https://novoagents.ai/docs/concepts/adapters |
| strict data handling | check `novo.bands.list()` availability, then `dataHandling: 'strict'` on the run |

Leave `subagents` at its default (on): delegation is Novo's job, not yours.

Success: every interview answer maps to a config field above, or you've told the user what needs registering first.

## Step 3: Install and key

1. Install `novoagents` with the project's package manager.
2. Add `NOVO_AGENTS_API_KEY=` to the env file (`.env.local` or equivalent) and tell the user: create a key at `https://app.novoagents.ai` → **api keys** (it is shown once) and paste it into that file themselves.
3. Confirm the env file is gitignored.

Success: the env var is wired and never appears in code, chat, or commits.

## Step 4: Create the agent once

Agents are configuration, not conversations: create one and reuse its id across threads. Write `scripts/novo-setup.ts`:

```ts
import { NovoAgents } from 'novoagents';

const novo = new NovoAgents();
const agent = await novo.agents.create({
  context: '<the context sentence from the interview>',
  band: 'core',
  // capabilities / workspace from Step 2
});
console.log(agent.id); // ag_...
```

Run it once (`npx tsx scripts/novo-setup.ts`), store the printed id as `NOVO_AGENT_ID` in the env file.

**Checkpoint:** creating an agent is free; runs bill credits. Confirm with the user before Step 5's live run.

## Step 5: Add the route

Next.js App Router (adjust path to the project):

```ts
// app/api/agent/route.ts
import { NovoAgents } from 'novoagents';

export const maxDuration = 300;
const novo = new NovoAgents();

export async function POST(request: Request): Promise<Response> {
  const { input } = (await request.json()) as { input: string };
  const thread = await novo.threads.create({
    agentId: process.env.NOVO_AGENT_ID!,
  });
  const stream = await novo.threads.stream(thread.id, {
    input,
    budgetCents: 500,
  });
  return stream.toResponse(); // SSE to the browser
}
```

Express: `stream.toResponse()` is a Web `Response`. Pipe it with `Readable.fromWeb(response.body)` and copy its headers. Hono/Bun/Deno accept the `Response` unchanged. Standalone script: skip the route and use Step 6's shape directly.

Success: the project typechecks.

## Step 6: Verify with a live run

```ts
const thread = await novo.threads.create({ agentId });
const stream = await novo.threads.stream(thread.id, {
  input: 'Say hello in five words.',
  budgetCents: 100,
});
const result = await stream.streamToCompletion();
console.log(result.text, `cost: ${result.usage.costCents.toFixed(2)}¢`);
```

Success: text prints and a nonzero cost is reported. Failures: 401 → key missing/wrong (check the env var name and the `novo_ag_` prefix); stream ends with no terminal → you consumed raw EOF instead of `streamToCompletion()`.

## Step 7: Consume safely in the UI (if there is one)

- Done means the `data-novo-terminal` chunk, never EOF.
- The wire is AI SDK `UIMessageChunk`s plus `data-novo-*` extensions. Branch on `data-novo-*` first if you validate chunk types.
- For runs longer than one connection, resume with the `Last-Event-Id` header: https://novoagents.ai/docs/guides/reconnect-a-dropped-stream

Success: the UI code branches on `data-novo-*` chunk types and treats only the terminal chunk as completion.

## Step 8: Report back

Tell the user: the agent id, files you created or touched, the smoke run's cost, and the three docs to read next (https://novoagents.ai/docs/concepts/capabilities, https://novoagents.ai/docs/concepts/streaming, https://novoagents.ai/docs/concepts/human-in-the-loop).

Success: the user can point at the agent id, the route file, and the smoke run's printed cost.

## When something fails

- `browser_runtime` → the SDK got into client code; move it behind a server route.
- 401 → wrong or missing key; verify `NOVO_AGENTS_API_KEY` and the `novo_ag_` prefix.
- Stream stops with no terminal chunk → reconnect or use `streamToCompletion()`; on Vercel also check `maxDuration`.
- `409 thread_busy` → the thread has a running turn; the message queues as a follow-up.
- Full error catalog: https://novoagents.ai/docs/errors. The machine-readable docs index is https://novoagents.ai/llms.txt.

Do not invent capability flags: the exact agent schema is https://novoagents.ai/docs/api/agents.
raw file: novoagents.ai/setup.md

Give your product the agent.

Starter credits at signup. Take an agent end to end before you add a card.