Onboard from your app
Your app already has the data: a phone app reads a watch’s heart rate, a web app holds a person’s notes. Write it into the person’s vault, and any agent or workflow they connect to that scope can work on it. Onboarding needs no agent and no agreement: the person writes their own data into their own vault, under their own key.
The running example: an iOS app writes heart-rate readings into a health scope.
Before you start
@cef-ai/vault-sdk5.5.0.- A
Signerfor the person:CereWallet.fromMnemonic(...)orCereWallet.fromKeystore(...)for the wallet on the device, orKeypairWallet.fromSeed(...)for a server acting as the person. - Your vault API URL and chain URL.
1. Construct the client with the person’s signer
import { VaultSDK, CereWallet } from "@cef-ai/vault-sdk";
const sdk = new VaultSDK({ endpoint: config.vaultUrl, chainUrl: config.chainUrl, signer: await CereWallet.fromMnemonic(mnemonic),});Every request is now signed with the person’s key, so the vault authorizes it because it descends from their wallet, not from a secret you hold.
2. Open their vault
const vault = await sdk.vault.ensure({ name: "My Vault" });On first use this claims and provisions the vault; afterwards it returns the
existing one. If it throws OnboardingRequiredError, run @cef-ai/account’s
provisioning.ensure and retry. See
Work with the Vault SDK.
3. Give the data its own scope
A scope of its own lets the person connect a fitness agent to exactly this data and nothing else.
async function ensureScope(name: string, displayName: string) { const existing = await vault.scopes.list(); if (!existing.some((s) => s.name === name)) { await vault.scopes.create({ name, displayName }); }}
await ensureScope("health", "Health");4. Publish the readings
Each reading is one event. Use one context per metric so each history is its
own stream, and stable, namespaced types: agents subscribe on them, and the
payload shape is the contract their handlers read.
const health = vault.scope("health");
for (const s of await readWatchSamples()) { await health.publish({ type: "health.heart_rate", context: "heart-rate", payload: { bpm: s.bpm, measuredAt: s.timestamp }, });}publish sends one event and throws if the vault rejects it, so a resolved call
means the reading is stored. Track what you already sent on your side: the same
reading published twice is two events.
5. Store files as objects
For files (a workout export, an audio note), upload an object and announce it in the same call:
await health.objects.upload(`exports/${day}.json`, bytes, { contentType: "application/json", publishEvent: { type: "health.export", context: "exports", payload: { day } },});The event’s payload gets the object’s vaultPath, so an agent can fetch it.
6. Read back what you wrote
const { items: streams } = await health.streams.list();const page = await health.stream("heart-rate").events.list({ limit: 50 });for (const e of page.items) console.log(e.type, e.payload);Pass page.nextCursor as cursor while page.hasMore is true.
7. Let an agent work on it
The data is in the vault. To have an agent or workflow act on it, the person
connects it to the same scope. That signs an agreement, so the SDK also needs
garEndpoint:
await vault.agents.connect({ agentId: "<agentServicePubkey>:fitness-coach", scope: "health",});From here the agent reacts to every reading you publish. See Connect to a vault.