Writing diagrams
Every architecture figure on this site is a Buzz file in docs/site/diagrams/,
drawn by magus/figure, a module embedded in the magus binary. A box is a
directory the knowledge graph holds, a group is a set of them, and the edges
between code boxes are the imports and declared calls those directories carry.
You declare what the figure shows; the module places everything and refuses a
figure it cannot draw, naming the call to change.
What a figure is
A figure makes one claim: the title states it, and the boxes and connectors are
the evidence. There are hard budgets:
at most 9 boxes, 12 connectors, 3 zones and 2 accented elements. A figure that
needs more is two figures, an overview and a detail, each with its own
figure\of().
The first figure
namespace cacheRead;
import "magus";
import "magus/figure";
export fun cacheReadFigure() > figure\Figure !> any {
final cache = magus\dir("internal/cache");
final run = figure\external("Run target", look: figure\Look.plain);
return figure\of("cache-read", title: "A hit skips the run")
.box(cache, label: "Cache key", focal: true)
.flowOut(cache, dst: run, label: "miss")
.scope([cache]);
}
magus\dir raises MGS7005 when the graph holds no such directory, naming the
nearest one, so a typo fails at the line that made it. Register the figure in
docs/site/diagrams/all.buzz (the import and an allFigures() entry), then
embed it on a page with <!--diagram:cache-read-->.
Boxes, groups and actors
box(dir, label:, sub:, focal:, look:)draws one directory.group(dirs, label:)draws every directory in a list as one box. Take the directories as records:magus\layer("handler").dirsis every directory a declared layer covers,magus\dirs("internal/queue/*")every directory a glob matches.+joins two lists, andfigure\without(dirs, drop: [...])leaves some out. A package added to the layer joins the group with no edit to the figure.figure\external(name, ...)is an actor: a person, a vendor service, a step, a Buzz file or a decision.
The layers this repository declares live under "layers" in the root
magusfile.buzz: transport, handler, service, repository and composition.
A directory is drawn once, so a box inside a group's dirs is refused; drop it
with figure\without. look: takes figure\Look.focal, store, external,
input, optional, decision (actors only) or plain. Add a legend() line
for each look you use.
Edges
edgesFromGraph() draws every import and every declared magus:calls marker
between two drawn boxes, and a figure with two or more code boxes must call it.
Every drawn directory needs a symbol index, so run magus graph build first.
hideEdges(src, dst:, why:)drops graph edges from one list of dirs to another, with a reason. A hide that matches nothing is a finding.markEdge(src, dst:, label:, stroke:)labels or strokes one graph edge.flowIn,flowOutandflowAcrossare the only hand edges, and each has an actor at one end. An edge between two packages is never drawn by hand.
Scope
scope(dirs) names the directories the figure answers for. Every one must be
drawn by a box or a group, or left out with except(dirs, why:), which is for a
true exclusion. A figure with no code behind it says so with unscoped(why:).
Findings
Nothing is drawn until the figure is clean. Each finding names the call to change:
10 nodes exceeds the budget of 9; split into overview plus detail, one figure\of() each: cut or fold boxes, or make two figures."internal/x" is in scope("internal/**") but nothing draws it: draw it, or narrow the scope. A finding names a list of dirs by the deepest directory holding them all, or by its one path.draws 2 boxes of code and no edge between them; call edgesFromGraph()."a" has no symbol index: build it withmagus graph build.hideEdges(...) hides no edge the graph draws: the code changed; drop the hide.
Generating the files
magus run diagrams-generate docs lays every figure out from the symbol index
and writes into docs/assets/gen/ the dark and light pair the README loads,
the page copy the site inlines, and a receipt beside each: the stamp, the claim
counts, the findings and the index digest it was drawn at. The stamp is also in
each SVG's metadata. It fails when the committed files move; :rw rewrites
them. The site render reads only the page copies, so it never needs the index.
The console view
The console's Diagrams page draws the project graph, one project's targets and
the import graph from /api/v1/diagrams, each through a lens of scope, focus
and depth. The server embeds the same module this site builds with, and boxes
link to their source.
Credit
The design system, its palette, role treatments and budgets, is cathrynlavery/diagram-design (MIT).