okf-gem · docs
CLI · serve & setup

okf server

Walk the bundle as a live graph.

When to use it

  • To explore a bundle the way it is meant to be read: as a graph, following links instead of directory listings.
  • While curating: edits show on the next click without a restart, so you can fix a concept and immediately see it re-rendered.
  • To show a bundle to someone. The live demo is this server running on the gem's own bundle.
  • To keep every bundle you work with one command away: a bare okf server hosts the whole registry behind one hub.

How it works

okf server takes zero or more bundles, and the count picks the mode. One directory (or one @slug) is the classic single bundle at /. Two or more mount behind a hub, each at /b/<slug>/, with the first at /. A @group from the registry mounts each of its members the same way, the first at /. None at all serves every bundle in the registry, its default at /. Behind a hub, /b/ is a browsable index of the hosted bundles, an unknown slug answers with a page listing the way home instead of bare text, and Cmd/Ctrl-K opens a switcher to move between bundles without leaving the page.

It starts a local HTTP server and prints its URL; stop it with Ctrl-C. -p/--port picks the port (default 8808), --bind the address (default 127.0.0.1), and --title, --link, and --layout tune the header and the initial layout. --map opens the graph with no links and the directories boxed, the far end of the link-amount control. --read-only declines the registry management the graph page offers by default (the Bundles panel and its write routes), which is on for a loopback bind and refused outright on any other address.

Responses are gzipped whenever the client accepts it, which browsers do. The compression sits at the boot seam, Rack::Deflater wrapped around the app as the CLI starts it: lossless, transparent, and at no new dependency, because Deflater ships inside the rack the gem already requires. A client that sends no Accept-Encoding keeps getting identity responses. The wrap is boot policy rather than part of the app, so a host mounting OKF::Server::App in Rails brings its own compression, and the static file okf render writes is served however your host serves it.

The page boots from a lean payload (nodes carry only id and title, plus compact type and tag indexes) and fetches each concept's markdown body live from disk as you click it, so the initial load stays small and edits show without a restart. Concepts render as nodes colored by type and sized by degree, links as edges, with a detail panel (rendered markdown, "Links to" and "Linked from" backlinks), layout switching, type/directory/tag filters on every view, and search. Search is a ranked MiniSearch index shared by the graph, catalog, and files views: several terms are ANDed, a term matches the tokens it prefixes as you type, and a typo still lands. Under the live server that index stays metadata-only (ids, titles, types, tags, descriptions), because bodies are fetched lazily and are not in the page to index; okf render bakes them in and searches them too. On the server side the search corpus is built once and warmed at boot rather than rebuilt per request, so a query answers in milliseconds; a hub drops it on any registry write so a held index never outlives its set. The graph page also carries a Bundles panel for managing the registry from the browser, which --read-only declines; the graph server page has the link-amount control, the spine, and that panel in full. Mermaid code blocks in a body render as diagrams, and a click or tap opens the diagram fullscreen with drag to pan and wheel or pinch to zoom. It is a Rack app, so the same server can be mounted in a host app such as Rails; the library page shows how.

The page is one template from a phone to a desktop, and it is keyboard-first. On small screens the navigation rail becomes a drawer, the toolbar folds into a settings sheet, and the panels go full-bleed; rotate a tablet and the layout re-evaluates rather than staying stuck. Cmd/Ctrl-K opens a command palette in every mode, views always in the list and bundles too when a hub is serving them; / jumps to the current view's search; ? answers with a sheet of every shortcut, also reachable from the rail; Esc clears the graph selection.

On the trust side, the page defends the two paths a hostile bundle could use: inlined graph data is escaped so it cannot break out of its <script>, and every fetched body runs through DOMPurify before it reaches the DOM, so a script or event handler hidden in a markdown body is stripped rather than executed. The page still loads its viewer libraries (Cytoscape, marked, and DOMPurify, plus Mermaid, Panzoom, and MiniSearch on first use) from a CDN and renders whatever links a body contains, so treat an unfamiliar bundle the way you would treat any document from a source you do not know. The graph server page has the full write-up.

Try it

okf server docs/
serving 37 concepts at http://127.0.0.1:8808 (Ctrl-C to stop)

Then open the printed URL. There is no --json here; the machine-readable equivalents are okf graph for the structure and okf catalog for the panel data.

Pitfalls

  • The hub reads its bundles at boot. Registering or renaming a bundle while a server runs changes nothing on the page; restart the server to pick the registry up. That is the honest trade for a hub that never re-scans disk per request.
  • Best-effort, by design. Under section 9, a file with invalid frontmatter is skipped and noted on stderr, never fatal, so the graph you browse can be smaller than the directory. Run okf validate to see what was left out.
  • It binds to 127.0.0.1 by default. Passing --bind 0.0.0.0 exposes the bundle (and your disk reads on its behalf) to the network; do that deliberately, not casually.
  • The page needs a network for its libraries. Cytoscape, marked, and DOMPurify come from a CDN at boot, and Mermaid and Panzoom follow on the first diagram, so the graph view will not render fully offline even though the bundle itself is local.
esc
navigate open