Skip to content

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

The Patchbay's code, docs and data as one graphUser-guide sections document UI actions and functions; actions are handled by functions; functions request API routes that server functions serve; code files read and write datasets; knowledge-base datasets define and describe the items, manuals and manual sections of the knowledge graph.User guide12 sectionsUI actions34 buttonsFunctions111 JS, 43 PythonCALLS 416 among themAPI routes7, two serversDeveloper README9 sectionsCode files7Datasets9 KB, 8 app stateKnowledge graphItems (79)Manuals (66)Sections (1,930)privateDOCUMENTS 34DOCUMENTS 20DOCUMENTS 3HANDLED_BY 60REQUESTS 9SERVED_BY 12DEFINES 154READS 24WRITES 6DEFINES 79, DESCRIBES 136DEFINES 66DEFINESdocumentationwhat a user clickscodedata and knowledgeprivate (not in the public graph)

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.

What a change to /api/sessions touchesRead right to left from the API: the functions that call it, the buttons they handle, and the user-guide sections that document either; and left to right to the two implementations that serve it.Review these guide sectionsGetting startedSessions and templatesButtonsopensavesaveasFunctions that call itbootopenDialogsaveAPI routesDELETE /api/sessions/:idGET /api/sessionsGET /api/sessions/:idPUT /api/sessions/:idServed bydo_DELETE (local)do_GET (local)do_PUT (local)staticApi (website)

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: pass cross: 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.

One app among many on a platformSeveral apps each publish a docs-to-code graph in the same schema; they join through shared datasets and API contracts into one knowledge graph of domain entities, documentation, code and owners.Patchbaythis repositoryDocsCodeAnother appsame schemaDocsCodeA servicesame schemaDocsCodeShared datasets and API contractsOne knowledge graphdomain entities + docs + code + ownersEach app publishes its owncode<->docs graph in the sameschema at build time.They join on shared ids:datasets, API routes, entities.Questions then cross appboundaries.

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_BY edges, "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.