title: Patchbay: code, docs and the knowledge graph
Patchbay: code, docs and the knowledge graph
The Patchbay is small enough to read in an afternoon, which makes it a good place to show an idea that matters much more at scale: documentation, code and data can be one graph, built from the source on every change, so that questions like "which pages go stale if this API changes?" are answered by a query instead of by memory.
tools/build_code_graph.py reads the app (its Python with the ast module, its JavaScript, its HTML buttons, its
user guide and README) and writes graph/public/code.json: 243 vertices and
785 typed edges. tools/build_graph.py merges that into the main knowledge graph, and the graph's
question runner checks three questions about it against answers worked out without the graph.
One graph, from a guide page down to the gear
Counts are computed from graph/public/code.json and the knowledge graph on every build. Manual sections stay private (copyright), so their edges never reach the public snapshot.
| Relationship | Edges | How it is derived |
|---|---|---|
| CALLS | 416 | parsed (a call to a known function in the body) |
| DEFINES | 154 | parsed (Python ast; JavaScript top-level functions) |
| HANDLED_BY | 60 | parsed (the onAction switch) |
| DOCUMENTS | 57 | declared in the guide (covers notes); README paths parsed |
| CONTAINS | 28 | parsed (files in patchbay/) |
| READS | 24 | parsed (file names in the code) |
| PART_OF | 17 | declared |
| SERVED_BY | 12 | parsed (server routes; the website's stand-in) |
| REQUESTS | 9 | parsed (api() calls) |
| WRITES | 6 | declared, then verified in the code |
| USES | 2 | declared |
Most edges are parsed from the code. The links from the user guide to the code are declared: each guide section
ends with a hidden note such as covers: save saveas fn:openDialog. Declared links are then checked, so they cannot
quietly rot. The build fails if a button has no guide section, if a note names a button or function that no longer
exists, or if a section covers a button but never shows its on-screen label. It also fails if the README names a code
file that is gone, if the client calls an API route that no server serves, or if a module claims to write a file it
never writes. The first run of these checks caught two real drift bugs: the guide said "jack labels" where the button
says "jack names", and the README pointed at a path that only exists one folder up.
Which guide section covers which button
| Guide section | Buttons it documents | Functions it documents |
|---|---|---|
| Adding gear from the palette | — | addNode, autoPatch, renderPalette |
| Arranging the canvas | collapse, delete, dup, fit, jack-labels, redo, undo | — |
| Checks | — | warnings |
| Device settings and start state | field-add, field-del, state-clear, state-kb | homeChannelOptions, stateInspector |
| Editing a device's jacks | port-add, ports-cancel, ports-edit, ports-save | savePorts |
| Exporting a diagram | export-png, export-svg | exportFile |
| Faceplates, boxes and icons | photos, theme, view-mode | iconHTML |
| Getting started | — | api, boot, saveDraft, staticApi |
| Patching cables | reverse | addCable, onPointerDown, renderLegend |
| Placing jacks on a panel | place-done, place-jacks, place-reset, place-skip | — |
| Sessions and templates | load-template, new, open, save, saveas | openDialog, sessionInspector |
| The Eurorack rack | enter-rack, exit-rack, rack-add-all, rack-arrange | arrangePanels, rackPower |
Worked example: what a change to the session API touches
Only three functions call /api/sessions: boot, openDialog, save. The buttons they handle are
open, save, saveas. The guide sections that document either are
Getting started and Sessions and templates. The same routes are served twice: by the local server (do_GET,
do_PUT, do_DELETE) and by the website's stand-in (staticApi), so a change has two implementations to keep in step.
Drawn from code.json with the same rule the graph question uses: direct links only, so the dispatcher that reaches every function does not flag every page.
Tied to the knowledge graph
The app's datasets are the join. A knowledge-base file defines the vertices it is the source of record for
(inventory.yaml → every item) and describes the ones it adds facts to (connections.yaml → the items it
wires or mounts). The Patchbay's own files (sessions, jack edits) belong to the app, not the knowledge base.
| Dataset | Belongs to | Read by | Written by | Knowledge-graph vertices it defines or describes (public) |
|---|---|---|---|---|
connections.yaml |
gear-kb | build_data.py, extract_ports.py | — | 43 |
docs/manuals |
gear-kb | extract_ports.py | — | 1,930 manual sections (private, so not in the public graph) |
graph/public/budget.json |
gear-kb | build_data.py | — | — |
graph/public/vertices.json |
gear-kb | build_data.py | — | — |
images |
gear-kb | build_data.py, trace_icons.py | — | — |
inventory.yaml |
gear-kb | build_data.py, common.py, extract_ports.py | — | 79 |
midi_channels.yaml |
gear-kb | build_data.py | — | 14 |
sources/eurorack |
gear-kb | extract_ports.py | — | — |
tools/image_manifest.yaml |
gear-kb | build_data.py, trace_icons.py | — | 79 |
patchbay/data/gear.json |
patchbay | app.js, patchbay.py | build_data.py | — |
patchbay/data/ports.seed.yaml |
patchbay | build_data.py, patchbay.py | extract_ports.py | — |
patchbay/device_fields.yaml |
patchbay | build_data.py | — | — |
patchbay/icons |
patchbay | patchbay.py | trace_icons.py | — |
patchbay/panels.yaml |
patchbay | — | patchbay.py | — |
patchbay/ports.yaml |
patchbay | build_data.py, common.py, extract_ports.py | patchbay.py | — |
patchbay/sessions |
patchbay | — | patchbay.py | — |
patchbay/templates.yaml |
patchbay | build_data.py | — | — |
Checked against the graph (each answer is also worked out without the graph):
- Which of the Patchbay's buttons have no section in its user guide? 0 UI actions have no user-guide section.
hand: passcross: pass - If the Patchbay's session API (/api/sessions) changed, which user-guide sections would need a review? review: Getting started, Sessions and templates; because these functions call /api/sessions: boot, openDialog, save; and these buttons are handled by them: open, save, saveas.
hand: pass - Which knowledge-base datasets does the Patchbay read, and how many knowledge-graph vertices does each one define or describe? connections.yaml: 43 knowledge-graph vertices; inventory.yaml: 79 knowledge-graph vertices; midi_channels.yaml: 14 knowledge-graph vertices; tools/image_manifest.yaml: 79 knowledge-graph vertices.
cross: pass
Scaled out: the Patchbay as one app on a larger platform
Picture the Patchbay as one of many applications and services on a shared platform, each with its own user docs and its own code, all built on shared data and shared APIs. The same relationships carry over unchanged, and they get more useful as the platform grows.
Each app publishes the same small schema at build time. The graph is the union, joined on ids that several apps share.
The schema is small and stays the same. Four families of relationship cover it: documentation
(DOCUMENTS), behaviour (HANDLED_BY, CALLS, REQUESTS, SERVED_BY), data lineage (READS, WRITES,
DEFINES, DESCRIBES) and ownership (CONTAINS, PART_OF, USES, and in a larger setting an OWNED_BY edge
to a team). Every app's build emits its own slice in that schema, exactly as build_code_graph.py does here, and a
central job merges the slices.
Apps join through what they share, not through each other. Two apps never need to know about each other: they meet at a dataset both read, an API route one serves and another calls, or a domain entity (here, a piece of gear) their data defines. Those shared ids are what turn many small graphs into one.
The questions cross app boundaries. With the slices merged, the same queries this page runs for one app run for all of them:
- Change impact: "If this dataset's schema changes, which apps read it, which of their features use it, and which user-guide pages must be reviewed?" (the worked example above, across every app at once)
- Documentation debt: "Which user-facing features, in any app, have no documentation?" (question q10, platform-wide)
- Stale docs: "Which pages document a button, route or function that no longer exists?" (caught at build time)
- Answer grounding: a support or search question lands on a guide section; the graph walks from that section to the feature, the code that implements it, the data it reads, and the domain entities involved, so an answer can cite all of them. Graph neighbours also help rank search results.
- Ownership: with
OWNED_BYedges, "who owns every page affected by this change?"
What keeps it trustworthy at scale is what keeps it trustworthy here: every edge says how it was derived (parsed, declared, or verified), declared links are checked on every build so drift fails the build rather than accumulating, inputs are hashed so a stale graph is refused, visibility rules keep private material out of what gets published (as the manual sections are kept out here), and each graph question is checked against an answer worked out without the graph.
Honest limits of this small version. The JavaScript is read with patterns, not a full parser, so dynamic calls are missed; the guide-to-code links are hand-declared (checked, but written by a person); and the impact rule follows direct links only. A platform version would use proper parsers per language and would add service-level edges (queues, events, schemas) alongside the function-level ones shown here.