fab0

fab0 privacy notice

This notice describes fab0 from version v0.3.0. It was last changed on 9 November 2026.

Until v0.3.0 is released, the only account that uses fab0's production service is fabtend's own.

Who we are and how to reach us

fab0 is a product of fabtend. fabtend runs fab0 and is the controller of the personal data this notice describes. In this notice, "the operator" is fabtend.

Write to privacy@fab0.dev with any question about this notice or about your data: to ask what fab0 holds about you, to have it corrected or deleted, to object to its use, or to ask for a copy. You may also complain to a data protection authority.

What fab0 is

fab0 is a pipeline driver and the record of its runs, offered as a service. A pipeline is a state machine its user writes as code. fab0 holds each run's state, calls each step at an endpoint the user owns (their own service, an agent's endpoint, or a person's queue), moves the run on when a signal arrives, and keeps the run's record. fab0 decides nothing for its users: it does not judge, approve, merge or label their work.

An account on GitHub, an organization or a person, uses fab0 by installing the fab0 GitHub App. That account is a tenant. The App only reads: repository metadata, issues, pull requests, and the one file .fab0/pipelines.yml. People sign in to fab0 with GitHub, through a remote MCP server for their AI assistants and the same operations over a REST API. A person who can reach one of the tenant's installed repositories is one of its members.

What fab0 keeps

fab0 keeps what it needs to run its tenants' pipelines and to be the record of their runs, which is the service a tenant installs it for. This table is everything it keeps, where, and for how long.

DataStoreWhereKept
A run's record: the inputs it took, its signals, transitions and attempts with their outputs, usage, cost and telemetry, its state and data the run's Durable Object EU while the tenant is installed; deleted 30 days after an uninstall, or when an admin asks once the run's tree has ended
The tenant: its installation, repositories, pipelines and their versions, its members' GitHub logins and ids, and the index of its runs the tenant's Durable Object EU while the tenant is installed, a pipeline version that is neither active nor used by an active run 30 days; deleted 30 days after an uninstall
Executor secrets, encrypted the tenant's Durable Object EU until replaced or deleted; deleted at an uninstall
Applied webhook delivery ids, with each delivery's event and sender's login the tenant's Durable Object EU 7 days
Webhook bodies as GitHub sent them R2 bucket payloads EU 30 days
Event references: a delivery's ids and flat fields Queues EU until consumed, at most 4 days
The catalogue: ids, pipeline and state names, statuses, times and cost totals D1 catalog EU as the record and the tenant
Metrics: one point per transition, with the tenant, run, pipeline, states, signal name and duration Analytics Engine not pinned 3 months
Logs: ids, codes and numbers R2 bucket fab0-logs EU 30 days
Sign-in grants: a person's GitHub user id, hashed tokens, and their tenants and GitHub tokens encrypted KV not pinned an access token 1 hour; a grant 30 days after its last refresh
Pages: a dead letter's run or delivery id the operator's mailbox not pinned as long as the operator keeps them
Mail sent to privacy@fab0.dev the operator's mailbox not pinned as long as the operator needs it to answer

"EU" is Cloudflare's EU jurisdiction: the data is stored in the European Union. A period is when the data is deleted: by a storage rule, a queue's retention, an expiry, Analytics Engine's own retention, or the deletions described below.

The personal data in it: the GitHub logins and ids of a tenant's members, and of the person who caused each GitHub event; a signed-in person's GitHub user id; and a tenant's own id, which identifies a person when the tenant is a person's account. A run's record also holds what the tenant's people, agents and services send into it: signals and their reasons, and each step's outputs. fab0 keeps them as sent, and what they contain is the tenant's choice.

What fab0 never keeps

Where it is kept and who provides it

Cloudflare hosts fab0: its programs, Durable Objects, D1 database, R2 buckets, queues, key-value store, Analytics Engine, and the mail routing of privacy@fab0.dev. Every store marked "EU" in the table is in Cloudflare's EU jurisdiction. The rows marked "not pinned" are not: Analytics Engine and the sign-in grants may be stored outside the European Union. Where fab0's programs run is not controlled either: Cloudflare may run them, and process the data that passes through them, outside the European Union.

The operator's mailbox receives the mail sent to privacy@fab0.dev, and fab0's alerts to the operator, which hold a run's or a delivery's id. It is not pinned to the European Union either.

GitHub is where the events and the sign-ins come from: the App receives the events of the repositories it is installed on, and people sign in with their GitHub account. fab0 writes nothing to GitHub.

When a step fires, fab0 calls the endpoint the tenant's pipeline names, authorized by the tenant's secret, and sends it one id. That endpoint belongs to the tenant or to a service the tenant chose, and reads the step through fab0's API with that id. What it does with what it reads is the tenant's choice.

Who can read it

A tenant's members read its runs and their records through fab0's API, after signing in with GitHub. An admin of one of the tenant's installed repositories can also change its pipelines, set its secrets and delete its records. No one reads a secret's value back.

The operator reads ids, codes and numbers in the logs and metrics to keep fab0 running, and can reach every store through its Cloudflare account to repair the service. It reads a tenant's data only for that, or when the tenant asks.

How it is deleted

When a tenant uninstalls the App, its secrets are deleted at once and its active runs are cancelled. 30 days later, every run of the tenant, its records, its rows in the catalogue and the tenant itself are deleted. If the App is installed again on the same account within those 30 days, nothing more is deleted: the runs, their records and the pipelines are kept.

While the App is installed, an admin of one of the tenant's installed repositories can delete the tenant's records with one call, using their own GitHub token:

curl -fsS -X DELETE "https://mcp.fab0.dev/api/v1/records?tenant=$TENANT" -H "Authorization: Bearer $(gh auth token)"

Before it, set TENANT in your shell to the id of the GitHub account that installed the App, which fab0's whoami tool shows as tenants[].id. The call deletes every run tree of the tenant whose runs have all ended, within minutes: a run and the child runs it started, at every depth, with their records and catalogue rows. It keeps every tree that has a run still active, and the tenant's pipelines, members and secrets. It answers how many runs are being deleted and how many are kept. Calling it again is harmless.

To delete everything at once, delete the records, then uninstall the App: the rest goes 30 days later. The other stores keep their own periods, given in the table: webhook bodies 30 days, delivery ids 7 days, logs 30 days and metrics 3 months, the last two holding ids only. A sign-in grant expires 30 days after it was last refreshed. To have anything else deleted, write to privacy@fab0.dev.

Changes to this notice

When what fab0 keeps, where, or for how long changes, this notice changes with it, and its date above changes. The notice is published from the same source as fab0's releases, which keeps it equal to fab0's own design.