@openbox-ai/openbox-sdk-ts
v1.0.1
Published
OpenBox TypeScript base SDK — shared governance, signing, and instrumentation behavior for Node/TS framework SDKs
Readme
@openbox-ai/openbox-sdk-ts
The OpenBox TypeScript base SDK — a contract-driven governance client for
Node/TS agent frameworks. It signs and sends governance events to OpenBox
Core, enforces verdicts (allow / constrain / require_approval / block
/ halt), and gives framework SDKs (Mastra, and future adapters) a shared,
hardened foundation instead of each reimplementing signing, validation, and
instrumentation. It plays the same role for the TypeScript SDK family that
openbox-sdk-python plays for Python.
Status
Contract-driven, not framework-driven: behavior is reproduced from the
canonical OpenBox Core wire contract and the hardened Python base SDK, then
verified against ported golden fixtures and a real Core-parity gate — a Go
harness that unmarshals TS-emitted payloads into Core's own SpanData struct
and independently verifies Ed25519 signatures. See
docs/source-of-truth.md and
docs/contract-conflict-ledger.md for the
full source hierarchy and every documented conflict + resolution.
This is a 0.1.x release: the wire contract, signing, config, client,
runtime, and Tier A1 Node instrumentation (fetch/fs/functions) are
implemented and tested. Database instrumentation (Tier A2/B) has
documented coverage gaps — most notably,
redis blocking covers client.sendCommand([...]) only; normal typed usage
(.get(), .set(), ...) is neither blocked nor observed. Read the
limitations before relying on this for defense-in-depth blocking.
What it owns
Contracts, layered config, identity/signing, an HTTP client, an always-strict
validation gate, a runtime/context composition root, span builders and wire
projection, hook evaluation, Node instrumentation, and a conformance kit for
testing adapters built on top of it. A framework SDK consumes this package and
keeps only its own lifecycle mapping (a thin adapter) — see
docs/framework-adapter-guide.md.
Install
npm install @openbox-ai/openbox-sdk-tsRequires Node.js >=24.10.0. See docs/installation.md
for optional peer drivers (pg, redis, mysql2, mongodb) and the
import-light root guarantee.
Quick start
Config → runtime → evaluate
OpenBoxRuntime is the recommended entry point: it owns the low-level
OpenBoxClient, the always-strict validation gate, and your
FrameworkAdapter, and it enforces the verdict for you (throws on
BLOCK/HALT, drives approval on REQUIRE_APPROVAL). See
why the client alone isn't enough
before wiring OpenBoxClient directly in your own code.
import { OpenBoxConfig } from "@openbox-ai/openbox-sdk-ts/config";
import { OpenBoxRuntime } from "@openbox-ai/openbox-sdk-ts/runtime";
import { Verdict, workflowStarted } from "@openbox-ai/openbox-sdk-ts";
const config = OpenBoxConfig.resolve({
apiUrl: "https://core.openbox.ai",
apiKey: process.env.OPENBOX_API_KEY! // "obx_live_..." or "obx_test_..."
});
const runtime = new OpenBoxRuntime(config);
// Throws GovernanceBlockedError/GovernanceHaltError on BLOCK/HALT; awaits the
// adapter's approval flow on REQUIRE_APPROVAL. Reaching the next line means
// governance let the workflow proceed.
const result = await runtime.evaluateLifecycle(
workflowStarted({ workflowId: "wf-1", runId: "run-1", workflowType: "order-fulfillment" })
);
console.log(result.verdict); // e.g. Verdict.ALLOW
runtime.close();Building a framework adapter rather than calling the SDK directly? Read
docs/framework-adapter-guide.md first —
it covers implementing FrameworkAdapter, driving hooks via
ContextStore.activityScope, and a fail-closed pitfall that is easy to
reintroduce at the wrapper layer.
Opt-in Node instrumentation
initOpenBoxInstrumentation installs governance patches for fetch,
node:http/node:https (preflight-blockable, same as fetch — covers
axios/got/node-fetch@2/superagent and other node:http-based clients that Node's
undici fetch bypasses), fs.promises (async, preflight-blockable), sync fs
(readFileSync/writeFileSync/mkdirSync, completed-hook telemetry only — see
the coverage doc), traced()-wrapped functions, and (opt-in per driver) pg,
redis, mysql2, mongodb. instrumentation.httpEnabled toggles fetch +
node:http + node:https together, and instrumentation.fileEnabled toggles both
the async and sync file hooks together. Nothing is patched on import — only
inside this call, and only for drivers you name:
import { initOpenBoxInstrumentation } from "@openbox-ai/openbox-sdk-ts/instrumentation";
const instrumentation = initOpenBoxInstrumentation({
runtime,
databases: ["pg"] // explicit opt-in — never auto-detected
});
// later, on shutdown — await flush() first so the last sync-fs completed-hook
// telemetry (which the sync wrapper fires after returning) is not dropped.
await instrumentation.flush();
instrumentation.shutdown();See docs/instrumentation-coverage.md for
exactly what each target blocks vs. passes through unblocked (the redis and
mongodb gaps in particular).
Public exports
The package root is intentionally import-light: it re-exports only pure
contracts and errors (no crypto, network, or OpenTelemetry), so
import "@openbox-ai/openbox-sdk-ts" has zero side effects. Everything else is a
subpath, added as real consumers need it.
| Import | Contents |
|---|---|
| @openbox-ai/openbox-sdk-ts | SDK_VERSION; Verdict + verdict helpers; EvaluationResult/ApprovalResult/GuardrailsResult; EventEnvelope/EventType + event factories (workflowStarted, activityStarted, hook, handoff, ...); span field matrices + diagnostics; ActivityContext; the full error hierarchy; strict gate helpers (prepareLifecyclePayload, prepareHookPayload, ...) |
| @openbox-ai/openbox-sdk-ts/adapters | FrameworkAdapter interface + the default CoreAdapter |
| @openbox-ai/openbox-sdk-ts/approvals | ApprovalPoller — HITL poll-loop orchestration |
| @openbox-ai/openbox-sdk-ts/client | OpenBoxClient — the governance HTTP client (evaluate/pollApproval/validateApiKey) |
| @openbox-ai/openbox-sdk-ts/config | OpenBoxConfig — layered env resolution + validation |
| @openbox-ai/openbox-sdk-ts/conformance | FakeCore/FakeAdapter, scenario matrices, wire-shape assertions (test utility, not a frozen API) |
| @openbox-ai/openbox-sdk-ts/context | ContextStore — per-runtime AsyncLocalStorage activity binding |
| @openbox-ai/openbox-sdk-ts/identity | AgentIdentity + Ed25519 signing primitives |
| @openbox-ai/openbox-sdk-ts/instrumentation | initOpenBoxInstrumentation, traced(), recursion-guard helpers |
| @openbox-ai/openbox-sdk-ts/runtime | OpenBoxRuntime composition root + HookEvaluator |
| @openbox-ai/openbox-sdk-ts/package.json | Raw package metadata (for tooling) |
Documentation
docs/installation.md— install, engine requirement, optional DB peers.docs/framework-adapter-guide.md— how to build a framework adapter on top of this SDK.docs/adapter-checklist.md— a checklist for future TS SDKs adopting this base.docs/instrumentation-coverage.md— exactly what Node instrumentation blocks vs. passes through.docs/source-of-truth.mdanddocs/contract-conflict-ledger.md— the source hierarchy this SDK is verified against, and every documented contract conflict + resolution.CHANGELOG.md.
Development
npm install
npm run lint # eslint (flat, type-checked)
npm run typecheck # tsc --noEmit
npm run test # vitest + v8 coverage
npm run build # tsup (ESM, bundle:false, dts)
npm run pack:check # npm pack --dry-run
npm run import:check # asserts the built root stays import-lightLicense
MIT — see LICENSE.
