Fibric. Docs fibric.io →
v1.0.0 · stable
Concepts

Architecture

Fibric is one operational layer that senses every system you run, reasons about what is happening, and acts safely. This page is the map: the loop the whole platform runs, the kernel components that implement it, one diagram of how an event becomes an action, and the five seams that let the implementation scale without changing the contract.

The sense, reason, act, receipt loop

Fibric runs one loop. Sense unifies real-time data from siloed systems into one operational picture. Reason is where agentic models understand what is happening, predict what is needed, and plan multi-step action, resolving conflicts before they occur. Act controls systems and dispatches teams, with no new hardware required. And every act step ends the same way: with a receipt, the immutable record of what was proposed, what was decided, and what happened.

Sense

Real-time data from every system, unified into one picture.

Reason

Understand, predict, and plan. Resolve conflicts up front.

Act

Control systems and dispatch teams, gated by policy.

Receipt

Every action leaves its record. Unaccounted means it did not happen.

The act step never reaches a system directly from the model. It always passes through the deterministic executor, which is where policy, single-flight, and idempotency live. That boundary is the subject of propose and dispose below.

Kernel components

The kernel is small on purpose. Six components carry an event from arrival to audit trail, and each has a dedicated page.

Envelope

Everything that happens travels as one canonical EventEnvelope. A Shopify webhook, an MQTT temperature reading, a cron tick, and an operator’s own output all become the same ten-field type, which is what lets the kernel route, govern, and audit anything without special-casing where it came from. Every envelope carries reseller_id and tenant_id; an envelope with no tenant cannot exist. Field reference and construction: The event envelope.

Router

The EventRouter matches an envelope’s event_type to registered operators by glob trigger, where * matches exactly one dot-delimited segment: "order.*" matches "order.created" but not "order.item.added". A matched operator is a function from envelope to ExecutionPlan; in production the function is a model call, but the contract is the same. Routing detail: The event envelope; the workers themselves: Operators.

Trust

Every side-effecting action in a plan is evaluated against the tenant’s TrustPolicy rules, which decide ALLOW, BLOCK, or ALERT. The evaluation fails closed: an action no policy matches is blocked, and any matching policy whose value limit is exceeded or whose predicate fails blocks it too. Detail: Trust tiers and Governance & trust.

Executor

The DeterministicExecutor is the only path from a plan to a real system. It serializes side effects per entity (single-flight on entity_key), collapses repeats on idempotency_key (a duplicate returns DEDUP without invoking), applies the trust decision, and invokes what survives. Reads bypass policy and idempotency and run immediately. Detail: Single-flight & idempotency and Receipts & audit.

Seams

Five infrastructure concerns sit behind stable interfaces so the MVP implementation can be swapped for a scale-up implementation without touching operators, connectors, or policy. The ModelRouter seam is also the kernel’s only model entry point, which makes per-tenant model choice a policy setting rather than code. The full table is below.

Store

PgEventStore persists envelopes to the event_log table under Postgres row-level security. Each transaction sets app.tenant_id and app.reseller_id transaction-locally from a verified context before touching a row, so a query for one tenant can only ever see that tenant’s rows and a request without valid context reads nothing. Detail: Tenancy & isolation.

Above the kernel sit capabilities: operators request them by intent, connectors provide them, and configuration binds the two, which is why swapping one vendor for another is a config change rather than a rewrite.

One diagram

The path from a change in a connected system to an audited action. Everything inside the frame is scoped by the same two fields; nothing crosses the wall.

Notice the diagram has no arrow from the operator to a connected system. That absence is the architecture: the model’s output is a plan, and the only path from a plan to the world runs through the policy gate and the executor.

Propose and dispose

This is the single most important idea in Fibric. The model never acts. It produces a validated execution plan, a list of proposed actions stated as capabilities and arguments. A deterministic executor then disposes of that plan: it validates the shape, checks every action against your policy, and runs what survives, in order. The model proposes; the executor disposes.

Model

Proposes

Reasons over what was sensed and emits a validated plan of capabilities and arguments. Suggestive, never authoritative.

Executor

Disposes

Deterministic. Validates the plan, applies policy, enforces single-flight and idempotency, runs what is allowed, writes a receipt.

Because the dispose half is deterministic and the model cannot reach a system except through it, the boundary between "what the model wants" and "what actually happens" is a hard line, not a hope.

The plan itself is a small, checkable structure. Each PlannedAction names a connector and tool, carries its arguments, an optional value for value-limit policies, an entity_key for single-flight, and an idempotency_key for deduplication:

trust.ts
export interface PlannedAction {
  connector: string;
  tool: string;
  args: Record<string, unknown>;
  value?: number;        // e.g. a refund amount, for max_value policies
  entity_key: string;    // single-flight key — serialize side-effects per entity
  idempotency_key: string; // dedup key for the side-effect
}

export interface ExecutionPlan {
  reasoning?: string;
  actions: PlannedAction[];
}
i
Why the two keys matter

Single-flight on entity_key means two runs cannot both act on the same order or the same door at once. Deduplication on idempotency_key means a retried or repeated action applies once. Together they make the classic runaway, an ungoverned loop that once sent 657 messages to one customer, structurally impossible. Detail: Single-flight & idempotency.

The five swap seams

The kernel is a thin MVP by design. Five infrastructure concerns are isolated behind interfaces in seams.ts, so the implementation behind each can be replaced as load grows while operators, connectors, and policy stay untouched. The interface is the contract; the row describes what currently fills it.

SeamMVP implementationScale-up target
DurableExec In-process, with a Postgres outbox Temporal
EventBus In-process, or EventBridge MSK / Kafka
ModelRouter Policy-routed. The kernel’s only model entry point; ModelPolicy carries a defaultModel and optional per-tenant overrides Same interface; per-tenant override, such as a US-hosted model requirement, is policy, not code
VectorStore pgvector OpenSearch Serverless
BlobStore S3 S3

The seams are also a budget instrument: the MVP row of the table runs the whole platform on ordinary managed Postgres and S3, and the swap to the right-hand column is a per-seam decision made when a tenant’s load demands it, not a rewrite.

Keep going