| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Causality as a Service. You publish that you are fucking around. You subscribe to find out.
The pitch: copyleftdev.github.io/fafoaas — the landing page the category deserves.
An event-driven reimagining of FOAAS, of blessed memory — and, beneath the jokes, a complete, working masterclass in specification-first engineering: two formal specs, a validation gate, polyglot code generation, spec-derived contract tests, a generated MCP server with live conformance checks, and mutation testing that proves none of it is decorative.
Every joke in this repository is load-bearing. heeded: const false is a punchline and a schema constraint. That is the whole idea.
FOAAS understood something profound: any sentiment, however severe, can be delivered as a message and a subtitle. But FOAAS was request/response — you asked to be told off, and you were told off, synchronously, within an HTTP round trip. A simpler time.
FAFO cannot be request/response, because nobody has ever found out synchronously. Fucking around is a command. Finding out is an event. Between them lies a nondeterministic delay, a correlation ID, and everything you were warned about. That is not an API — that is an event-driven architecture, and it deserves a contract.
sequenceDiagram
participant A as Actor
participant F as Causality Fabric
participant B as Bureau of Consequences
participant W as Witnesses
A->>F: IntentDeclared (fafo/v1/around/dave)
F->>B: audit + severity forecast
B-->>A: WarningIssued (fafo/v1/warnings/dave)
Note over A: warning received.<br/>heeded: false (const)
A->>F: AroundEscalated
Note over B: time passes.<br/>the integral accumulates.
B->>A: ConsequenceMaterialized (fafo/v1/findout/dave)
B->>W: ToldYouSoBroadcast (fafo/v1/toldyouso)
A->>F: LessonRecorded (willDoItAgainAnyway: true)
The full normative text lives in spec/asyncapi.yaml — the contract is the architecture.
Twice over:
Because it's funny. FOAAS was a monument to the idea that engineering rigor and a sense of humor are not enemies. This is a homage in its spirit: the sacred message/subtitle wire format is preserved as a frozen schema, the errors are non-appealable by type-level const, and the reference server's severity engine literally cannot attenuate consequences — the conformance suite checks.
Because spec-first is best learned on a system small enough to hold in your head and complete enough to be real. Most codebases show you one slice of this discipline. This one runs the entire ladder, end to end, with every rung executable:
specs (AsyncAPI 3.0 + TypeScript-first MCP schema)
│ modular $ref architecture · request/reply · traits · correlation IDs
▼
validation gates (5 stages, local, no cloud CI)
│ asyncapi CLI · tsc · generated-artifact sync · cross-spec drift (B5)
▼
polyglot codegen (one command)
│ Go · Python · TypeScript — models + contract constants
▼
contract tests (derived, not written)
│ valid vectors = spec examples · invalid = systematic mutations
▼
a generated MCP server (runnable, stdio)
│ protocol surface 100% derived · reference causality engine
▼
server conformance (a real MCP client walks the spec — 14 checks)
▼
mutation testing (98 mutants across clients, specs, and server — 100% killed)
If you work through this repo, you will have seen — running, verified, mutated — every major idea in contract-driven development.
Each chapter names the artifact to read, the command to run, and the transferable lesson. Do them in order; the ladder builds.
Read: spec/asyncapi.yaml, then spec/README.md for the module architecture.
The root document is wiring only — identity, the Laws, operation topology, and a stable pointer index. Substance lives in single-responsibility modules (spec/channels/, spec/components/schemas/, spec/components/messages/) composed by $ref, with dependencies pointing strictly downward. Study:
Lesson: a contract is a module system. Design the dependency direction and the public surface first; prose comes last.
Read: spec/mcp/FAFO-MCP.md, then spec/mcp/schema.ts.
The MCP layer mirrors how Anthropic defines the official MCP specification itself: TypeScript first (schema.ts is the source of truth), JSON Schema generated for wider compatibility (schema.json, never hand-edited), markdown as prose that defers to the schema. The prose declares its own precedence order in §0: where document and schema disagree, the schema wins and the document has a bug.
The seven binding rules (B1–B7) derive the MCP surface from the AsyncAPI document: send-operations become tools, receive-operations become subscribable resources, replies become deferred results correlated by _meta.fafoId, payload schemas are shared — never copied.
Lesson: when two protocols must expose one domain, don't write two specs. Write one, and derive the second under explicit, numbered rules.
Run: npm run validate — read scripts/validate.sh and scripts/check-b5-drift.mjs.
Five stages: validate the modular AsyncAPI tree → bundle and re-validate → typecheck schema.ts → regenerate schema.json and fail on hand-edits → the B5 drift gate, which semantically diffs the generated MCP definitions against the bundled AsyncAPI schemas (types, enums, required sets, bounds, consts — normalizing away representation differences like const vs single-value enum and inlined vs referenced schemas).
Lesson: "keep these in sync" is not an instruction to reviewers, it's a program. If a rule matters, make its violation a nonzero exit code.
Run: npm run codegen — read scripts/codegen.mts.
One command emits self-contained packages: gen/go/fafo, gen/python/fafo (stdlib-only), gen/typescript/fafo. Models come from schema.json via quicktype; contract constants (channel addresses, Kafka topics, error codes, tool annotations, resource templates) come from the generator importing schema.ts directly — the source of truth drives codegen by execution, not by parsing. Output is byte-deterministic across runs.
// Go
fafo.Intent{Category: fafo.ProductionDeploy, Recklessness: 9, ...}
fafo.ErrNonAppealable // -32042# Python
from fafo import models, FafoErrorCode
intent = models.Intent.from_dict(payload)
FafoErrorCode.NON_APPEALABLE # -32042// TypeScript
import { Convert, TOOL_ANNOTATIONS } from "./gen/typescript/fafo";
TOOL_ANNOTATIONS.fuck_around.destructiveHint // true. self-evidently.Lesson: if your schema language is executable, your codegen needs no parser. And determinism is a feature you test, not an accident you hope for.
Read: the vector synthesis in scripts/codegen.mts, then any harness: gen/go/fafo/contract_test.go, gen/python/fafo/contract_test.py, gen/typescript/fafo/contract.test.ts.
Codegen synthesizes a language-neutral vectors.json: valid vectors are the AsyncAPI message examples, verbatim; invalid vectors are systematic mutations against the schema — every required field dropped, every enum violated, every property wrong-typed, every numeric bound broken (57 vectors). Add a field to the spec and new test cases appear in all three clients on the next run.
The honest part: the three generated clients don't validate identically, so each harness declares its validation envelope — Go (encoding/json) rejects type violations only; Python and TypeScript also reject enum and missing-required; nobody enforces numeric bounds. Unenforced kinds are counted as skipped: documented leniency, not an oversight.
Lesson: test data should have provenance. And when implementations differ, document the difference in the tests instead of averaging over it.
Run: npx tsx gen/typescript/fafo-server/server.ts (a real MCP server over stdio) — read gen/typescript/fafo-server/.
Point an MCP host at it and fuck around interactively:
claude mcp add fafo -- npx tsx gen/typescript/fafo-server/server.tsLesson: a spec you can't run a conformance suite against is a wish. Generate the reference implementation and interrogate it over the real protocol.
Run: npm run test:mutation — read scripts/mutation-test.mts.
Three mutant populations, three oracles, every mutant must die:
| Population | Example mutants | Oracle |
|---|---|---|
| Clients | wire-key renames (derived from covered vector keys, per language), Python validation-stripping, corrupted constants | generated contract tests |
| Specs | enum divergence, bound divergence, const flips, dropped required fields, an unwired channel, schema.ts drift | the validation gate |
| Server | a server claiming fuck_around is safe; a broken homage subtitle; a Bureau that attenuates consequences | server conformance |
The harness verifies a green baseline before mutating (a red suite kills everything vacuously), applies each mutant in isolation, restores, and re-verifies green. Every mutation operator throws if its pattern goes stale, so regenerated code can't silently shrink the mutant population. Survivors are named and fail the run. Current score: 98/98 killed.
Lesson: coverage tells you what your tests execute. Mutation tells you what your tests constrain. Only the second one matters.
The AI story runs in both registers, like everything else here:
claude mcp add fafo -- npx tsx gen/typescript/fafo-server/server.tsThe repo now includes live dogfood harnesses that use the generated MCP server over the real protocol instead of merely admiring the contract from a distance. They are deliberately theatrical, because agent evals should be memorable, but the checks are concrete: tool annotations, subscriptions, deferred replies, _meta.fafoId, materialization, ledgers, lessons, and post-conclusion errors.
npm run dogfood
npm run dogfood:startup
npm run dogfood:chaosThe largest scenario, dogfood:chaos, simulates BurnRate AI, a fully agentic startup where every department has automated itself just enough to become a compliance event. Twelve staff agents subscribe to their own findout streams, declare intent, escalate selected threads, wait for materialization, record lessons, and then prove a concluded thread rejects further escalation.
Current representative chaos run:
{
"startup": "BurnRate AI",
"staff": 12,
"materialized": 12,
"biblical": 5,
"disproportionate": 1,
"proportional": 6,
"highestSeverity": 27,
"averageSeverity": 15.48,
"updates": 12
}There is also a terminal demo intended to be sent to another human before they ask why any of this exists:
npm run demo:terminal
asciinema rec --overwrite --quiet --cols 100 --rows 32 \
-c 'npm_config_loglevel=silent npm run demo:terminal' \
demo/fafo-chaos.cast
agg demo/fafo-chaos.cast demo/fafo-chaos.gifThe generated GIF lives at demo/fafo-chaos.gif. The GitHub Pages copy lives at docs/assets/demo/fafo-chaos.gif.
| Command | What it does |
|---|---|
| npm run validate | 5-stage spec gate: AsyncAPI tree → bundle → tsc → schema.json sync → B5 drift |
| npm run codegen | validate, then generate Go/Python/TS clients + fafo-mcp server, then run all contract tests + server conformance |
| npm run dogfood | live MCP smoke: subscribe, fuck around, find out, record a lesson |
| npm run dogfood:startup | multi-actor startup scenario: Pivot Labs finds out in four threads |
| npm run dogfood:chaos | full agentic-staff chaos scenario: BurnRate AI, 12 actors, escalations, ledgers |
| npm run demo:terminal | terminal-rendered BurnRate AI incident room, suitable for GIF capture |
| npm run test:mutation | 98 mutants across clients, specs, and server; all must die |
| npm run generate | regenerate spec/mcp/schema.json from schema.ts only |
| npx tsx gen/typescript/fafo-server/server.ts | run the reference fafo-mcp server (stdio) |
Everything runs locally. There is no cloud CI, which is fitting for a project whose seventh law is that there is no staging environment. Symlink the gate as a pre-push hook and no unvalidated contract change leaves your machine:
ln -s ../../scripts/validate.sh .git/hooks/pre-pushspec/
├── asyncapi.yaml # event contract ROOT — wiring + Laws + stable pointers
├── channels/ components/ # single-responsibility spec modules ($ref composition)
├── README.md # module architecture + extension recipes
└── mcp/
├── schema.ts # MCP SOURCE OF TRUTH (TypeScript-first, like MCP itself)
├── schema.json # generated — never hand-edited
└── FAFO-MCP.md # prose spec; defers to schema.ts (§0 precedence)
scripts/
├── validate.sh # the 5-stage gate
├── check-b5-drift.mjs # cross-spec semantic drift detection
├── codegen.mts # polyglot generator (imports schema.ts directly)
├── codegen.sh # THE one command
├── dogfood*.mts # live MCP dogfood scenarios
├── demo-terminal.mts # terminal demo renderer
└── mutation-test.mts # 98 mutants, 3 oracles
gen/ # all generated, byte-deterministic, stamped
├── go/fafo/ # models + contract + contract_test (go test)
├── python/fafo/ # stdlib-only package + contract_test
└── typescript/
├── fafo/ # models + contract + contract.test.ts
└── fafo-server/ # runnable fafo-mcp reference server + conformance
examples/
└── go-client/ # tiny consumer of the generated Go client package
demo/
├── fafo-chaos.cast # asciinema recording
├── fafo-chaos.gif # sendable terminal GIF
└── terminal-demo.tape # VHS recipe
Specs complete. Clients generated. Server conformant. Mutants dead. Consequences: eventual.
WTFPL — it would be hypocritical to gatekeep.
| Back | FazBrowse Home | New Git URL |