Skip to content

Quickstart

Create an account.

app.canopyhq.dev

Connect and configure an Openrouter key and model.

app.canopyhq.dev/inference

Terminal window
bun/npm/pnpm add @canopyhq/sdk zod

This is the schema and metadata that will be presented for the tenant to consent to; separate from the execution definition.

import * as z from "zod";
import { Canopy, appdoc, bind, declare, propose, type Bindings } from "@canopyhq/sdk";
const tools = {
refund: declare({
description: "refund a payment",
input: z.object({ amount: z.int(), customer: z.string() }),
output: z.object({ refunded: z.int() }),
}),
};

Combine tool metadata and application-wide metadata into an Application Document which will be presented to tenant for consent.

const document = appdoc({ name: "payhq", description: "moves money" }, tools);

Propose the composed Application Document, then store the retrieved key upon consent.

const proposal = await propose(document);
console.log("consent at", proposal.consentUrl);
const { key } = await proposal.granted();

Define executors for tools and open a session.

const refunds = (ledger: Ledger): Bindings<typeof tools> => bind(tools, {
refund: async ({ amount, customer }) => ({ refunded: await ledger.refund(customer, amount) }),
});
const canopy = new Canopy({ key });
const session = await canopy.open({
principal: "user:aiden",
instructions: "Help customers with their payments.",
tools: refunds(ledger),
});

Await a single turn and close the session.

const turn = await session.send("refund c-9 five dollars");
console.log(turn.reply, turn.finish);
await session.close();

Read the first twenty events of the session.

for await (const record of session.records({ from: 0, to: 20 })) {
console.log(record);
}
Session 7c1e…a9f2
Every record the session landed, in order. This is the audit trail.
#producerkind
user:sammessage“refund invoice 4471, it was billed twice”
harnessinference.requestedturn #2 · round 1
inferenceinference.completedsealedcalls refund · 1,204 prompt tokens
authorizerinvoke.allowedrefund · released to its executor
executorinvoke.completedsealedrefund · result sealed · digest c02d7e19…
inferenceinference.completedstop · “Refunded invoice 4471 (re_3k9).” · 1,388 prompt tokens
harnessturn.endedturn #2 · completed