Workbench

ontologiq workbench          # http://127.0.0.1:4400
ontologiq workbench --open   # and open the browser

One command, one page, no extra dependencies: the workbench is served by the CLI itself, from the compiled ontology and your adapter connection. It is the operational counterpart of ontologiq docs: where the docs page describes the ontology for a reviewer, the workbench shows it running — definitions next to live warehouse records, preconditions evaluated on demand, proposals as they arrive.

Live on both axes. Records are queried from the warehouse on every request, and the ontology itself follows the YAML while the workbench runs: add an object, save, and the graph has it within seconds — its records too, because reads are built from the compiled SELECT rather than the materialized view, so run can come later. An edit that does not validate never takes the page down: the last good ontology keeps serving and the validation error appears as a banner until you fix it.

What you see

Overview. The entity graph — same deterministic layout as the docs page — with governed objects outlined. Click a node to browse it.

Objects. For each object: its properties, its states with the predicate that computes each one in priority order, its relations, its generated SQL — and beneath the definition, the live records, with computed state as a chip on every row and one-click filters per state. Click a row to open the record: every field, its relations one hop away, and the actions that apply to it.

Actions. Every governed action with its roles, precondition, approval rule and effect. Open one and you get a console: fill the identity and the parameters, pick a role to evaluate as, and dry run it. The same code path an agent’s dry run takes checks the role and evaluates the precondition against live data, then reports what would happen — record snapshot, whether approval would be required, what the effect would be. Nothing is proposed and nothing executes.

Proposals. The approval queue, live. Each pending proposal shows what was proposed, by which role, with which parameters, and when it expires — and next to it, the exact terminal command that decides it, ready to copy. Decided proposals stay visible as history with their outcomes.

Audit. The append-only trail: every denial, proposal, approval, precondition re-check and effect outcome, in order.

What you cannot do, and why

The workbench holds no write path. There is no propose button, no approve button, no route that fires an effect — the only POST it answers is the dry run, which changes nothing. This is not a missing feature; it is the security model applied to a new surface.

The product’s central guarantee is that an agent cannot complete a gated action on its own, because approval lives in a process the model has no way to address. An HTTP server on localhost is addressable — and an agent already knows its proposal_id, because the propose response returns it. If the workbench had an approve endpoint, one POST would close the loop with no human anywhere. So it does not have one, and a test pins that: every mutating route answers 405 with the reason.

Three more structural choices, each also pinned by a test:

The loop it enables

The workbench makes the decision informed; the terminal makes the decision:

  1. An agent (or a colleague with ontologiq propose) proposes an action. The badge in the workbench ticks up.
  2. You open the proposal: identity, parameters, proposer, expiry. You browse the record it targets and see its current state.
  3. You dry-run the action if you want the precondition checked this second, against live data.
  4. You copy the ontologiq approvals approve … command the page offers, and run it in your terminal. The precondition is evaluated once more at execution — if the record moved while you deliberated, nothing executes.

When HTTP transport with OIDC lands, the identity of the person clicking becomes a verifiable fact rather than an assertion, and approval can move into the page. Until then the split stays physical — and the workbench is honest about it in its own header.