flowfig

Drawn from code. Checked by CI.

Your coding agent draws the diagram from your code. Flowfig links each box to a file and a symbol, and fails CI when that code is gone.

npx flowfig init

Node 18 or later. Zero runtime dependencies.

Browserthe callerGET/users/42GET/users/42 BACKEND examples/shop/api.ts#getUserAPI Serverhandles the request STORAGE examples/shop/cache.ts#getCachedCachein memorymissusers:42storedusers:42hitusers:42— examples/shop/db.ts#queryUserDatabasesource of truthROWreadAda Lovelace— request examples/shop/api.ts#getUserget examples/shop/api.ts#getUserquery GET /users/42 set 200 OK GET /users/42 200 OK cache miss cache hit The browser asks for user 42. The API server checks the cache first. The cache has no entry. The API server reads the row from the database. The API server stores the row in the cache and sends the response. The browser asks for user 42 again. The cache has the entry now. The API server sends the response. The database gets no query.
Browserthe callerGET/users/42GET/users/42 BACKEND examples/shop/api.ts#getUserAPI Serverhandles the request STORAGE examples/shop/cache.ts#getCachedCachein memorymissusers:42storedusers:42hitusers:42— examples/shop/db.ts#queryUserDatabasesource of truthROWreadAda Lovelace— request examples/shop/api.ts#getUserget examples/shop/api.ts#getUserquery GET /users/42 set 200 OK GET /users/42 200 OK cache miss cache hit The browser asks for user 42. The API server checks the cache first. The cache has no entry. The API server reads the row from the database. The API server stores the row in the cache and sends the response. The browser asks for user 42 again. The cache has the entry now. The API server sends the response. The database gets no query.
Rendered by flowfig 0.8.4 from figures/cached-request.ts.
PARTS LIST
ITEMBOXSOURCECHECK
1API Serverapi.ts#​getUserdefined
2Cachecache.ts#​getCached#getEntrydefinedmissing
3Databasedb.ts#​queryUserdefined
4Browsernonenot linked

NOTES

npx flowfig verify docs/cached-request.svg
0 errors, 0 warnings
docs/cached-request.svg: 3 of 3 boxes defined; edges: 2 found, 0 not found, 0 unsure, 1 not checked
1. The commit renames getCached to getEntry.
npx flowfig verify docs/cached-request.svg
error    missing-symbol     docs/cached-request.svg: box "cache" -> examples/shop/cache.ts#getCached: symbol not defined
1 error, 0 warnings
docs/cached-request.svg: 2 of 3 boxes defined; edges: 1 found, 0 not found, 0 unsure, 2 not checked
2. The agent updates the spec: cache.ts#getEntry.
npx flowfig verify docs/cached-request.svg
0 errors, 0 warnings
docs/cached-request.svg: 3 of 3 boxes defined; edges: 2 found, 0 not found, 0 unsure, 1 not checked
1. The commit renames getCached to getEntry.
npx flowfig verify docs/cached-request.svg
error    missing-symbol     docs/cached-request.svg: box "cache" -> examples/shop/cache.ts#getCached: symbol not defined
1 error, 0 warnings
docs/cached-request.svg: 2 of 3 boxes defined; edges: 1 found, 0 not found, 0 unsure, 2 not checked
2. The agent updates the spec: cache.ts#getEntry. verify exits 0.
TITLE
Cached request
DRAWN BY
coding agent
CHECKED BY
flowfig verify
FILE
docs/cached-request.svg
RESULT
exit 0exit 1
REV
01
SHEET
1 of 8
DATE
2026-10-06
SCALE
NTS

SHEET 2 OF 8 · DETAIL

DETAIL B

A renamed function should break a diagram.

Someone renames getCached. The diagram still shows the old name. No check fails, so no one sees the drift. With Flowfig, verify fails with exit code 1 and the pull request shows why.

SPEC, ONE BOX

{ "id": "cache", "label": "Cache", "sub": "in memory", "shape": "store", "width": 200, "source": "examples/shop/cache.ts#getCached" }
CONSOLE
npx flowfig verify docs/cached-request.svg
error    missing-symbol     docs/cached-request.svg: box "cache" -> examples/shop/cache.ts#getCached: symbol not defined
1 error, 0 warnings
docs/cached-request.svg: 2 of 3 boxes defined; edges: 1 found, 0 not found, 0 unsure, 2 not checked

SHEET 3 OF 8 · PROCESS

PROCESS SHEET

Three commands.

The agent writes JSON, not pictures. Flowfig does the layout, checks the spec with 23 rules, and writes one animated SVG with no script.

  1. flowfig init

    Set up 7 agents in one run: Claude Code, Cursor, GitHub Copilot, Codex and other AGENTS.md agents, Gemini CLI, Windsurf and Kiro.

    npx flowfig init --all-agents --dry-runwould create .claude/skills/figure/SKILL.mdwould create CLAUDE.mdwould create .mcp.jsonwould create AGENTS.mdwould create .cursor/rules/flowfig.mdcwould create .cursor/mcp.jsonwould create .github/copilot-instructions.mdwould create .vscode/mcp.jsonwould create GEMINI.mdwould create .gemini/settings.jsonwould create .windsurf/rules/flowfig.mdnote      windsurf: add {"command":"npx","args":["flowfig","mcp"]} to the MCP config by handwould create .kiro/steering/flowfig.mdwould create .kiro/settings/mcp.json
  2. flowfig verify

    Check every linked file, symbol and edge against the code.

    npx flowfig verify docs/checkout.svg0 errors, 0 warningsdocs/checkout.svg: 4 of 4 boxes defined; edges: 3 found, 0 not found, 0 unsure, 1 not checked
  3. flowfig diff

    List what changed between two figures.

    npx flowfig diff first.svg first2.svgbox changed: api (label "API" -> "API gateway")edge changed: api->db (label "read the user" -> "select the user")

SHEET 4 OF 8 · REVISIONS

REVISIONS

The pull request shows the drift.

The Action runs verify on every figure in a pull request. For each SVG the PR changes, it comments the old image, the new image and the spec changes. It names each figure whose linked code the PR changes.

NOTE 3. WORKFLOW
# .github/workflows/figures.ymlname: figureson: pull_requestjobs:figures:runs-on: ubuntu-latestpermissions:contents: readpull-requests: writesteps:- uses: actions/checkout@v4with:fetch-depth: 0 # the Action reads the old figure from the base commit- uses: actions/setup-node@v4with:node-version: 22- uses: iamalvisng/flowfig@v0.8.4with:figures: 'docs/**/*.svg' # default **/*.svg
PR COMMENT: docs/cached-request.svg
REVZONEDESCRIPTIONAPPROVED
0 | 1all
The cached request figure before the pull requestThe figure after the pull request. Only the source of Cache changed, so the picture is the same.
17Abox changed: cache (source "examples/shop/cache.ts#getCached" -> "examples/shop/cache.ts#getEntry")verify: 3 of 3 boxes defined

NOTES

  • this PR changes examples/shop/api.ts, linked from docs/cached-request.svg. Review the figure.
  • this PR changes examples/shop/cache.ts, linked from docs/cached-request.svg. Review the figure.
One comment per PR. The Action updates it on each push.

SHEET 5 OF 8 · FORMS

SHEET SET, 5.1 TO 5.6

Six forms. One spec.

A map of the parts. A rail of the messages. Swimlanes for a process. A timeline for a roadmap. A lifecycle for a state machine. Each one plays in a GitHub README and follows the reader's light or dark mode.

A browser loads a user through an API from a database.
TITLE
A browser loads a user through an API from a database.
FORM
Map
OPTION
the default
SHEET
5.1 of 5.6

Each form and its spec option

SHEET 6 OF 8 · SPECIFICATION

SPECIFICATION

Checked before it is drawn.

ITEMCHARACTERISTICVALUENOTE
1Rules23in flowfig check
2Errors11stop the render
3Warnings12--strict makes them errors

check finds ids that point nowhere, text wider than its box, edges through boxes, overlapping labels and low contrast. A render runs the same check and writes nothing on an error.

INSPECTION RECORD

npx flowfig check docs/checkout.svg0 errors, 0 warningsfigure: 5 boxes, 3 groups, 4 edges, 2 steps, 6 messages

LIMIT Edge checks cover TypeScript, JavaScript, Python, Go, Java, C# and Rust. Other languages keep the name check for boxes.

SHEET 7 OF 8 · CONNECTORS

CONNECTOR SCHEDULE

Any coding agent.

init writes the Flowfig guide where your agent reads it. flowfig mcp serves docs, check, render, verify and diff over stdio for an agent with no shell. render writes the file and returns the check lines, so no SVG text goes through the model.

npx flowfig init --all-agents --dry-run
  • Claude Code.claude/skills/figure/SKILL.mdCLAUDE.md.mcp.json
  • Codex and other AGENTS.md agentsAGENTS.md
  • Cursor.cursor/rules/flowfig.mdc.cursor/mcp.json
  • GitHub Copilot.github/copilot-instructions.md.vscode/mcp.json
  • Gemini CLIGEMINI.md.gemini/settings.json
  • Windsurf.windsurf/rules/flowfig.mdMCP: add {"command":"npx","args":["flowfig","mcp"]} to the MCP config by hand
  • Kiro.kiro/steering/flowfig.md.kiro/settings/mcp.json

TERMINAL BLOCK, MCP

{ "mcpServers": { "flowfig": { "command": "npx", "args": ["flowfig", "mcp"] } } }

The MCP tools

SHEET 8 OF 8 · ASSEMBLY

ASSEMBLY C

The same figure in your app.

The React player adds tabs for each step, pause, 2x speed and full screen. A hover on a box shows its source. Under reduced motion it shows the last beat and does not move.

LoadUser.tsx
import { Flow, type FlowProps } from 'flowfig';
import spec from './first.json';

export const LoadUser = () => <Flow {...(spec as FlowProps)} />;

React 18 or later is a peer dependency. The CLI and flowfig/svg do not need React.

<Flow /> WITH THE CHECKOUT SPEC
Browser
Edge
Gateway
Order service
Orders
Orders DB
External
Payments
3 items · $42.00
EDGEORDER SERVICEEXTERNALBrowserGatewayOrdersOrders DBPaymentssubmit1 of 63 items · $42.00examples/shop/gateway.ts#checkoutcreatepayexamples/shop/orders.ts#createOrdercharge $42.00examples/shop/orders.ts#createOrderorder #981examples/shop/orders.ts#createOrderASYNCwebhook: paid201 Created
The browser sends the cart.

SIGN-OFF

One command. Then ask your agent.

NO.STEPCOMMANDRESULTCopy
1Set up
npx flowfig init
2Ask
/figure how does login work
3Check
npx flowfig verify docs/login.svg
exit 0

The agent ends its reply with npx flowfig open <path>. Run it to see the animation.