A small text format for diagrams that agents write and people read, rendered as deterministic, themed SVG.
The author decides where everything goes, the way they would draw the figure by hand. The text records those decisions, so another agent can read and edit the diagram without looking at the picture. The renderer sizes the grid and draws; it never moves anything, and it reports every problem with its line number.
The kinds are routed flows and standalone outcome fan-outs; both formats are v0. See them on ablauf.uberblick.ai.
We started with Mermaid, and the first version of ablauf was a Mermaid
subset. Mermaid lays a diagram out automatically, which makes it quick to
write. For the documents we work on we wanted the author to decide where each
step sits and which side each edge leaves and enters, so that a small edit to
the text leaves the rest of the picture where it was. Edges are still spelled
like Mermaid's (-->, : label), because agents already know that spelling.
ablauf is much narrower than Mermaid: two kinds, flows and fan-outs, no automatic layout and no Mermaid import or export. If you need Mermaid's breadth, Mermaid is the better choice. The motivation page has the longer story.
The playground puts an editor beside the live render and lists each problem with its line number; click one to jump to it. It switches between light and dark and between a bare page and a 710 px document column, and it opens every example in this repository. In a checkout, with mise:
mise trust && mise run setup
mise run playground
Then open http://localhost:4620. Rendered examples of both kinds are on ablauf.uberblick.ai.
Requires Node.js 22.18 or newer. The package ships compiled JavaScript and TypeScript declarations, with no runtime dependencies or TypeScript required. Its public entry point is an ES module.
Install it in your project:
npm install @uberblick/ablauf
Save this as render-flow.mjs:
import { readFile, writeFile } from "node:fs/promises";
import { render } from "@uberblick/ablauf";
const [input, output] = process.argv.slice(2);
if (!input || !output) {
console.error("Usage: node render-flow.mjs input.flow output.svg");
process.exit(2);
}
const source = await readFile(input, "utf8");
const { svg, diagnostics } = render(source, {
idPrefix: "build-flow",
scheme: "light",
});
await writeFile(output, svg);
for (const { line, severity, message } of diagnostics) {
console.error(`${input}:${line} ${severity}: ${message}`);
}
// Keep the SVG for inspection, but fail the build on any source problem.
process.exitCode = diagnostics.length ? 1 : 0;
Run it with a flow file and the desired output path:
node render-flow.mjs diagram.flow diagram.svg
render(source, options?) returns { svg, diagnostics, layout }. Source
problems return diagnostics with one-based line, severity and message
fields while still producing SVG. Invalid caller options can throw.
idPrefix defaults to "ab"; supply distinct prefixes for diagrams sharing
a page. Omit scheme to follow the system theme, or pin it to "light" or
"dark". The existing fonts option accepts host font families and synchronous
width metrics; see host fonts and width metrics.
TypeScript consumers can import RenderOptions, Diagnostic, FontOptions,
FontsOptions and TextStyle from the same entry point. LIGHT and DARK
export the default palettes.
flow v0
columns fix main manual
pill push col=main tone=muted "push to main"
box build "compile and package"
box test "unit and integration tests"
box staging "deploy to staging"
box smoke "smoke tests"
box production "deploy to production"
end live "Live"
pill failed col=fix row=test tone=rework "checks failed"
box rollback col=fix row=production tone=rework "restore the last release"
panel approve col=manual row=smoke tone=stop
strong "Release manager"
muted "approves the release"
push --> build : on push
build --> test
test --> staging : green
staging --> smoke
smoke --> approve tone=stop : passed
approve --> production tone=stop from=bottom to=right label=end : approved
production --> live : healthy
build --> failed tone=rework to=top.2 : fails
test --> failed tone=rework : red
failed --> push tone=rework from=top.1 to=left label=end : fix and push
production --> rollback tone=rework : unhealthy
legend
pill "event or state"
box "automated job"
panel "manual step"
edge tone=rework "failure path"
columnsnames the columns left to right. Each node starts a new row unlessrow=puts it beside another node.- Nodes are
text,pill,box,end,panelordecision, coloured by a tone. - Edges use Mermaid's arrows.
from=andto=pick the sides an edge leaves and enters; each pair of sides has one fixed shape. legendexplains the shapes in fine print under the diagram.
spike/PRIMER.md is the full format on one page, and the page an agent reads before writing a flow.
For phone widths, author separate wide and narrow layouts. The worked pair keeps the same content and lets the host select a readable SVG.
From spike/examples/checkout.flow, with two sections:
The loop ub-agents runs on Uberblick's repositories, from spike/examples/loop.flow:
decision asks a question over a small diamond, and label=inline sets each
answer into a gap in its edge. From
spike/examples/project-workflow.flow:
A fan-out v0 diagram is one step and its ordered outcomes, each with a reason
and a destination:
fan-out v0
step "Check whether approval permits the run"
outcome "Approved" reason="A maintainer started it and the input is unchanged" destination="Start the run" tone="done"
outcome "Outside input" reason="The input has not been cleared by a maintainer" destination="Ask a maintainer" tone="stop"
outcome "Edited since" reason="The input changed after the maintainer started it" destination="Ask a maintainer" tone="stop"
Inline SVGs can follow a page's data-theme="light" / data-theme="dark"
switch through the existing --ab-* CSS properties, without rerendering.
See host page themes for the complete base and tone palette,
copyable host CSS and the difference between inline SVG and image embedding.
You need mise. In a fresh checkout or worktree:
mise trust && mise run setup
| Command | What it does |
|---|---|
mise run setup |
Installs the pinned Node and pnpm and the locked dependencies. |
mise run playground |
Serves the review page at http://localhost:4620 (another port if that one is busy). Open#examples/loop to see the loop beside its hand-drawn reference. |
mise run check FILE |
Renders one .flow file to an.svg beside it and lists its problems with line numbers. |
mise run render |
Renders every example to spike/out/ and refreshes the figures in this README. |
mise run site |
Builds ablauf.uberblick.ai intosite/out/ ;mise run site-serve serves it. |
mise run measure |
Shows what moved between the loop and the loop with a role inserted. |
mise run ci |
Lint, typecheck and tests, before you push. |
pnpm build emits the package into dist/. npm pack builds it automatically.
The tests in mise run ci install the actual tarball with production dependencies
only in an isolated directory and exercise the public import and this build script.
mise tasks lists everything. The plan is in docs/plan.md, and
the spike's results in spike/FINDINGS.md.
Maintainers release an already-prepared version with mise run release X.Y.Z.
Start with mise run release X.Y.Z --check; see releases
for trusted-publishing setup, confirmation and partial-release recovery.
The earlier Mermaid-subset version lives in uberblick-ai/old-ablauf.
MIT