Adapters
Adapters are the extension points where Novo calls your infrastructure. They let you bring an agent into your environment while keeping execution and private-network access under your control.
| Adapter | What it does | Spec |
|---|---|---|
| Environment | Hosts the agent's filesystem and shell. Novo POSTs each tool call to your endpoint; you execute it and respond. | Environments |
| Result handler | Receives signed, idempotent callbacks for durable artifact exports or oversized tool-result archive/recovery, depending on top-level artifacts config. | Result handlers |
| Tool server | An MCP server you host; its tools become callable by the agent. | Tool servers |
| HTTP connection | An OpenAPI/Swagger document whose selected operations become Novo-hosted api__* tools. Novo calls the target API directly with a reusable Secret. | HTTP connections |
| Tool approval hook | A signed callback that reviews sensitive tool calls before they execute. | Tool approval hooks |
| Secret context | A bundle of reusable Secrets projected into managed workspace commands. Registered in the console or via SDK/API, and selectable in the agent editor. | Secret contexts |
Why adapters
The hosted Novo loop runs outside your execution environment. Inference runs on Novo's workers with Novo-managed credentials. The agent's filesystem reads, shell commands, and MCP tool calls happen in your environment via signed HTTP callbacks to URLs you register.
That separation is the product: agent work stays on one Novo bill, and your data plane stays under your control.
How adapters get attached
Adapters are registered once at the workspace level and then attached per agent:
const env = await novo.environments.register({
type: 'http_workspace',
name: 'staging',
url: 'https://workspace.acme.dev/novo',
secret: 'env_secret_…', // for verifying Novo's signature on inbound calls
});
const agent = await novo.agents.create({
context: 'You are a refactor bot.',
band: 'core',
workspace: { type: 'remote', environmentId: env.id },
});
The agent's runs route every filesystem/shell tool to https://workspace.acme.dev/novo/*.
HTTP connections and approval hooks are attached separately: HTTP operations
become model tools under capabilities.http, and approval hooks sit under the
agent's approvals policy.
Signed requests
Novo signs every outbound callback (environment tool dispatch, result-handler post, approval hook review) with HMAC-SHA-256 and a timestamp. Your endpoint verifies before doing anything:
import { verifyNovoSignature } from 'novoagents';
const result = verifyNovoSignature({
rawBody: await req.text(),
signatureHeader: req.headers.get('Novo-Signature')!,
secret: process.env.NOVO_ENV_SECRET!,
});
if (!result.valid) return new Response('bad signature', { status: 401 });
Failure reasons are typed: 'signature_header_invalid', 'timestamp_outside_tolerance', 'signature_mismatch'. See Signed callbacks for the full spec.
Rotation
Environment, result-handler, and tool-approval-hook signing secrets rotate through their adapter rotateSecret(...) methods. Tool-server and HTTP-connection bearer auth use reusable Secrets; rotate a Secret with novo.secrets.rotate(secretId, { value }) or point the resource at another Secret with novo.toolServers.update(id, { auth }) / novo.httpConnections.update(id, { auth }).
Failure policy
Each adapter has explicit failure semantics:
- Environment tool failure → the model sees a
tool-output-errorand decides what to do. - Result handler failure → the current artifact export fails. Oversized tool-output recovery reports the failure on
data-novo-tool-result-overflow; managed tools return a tool-output error for the failed export. - Tool server failure → emits
data-novo-tool-server-unavailableand the tool drops out of the agent's toolset for that run. - HTTP connection failure → emits
data-novo-http-connection-unavailablewhen discovery fails; operation-level non-2xx responses are returned to the model as tool output. - Approval hook failure → follows the hook's configured
onHookErrorpolicy (deny,pause, orfail-run).
Before attaching a tool server or HTTP connection to an agent, call
novo.toolServers.test(id) or novo.httpConnections.test(id) to verify the
handshake/spec mapping and see the tools Novo will expose after filtering.
What stays on Novo's side
- Inference and managed-tool credentials.
- Billing, quota, and rate accounting.
- Run persistence and durable stream replay.
- Stream framing and SSE delivery to your SDK clients.
You never deal with these. You only implement the callback surfaces your product needs.
Console vs SDK/API
The console adapters screen covers registration and management for every adapter type, including reusable Secrets and secret contexts, plus the advanced fields behind each register dialog's advanced section: HTTP operation allowlists, MCP tool allowlists, trust flags, schema-loading deferral, required-skill gates, enable/disable, and approval-hook failure policy. A few tuning knobs remain SDK/API-only: result caps, request timeouts, MCP protocol version, and metadata.