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.
# the CLI (Node 18+)
npm install -g @fibric/cli
# the SDK, in your project
npm install @fibric/sdk
# 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.
# 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
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
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
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},
)
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
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
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:
| Command | What it does |
|---|---|
fibric login | Authenticate 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 create | Hold credentials for one account of a connector. |
fibric operator deploy <file> | Deploy an operator from its manifest. |
fibric operator run <name> --dry-run | Show the ExecutionPlan it would submit, without acting. |
fibric policy apply <file> | Apply a trust policy. |
fibric receipts list | List actions taken, with their reasons and results. |
fibric receipts export | Export the receipt ledger for compliance. |
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.
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.