underwrit-client
v0.3.0
Published
Client for an Underwrit data plane: decide, claim, record, and produce evidence for what an agent did.
Maintainers
Readme
underwrit-client
Client for a Underwrit data plane, for agent runtimes in TypeScript
and JavaScript. fetch-based, no dependencies, Node 18+ or any modern runtime.
Underwrit decides whether an agent's tool call may run, holds it for a person when it should, and hands back hash-chained, signed evidence of what happened. This package is the twenty lines between your runtime and that API.
import { Underwrit, Held } from "underwrit-client";
const underwrit = new Underwrit("https://underwrit.example.com", process.env.UNDERWRIT_AGENT_TOKEN!);
const s = await underwrit.session({ agent: "ops-assistant", environment: "production",
intent: "Restart api during incident 4417" });
const logs = await s.call("k8s/get_k8s_logs", getLogs, { pod: "api-1" });
try {
await s.call("k8s/rollout_restart", restart, { deployment: "api", namespace: "prod" });
} catch (e) {
if (e instanceof Held) {
park(e.decision.id); // a person answers in the console, then:
await s.resume(e.decision.id, restart, { deployment: "api", namespace: "prod" },
{ verify: (r) => ({ status: "passed", checks: [{ name: "rollout", ok: true }] }) });
} else throw e;
}
await s.close();call()decides, runs the function, and records the outcome. It throwsHeldwhen the data plane saysact: "hold"(enforcement on, verdict held or denied). In shadow mode nothing is thrown and the verdict is still recorded.resume()claims an approval with the same arguments immediately before executing. The claim is refused if the arguments or stated preconditions changed, the approval expired, the policy now refuses it, or it was already used.- Errors whose message says "timeout" are recorded as
uncertain; the data plane refuses a blind retry until someone reconciles it. verifyrecords what was observed afterwards, separately from whether the call succeeded.- 429 and 503 are retried honouring
Retry-After(three times, capped at thirty seconds). decide(..., { signals: { taint: true, risk: 80, source: "my-classifier" } })lets an external classifier raise taint or risk; it can never lower them.- Every decision carries
receipt.seq;underwrit.receipt(seq)returns the Merkle inclusion proof and the signed checkpoint once one covers the entry.
underwrit-client/vercel is a policy adapter for the Vercel AI SDK. The Python client, the MCP stdio
server and the REST reference are in the main repository.
MIT.
