Skip to content

Quick Start

  • Rust stable (MSRV 1.75, recommended 1.88+)
  • Python 3.11+ with pip (for Sayiir workflow engine)
  • Docker (for Postgres, Ollama, Whisper)
  • Node.js 18+ (for TypeScript SDK, optional)
Terminal window
brew install just protobuf
Terminal window
# Clone the repo
git clone https://github.com/AriSteffworking/fabric.git && cd fabric
# Start Postgres + Ollama + Whisper
just infra-up
# Configure environment
cp .env.example .env
Terminal window
just dev

The API starts on http://localhost:3001. Verify with:

Terminal window
curl http://localhost:3001/healthz
# {"status":"ok"}

Every consumer app (your SaaS, your mobile app, your internal tool) registers with Fabric to get client credentials.

Terminal window
cargo run -p fabric -- setup \
--app-name "My App" \
--email "dev@myapp.com" \
--password "SecureP@ss1"

Output:

Fabric setup complete.
App: My App (my-app)
Admin: dev@myapp.com
Organization: My App (swift-fox-742)
Organization ID: 5fe20183-...
Add to your consumer app .env:
FABRIC_API_URL=http://localhost:3001
FABRIC_CLIENT_ID=foc_abc123...
FABRIC_CLIENT_SECRET=focs_xyz789...
Terminal window
npm install @fabric-platform/sdk
import { FabricClient } from "@fabric-platform/sdk";
const fabric = new FabricClient({
baseUrl: "http://localhost:3001",
app: {
clientId: process.env.FABRIC_CLIENT_ID!,
clientSecret: process.env.FABRIC_CLIENT_SECRET!,
},
});

Your app’s users sign up through Fabric. Fabric creates the user and a personal org scoped to your app.

// User signs up through your app's UI
const auth = await fabric.auth.signup("alice@example.com", "UserP@ss1");
console.log("User:", auth.user.id);
console.log("Access token:", auth.access_token);

Your server uses token exchange to get a user-scoped client:

// Token exchange: get a client scoped to this user
const userFabric = await fabric.asUser(auth.user.id);
// Submit a workflow as this user
const run = await userFabric.workflows.runs.submit("content/generate", {
input: {
topic: "AI trends in 2026",
tone: "professional",
},
});
console.log("Run:", run.id, run.status);
// Watch the run step-by-step
const watcher = userFabric.workflows.runs.watch(run.id, {
onNodeStarted: (key) => console.log(`> ${key} started`),
onNodeProgress: (key, p) => console.log(` ${key}: ${p.percentage}%`),
onNodeCompleted: (key) => console.log(` ${key} done`),
onRunCompleted: () => console.log("Workflow finished!"),
onRunFailed: (p) => console.error("Failed:", p),
});
// Wait for completion
await watcher.done;
// Get the result
const result = await userFabric.workflows.runs.getResult(run.id);
console.log("Output:", result.output);

Set up a webhook to get notified when workflows complete:

import { createWebhookHandler } from "@fabric-platform/sdk";
// In your Next.js/Express route handler
export const POST = createWebhookHandler(
process.env.WEBHOOK_SECRET!,
{
"workflow.run.completed": async (event) => {
console.log("Run completed:", event.run_id);
const result = await fabric.workflows.runs.getResult(event.run_id!, {
includeArtifacts: true,
});
console.log("Output:", result.output);
console.log("Download:", result.primaryDownloadUrl);
},
"workflow.run.failed": async (event) => {
console.error("Run failed:", event.payload);
},
},
);

During local development, you can skip the full OAuth flow and use dev-header auth:

Terminal window
# Dev mode: authenticate with X-Principal-Id header (no JWT needed)
export AUTH="-H 'X-Principal-Id: 00000000-0000-0000-0000-000000000001'"
# List providers
curl $AUTH http://localhost:3001/v1/providers
# Create an org
curl $AUTH -X POST http://localhost:3001/v1/organizations \
-H 'content-type: application/json' \
-d '{"slug":"acme","name":"Acme Corp"}'
# Run the example pipeline
just example-pipeline