SDKs
Fibric ships one SDK today: TypeScript. It carries the same types the kernel is written in, EventEnvelope, ExecutionPlan, PlannedAction, TrustPolicy, so what you compile against is what the platform runs. Other languages are planned but not shipped, and this page says so plainly rather than listing installers that do not exist yet.
Language support
| Language | Package | Status | Notes |
|---|---|---|---|
| TypeScript / JavaScript | @fibric/sdk, @fibric/connector-sdk | available (preview) | The primary SDK. Kernel types re-exported directly; Node 18+. |
| Python | — | planned | Next in line. Until it ships, Python services use the HTTP API directly. |
| Go | — | planned | No date committed. The HTTP API is stable enough to build against today. |
The SDK is a typed convenience over the public HTTP API, not a privileged path. A planned language is a missing convenience, not a missing capability. Connectors are additionally reachable over MCP, which is language-neutral by design.
Installation
Two packages, two jobs. @fibric/sdk is the client: call the platform from your application or service. @fibric/connector-sdk is the authoring kit: build things that plug into the platform. Most integrations need only one of them.
# call the platform from your app
npm install @fibric/sdk
# build connectors and operator packs
npm install @fibric/connector-sdk
Client initialization
The client takes a token and nothing else it strictly needs. A token resolves to exactly one tenant, so there is no tenant parameter to pass and no way to pass the wrong one: isolation is a property of the credential, enforced by the platform, not an argument your code gets right.
import { Fibric } from '@fibric/sdk';
const fibric = new Fibric({
token: process.env.FIBRIC_TOKEN!, // mint with: fibric auth login, or a CI token
// baseUrl: 'https://api.fibric.io', // default
// timeoutMs: 30_000, // default
});
// the token's tenant is your whole world
const me = await fibric.whoami();
// { tenant_id: 't_8f2a...', reseller_id: null, workspace: 'paperco-prod' }
Typed envelopes, plans, and receipts
The SDK re-exports the kernel's types, so the envelope you publish and the plan you inspect are the same shapes documented on the envelope and governance pages. The two you will handle most:
import type { EventEnvelope, ExecutionPlan, PlannedAction } from '@fibric/sdk';
// EventEnvelope: the one canonical event
// {
// event_id, reseller_id, tenant_id, workspace_id,
// source, event_type, correlation_id, payload,
// agent_id, session_id
// }
// ExecutionPlan: what an operator proposes
// { reasoning?: string; actions: PlannedAction[] }
// PlannedAction: one governed side effect
// { connector, tool, args, value?, entity_key, idempotency_key }
Publishing an event and reading what came of it round-trips through those types with nothing lossy in between:
// publish an observation; the router matches operator triggers against event_type
const env = await fibric.events.publish({
source: 'warehouse-app',
event_type: 'pick.exception',
payload: { lane: 'B4', order_id: 'SO-11290' },
});
// everything downstream shares the envelope's correlation_id
const plans = await fibric.plans.list({ correlation_id: env.correlation_id });
const receipts = await fibric.receipts.list({ correlation_id: env.correlation_id });
for (const r of receipts.items) {
// decision is 'ALLOW' | 'BLOCK' | 'ALERT' | 'DEDUP' — the executor's disposition
console.log(r.action.tool, r.decision, r.ok);
}
A receipt's decision field carries the executor's disposition for the action: the kernel's TrustDecision (ALLOW, BLOCK, ALERT) plus DEDUP for a side effect that was collapsed into an earlier identical one. A BLOCK is a receipt too; fail-closed refusals are part of the audit trail, not an error you lost.
Configuration
The client reads its environment before its constructor, so the same code runs locally and in CI without branching. Constructor options win when both are set.
| Option | Environment variable | Default | Notes |
|---|---|---|---|
token | FIBRIC_TOKEN | — | Required. Mint interactively with fibric auth login, or a tenant-scoped CI token from workspace settings. |
baseUrl | FIBRIC_BASE_URL | https://api.fibric.io | Point at fibric dev's local kernel during development. |
timeoutMs | FIBRIC_TIMEOUT_MS | 30000 | Per-request timeout. Retries on 429 and 5xx are built in with backoff; see rate limits. |
A FIBRIC_TOKEN resolves to one tenant and can read that tenant's receipts and submit plans into it. Keep it out of source, rotate it like any credential, and prefer short-lived CI tokens over long-lived personal ones.
Pagination
Every list endpoint pages the same way: an items array and an opaque cursor that is present while there is more. The SDK also wraps the loop in an async iterator, which is the form most code should use.
// explicit cursor loop
let cursor: string | undefined;
do {
const page = await fibric.receipts.list({ since: '2026-06-01', cursor, limit: 200 });
handle(page.items);
cursor = page.cursor; // undefined on the last page
} while (cursor);
// or let the SDK drive the cursor
for await (const receipt of fibric.receipts.iterate({ since: '2026-06-01' })) {
handle([receipt]);
}
| Parameter | Type | Notes |
|---|---|---|
limit | number | Page size, 1 to 200. Default 50. |
cursor | string | Opaque. Pass back exactly what you received; do not construct or parse it. |
since / until | string | ISO 8601 bounds, accepted by all time-ordered lists. |
Errors
The client throws FibricError with the HTTP status, the stable error code, and the request id. One case deserves special handling: a plan submission whose actions are all blocked is not a thrown error. The submission succeeded; the executor disposed, fail-closed, and the dispositions are in the result. Inspect decision per action rather than wrapping submissions in try/catch and hoping.
import { FibricError } from '@fibric/sdk';
try {
const result = await fibric.plans.submit(plan);
for (const r of result.actions) {
if (r.decision === 'BLOCK') console.warn('fail-closed:', r.action.tool, r.error);
}
} catch (e) {
if (e instanceof FibricError) {
// e.status (HTTP), e.code (stable string), e.requestId (for support)
if (e.status === 429) { /* backoff is built in; this is the ceiling */ }
}
throw e;
}
The full code table lives on the errors page; rate-limit behavior on rate limits & quotas.
Keep going
- API overview: the HTTP surface the SDK wraps, endpoint by endpoint.
- Connector SDK: the authoring kit, if you are building rather than calling.
- The event envelope: the full field reference for
EventEnvelope. - CLI reference: minting tokens and tailing receipts from a terminal.