Bringing Linux up on a new board is one question asked a hundred times a day: the touchscreen is dead, why? The answer is always in the device tree, and the tools for finding it are dmesg and grep.

The Linux device tree is already a tree of nodes with typed relationships. Jac is a language whose primitives are nodes, edges and walkers. JacOS takes that correspondence seriously. It reads the device tree out of a running kernel and materialises it as a live Jac graph: 465 nodes and 732 edges off a real Motorola Moto E4. A device's vdd-supply = <&pm8937_l6> phandle becomes a typed SuppliedBy edge; clocks = <&gcc 42> becomes ClockedBy. Once those edges exist, "what does this device depend on" is a traversal.

Assessment is dispatched by node type on arrival — can check_regulator with Regulator entry, can check_device with Device entry. A regulator is healthy if its rail is enabled; a device is healthy if a driver bound. Those are different questions and the walker never branches on kind: it arrives and the right ability fires. Descent is one generic exit ability on the HwNode base, so traversal policy is written once for the whole machine. Root cause is ranked by walking the dependency chain and preferring the deepest, most fundamental fault. byLLM's return type is a typed Diagnosis object, so the type is the schema — there is no prompt template and no output parsing anywhere in the repo. The walker finds the fault; the LLM only phrases it.

The same walkers drive both frontends. The web console's client does root spawn DiagnoseNode(...) and the server wrapper spawns the identical Diagnose walker the CLI spawns. One graph, two frontends, zero duplicated diagnostic logic.

We brought a phone that already runs Linux; today we built the layer on top. Every number above was verified on that hardware.

For a board bring-up engineer or postmarketOS porter, this turns tribal knowledge into a query. And it makes a $10 phone out of a drawer — CPU, battery, modem, sensors — worth reviving instead of throwing away.

tools/dtb.py walks /sys/firmware/devicetree/base and resolves every phandle into a typed node/edge spec, then joins it against sysfs for live state. src/topology.jac declares the HwNode hierarchy and the five edge archetypes. src/importer.jac materialises the spec into Jac archetypes hung off root — and because Jac persists everything reachable from root, that graph is the database. No ORM, no schema, no serialisation layer in the repo.

src/diagnose.jac holds the walkers: Diagnose (spawn on a symptom, traverse outward, assess each hop, rank a root cause), Survey and Probe. src/explain.jac declares the byLLM Diagnosis object. src/jacos.jac is the CLI. src/main.jac plus src/webapi.sv.jac and src/components/ManPage.cl.jac are the fullstack web console — Jac 0.16.7 codespaces, no jac-cloud needed.

On the device: busybox-only capture scripts, and an offline install that unzips the jaclang wheel and points PYTHONPATH at it, because the phone has no pip and no network.

Built With

  • busybox
  • byllm
  • devicetree
  • jac-client
  • jaclang
  • linux
  • postmarketos
  • python
Share this project:

Updates