Examples
Six diagrams archgram drew, each with what it shows, the keys in its spec that make it so, and the spec to copy.
Each drawing below is archgram's own output, untouched, drawn from the spec under it. Under each one you'll find what it shows, the keys in its spec that make it look that way, and the kind of system it suits. Open the spec, copy it, and change it into yours.
To draw one, save its spec in your project and run archgram build on it. The Quickstart shows how.
A web service with a cache and a worker#
A link shortener. The API reads the cache and falls back to the database on a miss, and a worker counts the clicks in the background.
| Fields in the spec | What it does |
|---|---|
frames: [{ id: redis, label: Redis }] | Draws a box round the cache and the click stream, two parts of one Redis. |
style: dashed | Draws the call that happens only sometimes, on a cache miss, as a dashed line. |
note: "1-day TTL" | Adds a short line under a card's name. |
flows: [{ name: a visit, … }] | Animates one visit, from the browser to the database. |
Use it for the README of a typical web backend.
linkshort.archgram.yaml
archgram: 1
credit: false
title: linkshort
description: >-
The API creates short links and redirects. A redirect reads the URL from
the Redis cache, falls back to Postgres on a miss, adds the click to a
Redis stream and returns. A worker drains the stream in batches and adds
the counts to Postgres, where the stats route reads them.
nodes:
- { id: browser, kind: browser, label: Visitor }
- { id: api, kind: service, label: API, note: "FastAPI, port 8000", tech: fastapi }
- { id: cache, kind: cache, label: URL cache, note: "1-day TTL", tech: redis, frame: redis }
- { id: clicks, kind: queue, label: Click stream, tech: redis, frame: redis }
- { id: worker, kind: service, label: Worker, note: up to 500 per read }
- { id: postgres, kind: database, label: links, note: source of truth, tech: postgresql }
frames:
- { id: redis, label: Redis }
edges:
- { from: browser, to: api }
- { from: api, to: cache }
- { from: api, to: postgres, label: on a miss, style: dashed }
- { from: api, to: clicks }
- { from: clicks, to: worker }
- { from: worker, to: postgres }
flows:
- { name: a visit, steps: [browser, api, clicks, worker, postgres] }A request turned away at a check#
A request without a session is refused at the session check and the refusal goes back to the browser. Signed in, the same request passes and reaches the database.
| Fields in the spec | What it does |
|---|---|
stop: session | Ends the first flow at Session. A ✕ marks the line into it, and the refusal travels back to the browser. |
direction: down | Lays the drawing out from top to bottom. |
variant: external | Marks Session as a service you do not run, here Clerk. |
Use it for sign-in, permissions, validation or rate limits, anywhere a request can be told no.
sign-in.archgram.yaml
archgram: 1
credit: false
title: Orders behind a sign-in
description: >-
The browser asks the API for the user's orders. Before anything is read,
the API has Clerk check the request's session. A request without a
session is refused at the session check and the refusal goes back to the
browser; signed in, it passes to the orders service, which reads the
orders from Postgres.
direction: down
nodes:
- { id: browser, kind: browser, label: Browser, note: the shop, tech: react }
- { id: api, kind: service, label: API, note: GET /orders, tech: nodedotjs }
- { id: session, kind: service, label: Session, note: is the user signed in?, tech: clerk, variant: external }
- { id: orders, kind: service, label: Orders, note: the user's orders }
- { id: db, kind: database, label: Postgres, note: orders, tech: postgresql }
edges:
- { from: browser, to: api }
- { from: api, to: session, label: check }
- { from: session, to: orders, label: signed in }
- { from: orders, to: db }
flows:
- { name: a request without a session, steps: [browser, api, session], stop: session }
- { name: "signed in, it goes through", steps: [browser, api, session, orders, db] }A checkout across hosted services#
A storefront built on hosted services. A guest's checkout is refused at the session check. Signed in, the order is paid, and a webhook starts a workflow that saves the order and sends the receipt at once.
| Fields in the spec | What it does |
|---|---|
variant: external | Marks Clerk, Upstash, Stripe and Resend as services you do not run. |
steps: [… flow, [db, mail]] | A list inside the steps is a branch. Both are reached at once. |
label: webhook | Names a line. |
signal: spark | Picks how the moving request is drawn. |
Use it for a product built on SaaS APIs, where most boxes belong to someone else.
saas.archgram.yaml
archgram: 1
credit: false
title: Checkout on the edge
description: >-
The Next.js storefront on Vercel sends each checkout through edge
middleware, which asks Clerk to verify the session before the checkout
API reads the cart from Upstash Redis and charges with Stripe. Stripe's
webhook starts a Temporal workflow that writes the order to Supabase and
sends the receipt with Resend. A guest's checkout is refused at the
session check; signed in, it goes through.
direction: down
signal: spark
glow: true
nodes:
- { id: web, kind: browser, label: Storefront, note: Next.js, tech: nextdotjs }
- { id: edge, kind: service, label: Middleware, note: at the edge, tech: vercel, frame: vercel }
- { id: auth, kind: service, label: Session, note: verify, tech: clerk, variant: external }
- { id: api, kind: service, label: Checkout API, note: route handlers, tech: nodedotjs, frame: vercel }
- { id: cart, kind: cache, label: Cart, tech: upstash, variant: external }
- { id: pay, kind: service, label: Payments, tech: stripe, variant: external }
- { id: flow, kind: service, label: Fulfilment, note: durable workflow, tech: temporal }
- { id: db, kind: database, label: orders, tech: supabase }
- { id: mail, kind: service, label: Receipts, tech: resend, variant: external }
frames:
- { id: vercel, label: Vercel }
edges:
- { from: web, to: edge }
- { from: edge, to: auth }
- { from: auth, to: api, label: signed in }
- { from: api, to: cart }
- { from: api, to: pay }
- { from: pay, to: flow, label: webhook }
- { from: flow, to: db }
- { from: flow, to: mail }
flows:
- { name: a guest checks out, steps: [web, edge, auth], stop: auth }
- { name: "signed in, the order goes through", steps: [web, edge, auth, api, pay, flow, [db, mail]] }An AI agent with tools#
An agent that reasons with a model and calls three tools, one of which searches a docs index that a nightly script fills.
| Fields in the spec | What it does |
|---|---|
kind: agent / model / tool / vector-store | Gives each AI part its own icon. |
frames | Two boxes, loop and nightly, separate the agent's loop from the nightly indexing. |
flows | Three paths, played one after another. One branches to two tools at once. |
signal: comet | Draws the moving request as a comet. |
Use it for LLM apps, RAG and agents with tools.
agent.archgram.yaml
archgram: 1
credit: false
title: A coding agent with tools
description: >-
A chat sends the question to the agent, which reasons with Claude and
calls its tools: search_docs reads a Qdrant index of the docs, query_db
reads the Postgres warehouse and run_code runs in a Docker sandbox.
Every night a Python script embeds the docs with Mistral into the index.
signal: comet
glow: true
nodes:
- { id: chat, kind: browser, label: Chat, note: React, tech: react }
- { id: agent, kind: agent, label: Agent, note: plans and calls tools, tech: claude, frame: loop }
- { id: llm, kind: model, label: Claude, note: reasoning, tech: anthropic, variant: external, frame: loop }
- { id: search, kind: tool, label: search_docs, frame: loop }
- { id: sql, kind: tool, label: query_db, frame: loop }
- { id: run, kind: tool, label: run_code, note: sandbox, tech: docker, frame: loop }
- { id: vec, kind: vector-store, label: Docs index, tech: qdrant }
- { id: db, kind: database, label: Warehouse, tech: postgresql }
- { id: docs, kind: file, label: docs/, note: Markdown, frame: nightly }
- { id: ingest, kind: script, label: ingest.py, tech: python, frame: nightly }
- { id: embed, kind: model, label: Embeddings, tech: mistralai, variant: external }
frames:
- { id: loop, label: Agent loop }
- { id: nightly, label: Nightly }
edges:
- { from: chat, to: agent }
- { from: agent, to: llm, label: think }
- { from: agent, to: search }
- { from: agent, to: sql }
- { from: agent, to: run }
- { from: search, to: vec }
- { from: sql, to: db }
- { from: docs, to: ingest }
- { from: ingest, to: embed }
- { from: embed, to: vec }
flows:
- { name: indexing the docs, steps: [docs, ingest, embed, vec] }
- { name: a question, steps: [chat, agent, [search, sql], [vec, db]] }
- { name: trying the fix, steps: [chat, agent, run] }Three apps on one platform#
iOS, Android and web apps behind one gateway. Services on Kubernetes write to Postgres and stream events into an analytics database.
| Fields in the spec | What it does |
|---|---|
kind: mobile / browser | Draws each client as what it is. |
variant: multi | Shows a service that runs as several instances. |
frames: [{ id: k8s, label: Kubernetes }] | Draws the cluster round the services in it. |
signal: pulse | Draws the moving request as a pulse. |
Use it for microservices behind a gateway, with more than one client.
platform.archgram.yaml
archgram: 1
credit: false
title: One platform, three apps
description: >-
The iOS, Android and web apps call one Cloudflare gateway. On Kubernetes,
the Go orders service writes to Postgres and publishes each order to
RabbitMQ, which streams it into ClickHouse; the Python recommendations
service reads ClickHouse, and Grafana charts it.
direction: down
signal: pulse
glow: true
nodes:
- { id: ios, kind: mobile, label: iOS, tech: swift }
- { id: android, kind: mobile, label: Android, tech: kotlin }
- { id: web, kind: browser, label: Web, tech: react }
- { id: gw, kind: service, label: Gateway, tech: cloudflare, variant: external }
- { id: orders, kind: service, label: Orders, note: 6 pods, tech: go, variant: multi, frame: k8s }
- { id: recs, kind: service, label: Recommendations, tech: python, variant: multi, frame: k8s }
- { id: events, kind: queue, label: Events, tech: rabbitmq, frame: k8s }
- { id: pg, kind: database, label: Orders DB, tech: postgresql }
- { id: olap, kind: database, label: Analytics, tech: clickhouse }
- { id: dash, kind: service, label: Dashboards, tech: grafana }
frames:
- { id: k8s, label: Kubernetes }
edges:
- { from: ios, to: gw }
- { from: android, to: gw }
- { from: web, to: gw }
- { from: gw, to: orders }
- { from: gw, to: recs }
- { from: orders, to: pg }
- { from: orders, to: events }
- { from: events, to: olap, label: stream }
- { from: recs, to: olap }
- { from: dash, to: olap }
flows:
- { name: an order, steps: [ios, gw, orders, events, olap] }
- { name: a recommendation, steps: [web, gw, recs, olap] }Tooling, written in JSON#
Not a running system but a repository's tooling. An agent, a person and CI reach the same checks, and a commit with a raw colour is refused, then passes once fixed.
| Fields in the spec | What it does |
|---|---|
"kind": "script" / "file" / "check" / "users" | Draws hooks, files, checks and people. |
"stop": "checks" | Refuses the first commit at the checks. |
{ "archgram": 1, … } | The whole spec is JSON. The fields are the same as in YAML, which suits a spec another program writes. |
Use it for build pipelines, git hooks, CI and other tooling.
commit-gates.json
{
"archgram": 1,
"credit": false,
"title": "One set of gates for agent, person and CI",
"description": "An agent's edit or commit goes through its hooks in .claude/hooks/design-system, a person's commit through the git pre-commit hook, and CI calls the core directly. All three run a stage of design-system/harness/gates.mjs, which reads design-system/gates.json and runs the token and rules checks against the DTCG tokens and DESIGN.md. A commit with a raw colour is refused at the checks and goes back to the person; fixed, it passes.",
"direction": "down",
"nodes": [
{
"id": "agent",
"kind": "agent",
"label": "Claude Code",
"note": "an edit, a commit",
"tech": "claude",
"variant": "external"
},
{
"id": "person",
"kind": "users",
"label": "A person",
"note": "git commit"
},
{
"id": "ci",
"kind": "service",
"label": "CI job",
"note": "optional",
"tech": "githubactions"
},
{
"id": "adapters",
"kind": "script",
"label": ".claude/hooks/design-system",
"note": "only translate",
"frame": "claude"
},
{
"id": "precommit",
"kind": "script",
"label": "pre-commit",
"note": "git hook"
},
{
"id": "core",
"kind": "script",
"label": "harness/gates.mjs",
"note": "every decision",
"frame": "ds"
},
{
"id": "gates",
"kind": "file",
"label": "gates.json",
"note": "what runs, and when",
"frame": "ds"
},
{
"id": "checks",
"kind": "check",
"label": "checks/",
"note": "tokens and rules contract",
"frame": "ds"
},
{
"id": "tokens",
"kind": "file",
"label": "tokens/",
"note": "DTCG, the one source of values",
"frame": "ds"
},
{
"id": "designmd",
"kind": "file",
"label": "DESIGN.md",
"note": "rules, no values"
}
],
"frames": [
{
"id": "claude",
"label": "The agent's own folder"
},
{
"id": "ds",
"label": "design-system/ names no agent"
}
],
"edges": [
{
"from": "agent",
"to": "adapters"
},
{
"from": "person",
"to": "precommit"
},
{
"from": "ci",
"to": "core",
"label": "before-commit"
},
{
"from": "adapters",
"to": "core"
},
{
"from": "precommit",
"to": "core",
"label": "before-commit"
},
{
"from": "core",
"to": "gates"
},
{
"from": "core",
"to": "checks"
},
{
"from": "checks",
"to": "tokens"
},
{
"from": "checks",
"to": "designmd"
}
],
"flows": [
{
"name": "a commit with a raw colour",
"steps": [
"person",
"precommit",
"core",
"checks"
],
"stop": "checks"
},
{
"name": "the commit again, fixed",
"steps": [
"person",
"precommit",
"core",
"checks",
[
"tokens",
"designmd"
]
]
}
]
}