SDK v1.4.0

Build

SDKs & CLI

Build on Fibric in code. The Connector SDK lets you define connectors and the tools they expose; the same SDK lets an operator propose a validated ExecutionPlan that a deterministic executor disposes of. First-class TypeScript and Python, one CLI to ship it all.

Install #

Install the CLI once, globally. Then add the SDK to whatever project will hold your connectors and operators. The CLI and the SDKs share a version line, so fibric --version should match the SDK in your project.

TypeScript / Node
# the CLI (Node 18+)
npm install -g @fibric/cli

# the SDK, in your project
npm install @fibric/sdk
Python
# the CLI ships standalone; the SDK is on PyPI (Python 3.10+)
pipx install fibric-cli
pip install fibric

Authenticate #

Log in once with the CLI. This opens a browser, links your workspace, and writes a short-lived token to ~/.fibric/credentials. For CI and servers, mint a non-interactive token and pass it as an environment variable.

bash
# interactive, for your machine
fibric login
fibric workspace use paperco-prod

# non-interactive, for CI / servers
export FIBRIC_TOKEN="fbc_live_..."     # mint with: fibric token create --name ci
fibric whoami                          # confirms the token resolves to a workspace
!
Tokens are tenant-scoped

A token resolves to exactly one workspace and tenant. It can never read or act across the wall into another tenant's data, isolation is enforced by the platform, not by your code. Treat FIBRIC_TOKEN as a secret and rotate it with fibric token revoke.

Define a connector #

A connector is declared with defineConnector. It carries an auth spec and a set of tools. Each tool maps to a capability so operators bind to the capability, not your brand. A tool that changes the outside world sets sideEffecting: true, which forces it to route through the governed executor, where your trust policy can veto it.

TypeScript

TypeScript
import { defineConnector, tool, auth } from "@fibric/sdk";
import { z } from "zod";

export default defineConnector({
  name: "acme-wms",
  summary: "Acme warehouse management system",

  // credentials are resolved from the vault, never hard-coded
  auth: auth.apiKey({ header: "X-Acme-Key", secret: "ACME_API_KEY" }),

  tools: [
    // read-only: senses the world, no side effects
    tool({
      name: "list_open_orders",
      capability: "order.read",
      input: z.object({ since: z.string().datetime() }),
      async run({ input, ctx }) {
        return ctx.http.get(`/orders?status=open&since=${input.since}`);
      },
    }),

    // side-effecting: routes through the governed executor
    tool({
      name: "hold_order",
      capability: "order.hold",
      sideEffecting: true,
      input: z.object({ orderId: z.string(), reason: z.string() }),
      async run({ input, ctx }) {
        return ctx.http.post(`/orders/${input.orderId}/hold`, {
          reason: input.reason,
        });
      },
    }),
  ],
});

Python

Python
from fibric import define_connector, tool, auth
from pydantic import BaseModel

class ListOpenOrders(BaseModel):
    since: str

class HoldOrder(BaseModel):
    order_id: str
    reason: str

connector = define_connector(
    name="acme-wms",
    summary="Acme warehouse management system",
    # credentials resolved from the vault, never hard-coded
    auth=auth.api_key(header="X-Acme-Key", secret="ACME_API_KEY"),
)

# read-only: senses the world, no side effects
@connector.tool(capability="order.read")
def list_open_orders(input: ListOpenOrders, ctx) -> list[dict]:
    return ctx.http.get(f"/orders?status=open&since={input.since}")

# side-effecting: routes through the governed executor
@connector.tool(capability="order.hold", side_effecting=True)
def hold_order(input: HoldOrder, ctx) -> dict:
    return ctx.http.post(
        f"/orders/{input.order_id}/hold",
        json={"reason": input.reason},
    )
i
sideEffecting is the contract

Marking a tool sideEffecting is what makes Fibric governable. Read tools run inline; side-effecting tools become steps in an ExecutionPlan that the executor disposes of one at a time, under single-flight and idempotency. See Governance & trust for the full model.

An operator proposing a plan #

An operator senses, reasons, and then proposes a validated ExecutionPlan. It does not act. plan.submit() hands the plan to the deterministic executor, which checks it against your trust policy, acquires single-flight per entity, applies idempotency keys, and disposes of each step, returning a receipt. The model proposes; the executor disposes.

TypeScript

TypeScript
import { defineOperator, plan } from "@fibric/sdk";

export default defineOperator({
  name: "order-risk-watcher",
  model: "fibric/reason-1",

  async run({ sense, reason }) {
    // 1. SENSE: read through granted capabilities
    const orders = await sense("order.read", { since: "PT24H" });

    // 2. REASON: the base model scores which orders will slip
    const atRisk = await reason.rank(orders, {
      goal: "Find orders that will miss the carrier cutoff.",
    });

    // 3. PROPOSE: build a validated ExecutionPlan. Nothing has acted yet.
    const p = plan();
    for (const order of atRisk.filter((o) => o.willSlip)) {
      p.act("order.hold", {
        orderId: order.id,
        reason: order.why,
        // exactly-once: a retry can never double-hold the same order
        idempotencyKey: `hold:${order.id}:${order.shipBy}`,
      });
    }

    // 4. DISPOSE: the executor enforces policy + single-flight, returns receipts
    return p.submit();
  },
});

Python

Python
from fibric import define_operator, Plan

@define_operator(name="order-risk-watcher", model="fibric/reason-1")
def run(sense, reason):
    # 1. SENSE: read through granted capabilities
    orders = sense("order.read", since="PT24H")

    # 2. REASON: the base model scores which orders will slip
    at_risk = reason.rank(orders, goal="Find orders that will miss the carrier cutoff.")

    # 3. PROPOSE: build a validated ExecutionPlan. Nothing has acted yet.
    plan = Plan()
    for order in (o for o in at_risk if o.will_slip):
        plan.act(
            "order.hold",
            order_id=order.id,
            reason=order.why,
            # exactly-once: a retry can never double-hold the same order
            idempotency_key=f"hold:{order.id}:{order.ship_by}",
        )

    # 4. DISPOSE: the executor enforces policy + single-flight, returns receipts
    return plan.submit()

The returned receipts are the audit trail. Each one records the proposal, the policy rule that allowed it, the idempotency key, and the result, the same record you read in Review receipts & audit.

CLI reference #

One CLI drives the whole loop, from connecting a system to reviewing the receipts it produced. The most-used commands:

CommandWhat it does
fibric loginAuthenticate and link a workspace.
fibric workspace use <name>Select the active workspace and tenant.
fibric connector scaffold <name>Generate a new connector project from a template.
fibric connector validate <dir>Check a connector against the marketplace contract.
fibric connector publish <dir>Publish a versioned connector to the marketplace.
fibric connection createHold credentials for one account of a connector.
fibric operator deploy <file>Deploy an operator from its manifest.
fibric operator run <name> --dry-runShow the ExecutionPlan it would submit, without acting.
fibric policy apply <file>Apply a trust policy.
fibric receipts listList actions taken, with their reasons and results.
fibric receipts exportExport the receipt ledger for compliance.
+
Help is built in

Every command takes --help, and fibric <group> --help lists the subcommands. Add --json to any read command to get machine-readable output for scripting.

REST API #

Everything the SDKs and CLI do runs on a governed REST API, so you can build against Fibric in any language. Submit a plan, read receipts, manage connections and policies, all under the same tenant wall and the same fail-closed executor.

POST /v1/plans
bash
curl -X POST https://api.fibric.io/v1/plans \
  -H "Authorization: Bearer $FIBRIC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "operator": "order-risk-watcher",
    "steps": [
      {
        "capability": "order.hold",
        "args": { "orderId": "SO-44817", "reason": "Proof not approved; will miss cutoff." },
        "idempotencyKey": "hold:SO-44817:2026-06-13"
      }
    ]
  }'

The full surface, every endpoint, parameter table, and method badge, lives in the API reference. For the connector-authoring SDK in depth, see the Connector SDK guide.