Workbooks Documentation

The Build Plan

The build plan is a JSON document the OQL kernel emits from a workbook's source. It describes the complete set of WASM worlds, components, inputs, outputs, and edges — everything the runtime needs to compile and wire the workbook's code. It is the interface between the Org source and the WASM execution layer.

Structure

{
  "worlds": [
    {
      "id": "my-workbook/score-items",
      "lang": "javascript",
      "src": "export function score_items(items) { ... }",
      "args": {"in": ["items"], "out": ["scores"]}
    }
  ],
  "components": [
    {
      "id": "my-workbook/score-items",
      "world": "my-workbook/score-items",
      "in": ["items"],
      "out": ["scores"],
      "deps": []
    }
  ],
  "edges": [],
  "imports": ["items"],
  "exports": ["scores"]
}
KeyTypeDescription
worldsarrayOne entry per compilable source block. Contains the source text and language.
componentsarrayOne entry per wired component (heading with :in:, :out:, or :deps:).
edgesarrayDirected edges connecting component outputs to inputs.
importsarrayNames the workbook consumes from outside (unresolved inputs).
exportsarrayNames the workbook produces (resolved outputs).

How OQL builds it

The Rust kernel (kernel/src/lib.rs) uses the orgize parser to walk the heading tree. For each heading it collects:

  1. :PROPERTIES: → reads :in:, :out:, :deps:, :sig:

  2. Child source blocks → reads language, source text, and block header args

  3. Heading title → derives the component ID (lowercased, hyphenated)

A World is created for each source block that has a compilable language. A Comp is created for each heading that declares :in:, :out:, or :deps:. Args holds the parsed property values. A Sig holds the optional explicit WIT signature.

Edges are computed by matching: for each component with :deps: entries, find the upstream component(s) and create directed edges from their :out: names to this component's matching :in: names.

Inspecting the plan

wb tangle my.org          # prints the full plan as JSON
wb tangle my.org | jq .   # pretty-print with jq

Or in iex:

org = File.read!("my.org")
plan = Workbooks.OQL.tangle_plan(org)
plan["worlds"]      # list of worlds
plan["components"]  # list of components
plan["edges"]       # list of edges
plan["imports"]     # top-level inputs
plan["exports"]     # top-level outputs

Worlds vs components

A world is a compilable unit: source code + language. It maps directly to a WASM module. A component is the wired unit: it references a world and declares how its inputs and outputs connect to the rest of the graph.

One world can back multiple components (the same code reused with different wiring), though this is uncommon in practice. The more common case is 1:1.

The edge map

Each edge in edges is:

{
  "from": {"component": "parse-input", "port": "parsed"},
  "to":   {"component": "process",     "port": "parsed"}
}

The runtime walks edges topologically to determine execution order. Components with no incoming edges run first; components with unsatisfied imports wait until their upstream completes.

Validation

wb lint my.org (or Workbooks.OQL.lint/1) checks the build plan for common errors:

  • Declared :deps: that reference non-existent components

  • :in: names with no upstream edge and no workbook-level import

  • :out: names that nothing downstream consumes (warnings, not errors)

  • Source blocks with unsupported languages (if :out: is declared)

The current lint implementation is a stub that returns an empty issues list — full static analysis is a planned addition.

WIT component model

The runtime uses the WASM Component Model (WIT) to type-check component interfaces at link time. Each world in the build plan is compiled to a WIT component; the engine verifies that the types declared in :sig: (or inferred from :in: / :out:) are satisfied before execution. Type mismatches are caught at link time, not at runtime.