Fibric. Docs fibric.io →
v0.9 · preview
Reference

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

LanguagePackageStatusNotes
TypeScript / JavaScript@fibric/sdk, @fibric/connector-sdkavailable (preview)The primary SDK. Kernel types re-exported directly; Node 18+.
PythonplannedNext in line. Until it ships, Python services use the HTTP API directly.
GoplannedNo date committed. The HTTP API is stable enough to build against today.
i
Anything that speaks HTTP can integrate now

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.

terminal
# 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.

client init
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:

kernel types, re-exported
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 and trace
// 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.

OptionEnvironment variableDefaultNotes
tokenFIBRIC_TOKENRequired. Mint interactively with fibric auth login, or a tenant-scoped CI token from workspace settings.
baseUrlFIBRIC_BASE_URLhttps://api.fibric.ioPoint at fibric dev's local kernel during development.
timeoutMsFIBRIC_TIMEOUT_MS30000Per-request timeout. Retries on 429 and 5xx are built in with backoff; see rate limits.
!
Treat the token like the production secret it is

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.

pagination pattern
// 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]);
}
ParameterTypeNotes
limitnumberPage size, 1 to 200. Default 50.
cursorstringOpaque. Pass back exactly what you received; do not construct or parse it.
since / untilstringISO 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.

error handling
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