hiveloomdocs

The workbench

The workbench is hiveloom's development UI: a chat-first environment for building, running, debugging, and improving harnesses without first learning the CLI or the specification language. Everything the framework knows about a harness — its spec, its runs, the full journal of any one of them, its version history, its pending improvement proposals — is one click away, beside a conversation with an agent that can act on all of it.

uv add hiveloom          # the framework your harnesses run on
npx hiveloom-workbench   # the inspector — fetched on demand, nothing to install

It opens on http://127.0.0.1:8770. --host 0.0.0.0 when the browser is not on this machine, --port to move it, --dir to offer one harness beyond the registry, --scan-dir to discover a tree (./harnesses is picked up automatically). State — conversations, memory, and the copilot's own working copy — lives under ~/.hiveloom/workbench/, which HIVELOOM_HOME relocates and HIVELOOM_UI_DB overrides for the database alone.

One package, three parts. npx fetches a single npm package containing the compiled interface, the Python API (server.py and the copilot harness), and a Node launcher. The launcher finds the interpreter that has hiveloom — your project's uv environment, an active virtualenv, or one it creates on demand — starts the API on a private loopback port, and serves the interface in front of it, proxying /api through. You get one URL and one origin; the API is not reachable from anywhere else.

Why the API is still Python. Every action in the workbench validates a spec, runs a harness, reads a journal, or drafts an evolution proposal. Those are hiveloom's own modules. A JavaScript reimplementation would mean two versions of the rules that decide whether foreign code is allowed to run, so the workbench composes the real ones instead.

Why it is not part of the hiveloom wheel. The framework is what runs a harness in production, on machines that will never open a browser. Shipping the inspector separately keeps uv add hiveloom exactly as small for everyone who does not want it, and hiveloom ui is a shortcut to the same npx command.

From a checkout

Contributors run both halves with hot reload instead:

devtools/ui/dev.sh
#   workbench   http://127.0.0.1:5173
#   api         http://127.0.0.1:8770

The first launch installs the local npm dependencies. Ports move with HIVELOOM_UI_PORT and HIVELOOM_UI_API_PORT, and harnesses come from the local registry plus a recursive scan of this checkout's harnesses/. A checkout keeps its state in devtools/ui/.hiveloom/ rather than under ~/.hiveloom, so development never writes into the directory an installed workbench uses.

The workbench: the copilot conversation on the left, the selected harness's workspace on the right

One conversation, and evidence beside it

There is one primary interaction: a conversation with the bundled hiveloom-copilot harness — a framework expert with constrained tools for creating, inspecting, validating, dry-running, executing, diagnosing, measuring, and proposing improvements to target harnesses.

Target harnesses are context, not alternate chat agents. Selecting a harness or run in the rail attaches it to the conversation. A target execution is always a separate, journalled run owned by that target harness, so copilot reasoning never pollutes the target's fitness data.

Chat stays the front door, but it is never the only route to a fact. Selecting a harness opens its workspace beside the conversation, with seven tabs that show the framework's exact state rather than the copilot's paraphrase of it:

Tab What it is
Use the harness's generated interface — a real, runnable page
Overview contract, model, tools, guardrails, verification at a glance
Runs every recorded run, with outcome, cost, and turns
Trace the complete journal: filters, integrity, payloads, context, timing, fork
Versions the version graph, tags, and side-by-side comparison
Spec the validated spec, editable through the same construction API
Improve the evolution proposal queue and its human gate

Opening a workspace collapses the navigation rail to an icon strip; drag the divider (or focus it and use the arrow keys) to resize the evidence area.

Conversations are durable. Messages, artifacts, and the selected harness/run live in a local SQLite database (~/.hiveloom/workbench/workbench.db, or devtools/ui/.hiveloom/workbench.db from a checkout) ignored by Git (HIVELOOM_UI_DB moves it). A browser refresh or an API restart resumes the same conversation instead of opening an empty one.

Cross-conversation memory is separate and explicit. Global and harness-scoped memories share that database, are inspectable and deletable under Settings → Memory, and reach the copilot through recall_memories, remember_memory, and forget_memory. The copilot is instructed to save only requested or clearly durable preferences; ordinary conversation content is never silently promoted into memory.

The journal, readable

The Trace tab is the reason the workbench exists. A run's journal is long, structured, and nested — exactly the shape a terminal is worst at.

The Trace tab: the ordered journal, integrity result, event payload, and the folded context at a chosen model call

It shows the ordered events with filters, the hash-chain integrity result, each event's payload, the folded context at any model call (the exact request that went to the provider), per-event timing, and the fork controls. A completed run also exports: GET /api/runs/{id}/export returns the journal bytes verbatim, because a re-serialisation would not verify against the hash chain.

Live runs are steerable

A run in flight is not a black box. The run stream opens with run_accepted carrying a pre-allocated id, and that id addresses the run while it is still going:

Action Endpoint
Stop POST /api/runs/{id}/stop
Steer POST /api/runs/{id}/messages (with GET, PATCH, DELETE)
Change model POST /api/runs/{id}/model
Change mode POST /api/runs/{id}/playbook
Fork POST /api/runs/{id}/fork

Steering messages are addressable: you can see the queue before the loop drains it, and edit a message in place rather than re-queueing it, so a correction cannot silently reorder what the agent is told. A playbook switch goes through the mode's own on_enter/on_exit gates — an operator switch uses the same door the model does, not a way around it — and the model is told, because a mode change it cannot see is one it will misread.

Everything here is RunControl in hiveloom.loop.control, applied at the loop's next turn boundary, where no model call or tool is in flight. The workbench is a client of it, not a privileged path.

Fork, compare, resume

The Versions tab puts two versions side by side with deltas and the failure signatures that appeared or disappeared between them. The fork controls turn a failed run into an experiment: pick a model call, name the fork, optionally override the model, and resume it.

The Versions tab: two harness versions compared, with deltas and changed failure signatures

Forks are nested under the harness that contains them. Catalog rows carry root_path, is_fork, and parent_id, and the rail groups by containment rather than by name — so a renamed fork stays with its harness, and two unrelated harnesses that share a name stay two harnesses. A fork's target name is slug-checked and resolved beside its parent: a fork writes files, and a browser must never choose where.

POST /api/harnesses/{id}/resume re-runs a fork from the journal point it was created at.

Delegated runs read as one run

A harness that hands its task to a peer (delegation) produces two runs, and the workbench keeps the link between them visible from both ends.

A turn's reply carries a delegated to <peer> line per hand-off — status, cost, turns, and a click straight into the child run — and the cost footer says how much of the total was spent elsewhere (incl. $0.0310 delegated). Peers that fitted but were not used appear under it as referrals, with the measured odds that ruled them out: ranked-retrieval · success 82% over 44 runs · below_fitness. That is the run answering "I am not the right harness for this, ask that one" rather than guessing.

In the Trace tab, the run header gains a delegation stat, a delegated run says so and links to the parent that handed it the work, and the Lineage evidence lists every child — forks by their re-entry seq, delegated runs by the harness that did the work — each one clickable. Delegation is its own event filter: the four delegation_* events read as one hand-off each, showing the peer and its fitness, the depth, chain and cost cap, and the child's status, cost and run id — or, when nothing was handed over, the reason.

Improvement stays gated

The copilot may draft an improvement; applying it is a distinct user action. The UI applies accepted YAML changes explicitly and leaves code changes unapproved unless you select them — silence is a refusal, not consent. Frozen safety fields remain protected by hiveloom's evolution gate, which the UI cannot bypass because it goes through the same construct API everything else does.

Generated interfaces

create_interface writes a dependency-free page to <harness>/interfaces/default/index.html and returns the complete HTML as an artifact. This is how a harness stops being a CLI invocation and becomes something you can hand to someone.

A generated harness interface running inside the workbench preview

The workbench previews it in an allow-scripts sandbox with a narrow message bridge that can only run the artifact's named harness. URL and text contracts send literal input; file contracts upload into the harness workspace and send the resulting safe relative path. Preview executions use the normal streaming runner, so progress, stop control, verification verdicts, cost, and run identity stay visible, and a finished preview opens directly into the same recorded trace the Runs view uses.

Select a harness and choose Use. Harnesses without an interface explain the copilot request that creates one; afterwards the same selection opens the runnable page directly. The generated page also works against the ordinary non-streaming /run endpoint when hosted with a deployment — a direct file page needs a deployment-provided upload bridge, which the workbench preview supplies automatically.

Safety and boundaries

  • The bundled copilot is validated and trusted when the workbench starts.
  • Foreign target harnesses keep the normal trust gate before their code runs.
  • Harness creation goes through hiveloom.construct; every step validates, and a failed creation removes the incomplete directory.
  • Builtin names come from the live catalog, never a UI-maintained copy.
  • Uploads pass through hiveloom's safe-path containment and cannot enter .hiveloom or .env.
  • The preview iframe receives no credentials and no direct framework object.
  • Copilot selection is request-owned context, not a global, so concurrent chats do not leak their selected harness or run into one another.
  • Credentials are inherited: a harness runs inside the API process, so its provider's key must be exported where dev.sh runs, or live in the harness's own .env.

Tests

uv run pytest -q tests/test_devtools_ui.py
uv run ruff check devtools/ui/server.py devtools/ui/copilot/tools/workbench.py
npm run typecheck --prefix devtools/ui
npm test --prefix devtools/ui
npm run build --prefix devtools/ui

scripts/build_workbench.sh    # the release build, end to end

uv run hiveloom validate devtools/ui/copilot --json
uv run hiveloom run devtools/ui/copilot --input "inspect this harness" --dry-run --json