Overview
Welcome. This is the onboarding path for Factflow and the products around it: what the parts are, how we make changes, the tooling we work with, and how we ship. The first time through, read the pages in order — each assumes the one before it.
Start with the map. Factflow ingests content from DNB's source systems — SharePoint, Confluence, websites, Boost.AI exports — and produces Avalon, a knowledge base holding one page per concept, which agents and people then query. Three repos divide that work between them, and knowing which owns what saves you from hunting for the generated pages inside the pipeline, or for the serving layer in either.
Three repos, three owners
Section titled “Three repos, three owners”flowchart LR FF["<b>factflow</b><br/><i>the pipeline</i><br/>Python · React · Go · Astro"] AV["<b>dnb-avalon</b><br/><i>the corpus</i><br/>markdown · taxonomy · stats"] KU["<b>dnb-kunnskap</b><br/><i>the operational surface</i><br/>MCP server · dashboard"] CO["<b>consumers</b><br/><i>RaiWork · Raicode</i><br/>agents · people"] FF -- "exports pages<br/>one commit per change" --> AV AV -- "embedded / indexed" --> KU KU -- "MCP tools" --> CO
| Repo | Owns | You change it when |
|---|---|---|
factflow | The pipeline — engine, adapters, configs, API, CLI, this site | Ingestion, adapters, the engine, anything that produces |
dnb-avalon | The corpus — generated pages, taxonomy.yaml, stats/, the consumer skill | The taxonomy, or the agent skill. Never the pages — Factflow writes those |
dnb-kunnskap | Serving and visibility — the MCP server, the dashboard, an HTTP API | How the knowledge is served, searched, or displayed |
dnb-kunnskap states the boundary itself: it "does not own the corpus (that's dnb-avalon) or the pipeline (that's factflow). It owns visibility into and management of the knowledge layer."
Two more repos you will meet: radical-gateway is the multi-provider AI gateway Factflow calls for LLM and embedding work, and raicode is the assistant CLI you develop with.
Checking out
Section titled “Checking out”Factflow is a single repository, not submodules. The four apps are directories inside it, each self-contained with its own toolchain:
GH_HOST=dnb.ghe.com gh repo clone radicalAI/factflowcd factflow && just installfactflow/├── backend/ Python 3.13 · uv workspace · FastAPI → run uv, pytest, ruff from here├── frontend/ React 19 · Vite · Bun → run bun from here├── cli/ Go 1.26 · cobra → run go from here├── docsite/ Astro Starlight · Bun → run bun from here└── .claude/ the assistant harnessPaths are always written relative to the repo root; the tools run from their app directory. Development process has the full setup and the gates.
You only need the other repos checked out for specific work: dnb-avalon if you are touching the taxonomy or the skill — and the dnb-kunnskap dashboard reads stats/ from a local dnb-avalon checkout, so it needs one alongside.
Working with Raicode
Section titled “Working with Raicode”Development here is assistant-driven. raicode is the CLI — it "handles auth, model selection, and connects your AI client to the Radical Gateway", so there is no token juggling.
What makes it effective in this repo is the .claude/ harness: conventions that load automatically based on the file you are editing, domain knowledge available on demand, and the /ff- commands that carry a change from issue to merged PR. You get the conventions applied without having to remember them.
The short version of the loop:
/ff-issue— describe the work, get an issue and a design doc./ff-start <N>— branch, implement, self-review, PR.- A teammate reviews and fixes; you merge. See Review and merge.
For a bug you already understand, /freestyle skips the ceremony and still runs the same gates.
What Factflow itself does
Section titled “What Factflow itself does”Factflow executes configuration. A pipeline is YAML: routes, the adapters each route runs, and the queues between them. Changing what the platform does normally means changing a config, not Python.
Each execution is isolated — OrchestratorManager runs "multiple concurrent pipeline executions", and each execution gets its own PipelineOrchestrator with isolated state, bounded by max_concurrent_executions. Queues are rewritten per execution so two runs of the same config cannot collide.
Adapters are the extension point. An adapter is declared by type name:
adapters: - type: "html_to_markdown" config: preserve_tables: trueThe engine resolves the type through a registry, validates the config against the adapter's model, injects dependencies, and runs it. Nothing imports the adapter by module path, so adding capability means adding an adapter and referencing it — see Write an adapter.
Workflow packages group adapters by domain and never import each other; they hand work over through queues and storage. That is what lets a config compose domains that know nothing about one another.
flowchart TB subgraph SRC["Sources"] direction LR W["Websites"] SP["SharePoint"] CF["Confluence"] BO["Boost.AI exports"] end subgraph ING["Ingest"] direction LR WS["webscraper<br/><i>scrape · crawl</i>"] SPI["sharepoint"] CFI["confluence"] BOI["boost"] end subgraph NORM["Normalise"] direction LR MD["markdown<br/><i>HTML → segments</i>"] TR["translator"] end GOV["hygiene<br/><i>PII · sensitivity</i>"] subgraph ENR["Enrich"] direction LR EM["embeddings<br/><i>pgvector</i>"] KN["knowledge<br/><i>concepts · consolidation</i>"] end W --> WS SP --> SPI CF --> CFI BO --> BOI WS --> MD SPI --> MD CFI --> MD BOI --> MD MD --> TR MD --> GOV TR --> GOV GOV --> EM GOV --> KN
There are 31 configurations under backend/config/pipelines/ across nine domain directories, each composing a different slice. Workflows covers each domain; The pipeline spine covers how a config becomes a running execution.
Three surfaces over one API
Section titled “Three surfaces over one API”Nothing reaches the engine directly. Everything goes through the backend's HTTP API at /api/v1, and Factflow ships two first-party clients over it.
flowchart LR BE["<b>backend</b><br/><i>factflow-server</i><br/>/api/v1"] FE["<b>frontend</b><br/><i>React dashboard</i><br/>localhost:3000"] CL["<b>cli</b><br/><i>factflow binary</i><br/>Go · cobra"] OT["other clients<br/><i>agents · scripts · CI</i>"] BE --> FE BE --> CL BE --> OT
| Surface | Lives in | For |
|---|---|---|
| Backend | backend/packages/factflow-server/ | The API itself, plus the engine behind it |
| Frontend | frontend/src/ | The dashboard — browse configs, watch executions, inspect lineage and storage |
| CLI | cli/cmd/factflow/commands/ | Operating the platform from a terminal or CI: validate a config, run it, follow an execution, replay a stage |
The CLI is the management interface, and it is deliberately broad — fifteen command domains covering configs, executions, pipelines, storage, lineage, search, replay, indexes, embeddings, adapters, content, webhooks, auth, docs and system. It talks to a backend chosen client-side with --server, so pointing it at another environment needs no server restart. CLI reference documents the commands.
Run them locally with just serve-backend, just serve-frontend, and cd cli && go build ./cmd/factflow/. The frontend dev server proxies /api to the backend, so it needs one running.
The contract rule that will catch you
Section titled “The contract rule that will catch you”The backend is the source of truth for response shapes, and both clients must agree with it. If you change a field name, a type, a status code or an SSE event, you update all three in the same PR:
| Change | Also update |
|---|---|
A Pydantic response model in factflow-server | frontend/src/types/ and frontend/src/api/ |
| The same | cli/internal/api/types.go and the command that prints it |
Label the PR api so reviewers know to check both consumers. .claude/rules/api-contract.md loads automatically when you touch those files and carries the full checklist.
This site renders the API from a committed snapshot at docsite/public/openapi.json, not from a live server — so an API change also means refreshing that snapshot, or the published reference silently describes the previous shape.
Understanding the artifacts
Section titled “Understanding the artifacts”Factflow's output is not a database you query — it is generated content committed to dnb-avalon. Avalon is "DNB's automatically-generated consolidated knowledge base — Wikipedia for DNB", where each page is one concept synthesized from every source that mentions it, with paragraph-level citations back to the originals.
Three properties define the boundary, and they are what your changes must not break:
- Consolidated — one page per concept, not one per source. An agent asking a question gets one authoritative answer rather than ten snippets to reconcile.
- Provenance-preserving — every claim cites its upstream source by a stable
{origin}:{source_ref}handle, so a fabricated citation fails a membership check. - Agent-queryable — typed YAML frontmatter over markdown, designed for retrieval rather than reading.
The seam between Factflow and everything downstream is therefore a file contract: exported markdown plus its typed frontmatter. Because the contract is typed and stable, the pipeline and its consumers evolve independently — which is why changing a projected frontmatter field is a far bigger deal than changing an internal column.
On the serving side, dnb-kunnskap ships an MCP server (a single Go binary that embeds the corpus, encrypted at rest, exposing read-only tools such as search, navigate_taxonomy and get_page) and a read-only dashboard over the stats/ rollups. Its HTTP API is still a skeleton. Consumers reach the knowledge through those tools, never by reading Factflow's internals.
One caveat worth carrying: of the four artifacts the method describes, the corpus, the concept map and the knowledge-state memory are in production, while the person graph is a proof-of-concept — populated at organizational scale but not wired into downstream consumers. Design docs sometimes speak of it as though it were live.
Where to go next
Section titled “Where to go next”- Development process — issue to merged PR, the conventions, the local gates
- Coding assistants — the
.claude/harness and the/ff-commands in detail - Cutting a release — promoting
devtomain - Concepts — the engine's mental model, if you want the internals