Skip to content

Connect to a vault

Deploying makes a version available. Nothing runs on a vault’s data until the vault owner connects the agent. A connection is a signed, scoped, revocable agreement between the vault and the agent: the owner signs it with their wallet, and the vault records it with the settings they chose and the code they consented to.

What a connection holds

Part Meaning
Scopes The vault scopes the agent may read and publish in. Each must be in the manifest’s requiredScopes (default default).
Settings Values for the agent’s declared settings, validated against its schema.
Bundle pin The bundle of the version the owner consented to. Dispatch runs exactly that code.
Ceiling Optional spend limits. See Spend limits.

The connection also provisions the agent’s cubbies in the vault.

Connect from ROC

Where How
Workflow Builder Deploy connects the workflow, and any agent it calls, to your vault. Your wallet may ask for your passkey.
Sandbox Pick the agent and a vault; the pill reads agent not connected with a Connect button. When connected, it reads agent connected, with a control to disconnect.
A widget WidgetRuntime.connectAgent() connects the widget’s agent for the signed-in reader.

Reconnect to pick up new code

A connection pins the bundle the owner consented to. Pushing and deploying a new version does not change the code a connected vault runs; the vault keeps running the pinned bundle until the owner reconnects. Routing, params, and the engagement list do follow the deployment; only the code is pinned.

When the code has changed, ROC shows a prompt: “This agent’s code changed since you connected it (was …, now …). Reconnect to the new version?” with Reconnect and Not now. Reconnect signs the consent for the new bundle.

LLM agents have no bundle and pin nothing.

Connect with the vault SDK

import { VaultSDK, CereWallet } from "@cef-ai/vault-sdk";
const sdk = new VaultSDK({
endpoint: vaultApiUrl,
garEndpoint: garUrl, // required for agents.connect
signer: await CereWallet.fromMnemonic(mnemonic), // or KeypairWallet.fromSeed(seed)
});
const vault = await sdk.vault.ensure();
const connection = await vault.agents.connect({
agentId: "<agentServicePubkey>:<alias>",
scope: "default", // or scopes: ["default", "research"]
settings: { apiKey: "…" },
ceiling: { gpuUnits: 500, a2aTokens: 200000 },
bundleCid: reviewedBundleCid, // the code the owner reviewed
});
Input Required Meaning
agentId yes <agentServicePubkey>:<alias>. The pubkey is taken from the prefix unless you pass agentServicePubkey.
scope or scopes one of them The scopes to connect into.
settings no Values for the agent’s settings schema.
ceiling no Spend limits, written together with the connection.
bundleCid no The bundle the owner consented to. Required when reconnecting to a different bundle.

connect signs one consent agreement covering every requested scope, submits it to the agreement registry, and creates the connection. The vault reads the manifest from the registry itself; you never send it.

Reconnect after a new version

import { BundleChangedError, ReconsentRequiredError } from "@cef-ai/vault-sdk";
try {
await vault.agents.connect({ agentId, scope: "default" });
} catch (e) {
if (e instanceof ReconsentRequiredError) {
// Show the owner the new code (e.currentCid), then:
await vault.agents.connect({ agentId, scope: "default", bundleCid: e.currentCid });
} else if (e instanceof BundleChangedError) {
// A new version landed after the owner reviewed; show e.currentCid and ask again.
} else throw e;
}
Error Code Meaning
ReconsentRequiredError RECONSENT_REQUIRED The reconnect would run different code than the owner consented to, and no bundleCid was given. Nothing changed.
BundleChangedError BUNDLE_CHANGED The bundleCid you named is no longer the agent’s current bundle. Nothing was stored.

Manage a connection

const all = await vault.agents.list();
const one = await vault.agents.get(agentId); // status, scopes, bundle, ceiling
await one.update({ apiKey: "…" }); // new settings
await one.setCeiling({ gpuUnits: 1000 }); // new limits
await one.disconnect();

Disconnecting keeps the cubby data.

Spend limits

A connection can carry two limits. Blank or 0 means no limit.

ROC label SDK field Counts
Compute limit — metered GPU units gpuUnits GPU units the platform measured. Decimals allowed.
Token limit — agent-reported a2aTokens Tokens the agent reports about itself. Whole numbers. A stop signal, not a measured cost.

Once the connection’s total reaches a limit, new tasks for that agent in that vault are refused. Spend is counted when a task finishes, so a limit stops the next run after it is crossed, not a run in progress.

In ROC, set limits in the deployment dialog’s Execution rules section: pick the vault, enter the limits, and click Save limits. Limits belong to the connection, not to the deployment revision, so the agent must already be connected to that vault.

Errors

Code Cause Fix
MANIFEST_INVALID A requested scope is not in requiredScopes, or the agent id does not match the manifest. Connect into a declared scope, or push a version that declares it.
MANIFEST_NOT_FOUND No manifest for that agent id in the registry. Check the id and that the agent was pushed.
SETTINGS_SCHEMA_MISMATCH Settings do not satisfy the schema. Fix the values.
AGENT_ALREADY_CONNECTED A connection already exists. Use the existing connection.
GAR_MISSING, GAR_EXPIRED No valid consent agreement. Connect again to sign a new one.
CUBBY_PROVISION_FAILED A cubby migration failed. Fix the migration in a new version.

All codes: Errors.