onepipeline-ui
The read API and browser view for onepipeline runs: an axum server wrapping the onepipeline SDK, plus the frontend that reads it.
npm install -g onepipeline-api-cli # or pip, or cargo — see Install
onepipeline-api serve --runs-root ./runs --ui # the API, and the view above at /
The DAG Observatory
apps/dag-ui is that view: every run under a runs root, read as a
whole and then one level at a time. It opens on the projects — one card per plan,
newest activity first, each counting its runs in the server's own words — and a run
opened from one keeps that page a step back. The Overall view above is the run
read as a whole: its telemetry tiles over the graph timeline, which is the same plot,
the same lane words and the same clock used at three scopes — the whole run, one node,
one conversation — each a single click into the last.
It is not only a read. Every verb the onepipeline CLI has once a plan is running is
here, from the run it is about: stop, adopt, attest, reply on the channel, and shut
down a run, every run this session owns, or the whole host — each behind a confirm
that names what it will act on, and each showing the engine's own receipt or refusal
verbatim rather than a restatement of it. docs/dag-ui.md is the
design record; what follows is what the screens are.
The graph
Status and progress at a glance. Green nodes succeeded, red ones failed or were cancelled, and an animated highlight marks the work still running. The canvas arrives fitted whole — every card inside it — at every width the view is read at, and its own controls zoom in from there; a floor on the fit rather than a fixed scale, because the scale that fits a plan of six on a desktop shows a third of it on a phone with the rest off both sides of a canvas that says nothing about having more beside it. Selecting a node here, or from the keyboard-accessible node list beside it, opens that node's timeline.
A node: its timeline over its transcript
One node, read the way the run was. The plot at the top is the node's own work on the
node's own clock, collapsed to one line and expandable into a row per category; the
list underneath is what the node recorded, turn by turn. The two are one reading —
selecting in either moves the other — and the vocabulary does not change on the way
down, so a segment labelled worker · judge at the graph scope sits in the worker
lane here and heads the conversation opened from it with the same words.
A conversation
The third scope. A transcript opens beside the timeline it came from, with that session's own turns plotted above them and each turn's tokens and cost read underneath it. A transcript is re-read only when the served timeline says that session recorded something, so a run whose other nodes are busy costs an open conversation nothing; when the session it belongs to is live, new turns are appended underneath the ones already on the page rather than replacing them, and the panel follows that growth only while the reader is at the end of it.
Projects
A bare address is the project list, in the server's own order. The runs whose launch recorded no project are a card like any other, headed by that word rather than by the plan name of whichever run in them wrote last. A project's page is every DAG launched against it, each row the same row the flat run list serves. Nothing here recomputes an order or a count: the tallies are of the served rows, in the served words.
The channel
The run's channel, shown as the engine keeps it: the pending surface nobody has given up on, the waiting ones nobody has read, an abandoned one where the process serving it exited without an answer, and the answered ones. Reading it consumes nothing. The composer sends the editor's text byte for byte — never a parse of it — so a manager can type an envelope this app has never heard of and the engine's refusal of a malformed one is the engine's own.
At the width it is actually read
The shell is exactly one viewport tall and every region inside it scrolls on its own, which is a thing that fails silently — a region that overflows reports nothing, it just puts content where no scroll can reach it. So the view is held to five widths down to a phone, and a journey drives the ones whose outcome depends on width at both extremes. The phone is where the two columns stop being a comfortable fit, which makes it the width every reflow defect shows up at first.
Every screen above is a real capture of this app, driven by
just dag-ui-screens against the real
onepipeline-api serve --ui over a generated run corpus, and gated on the content hash
of each image by screencomp — so a
picture here cannot quietly stop being true of the app.
The read API
docs/contract.md is the source of truth, quoted verbatim
from the task that commissioned this repository. tests/contract.rs reconciles
the code against it, so a route that exists in one and not the other fails the
gate.
GET /healthz
GET /api/v2/runs # list w/ session attribution
GET /api/v2/runs/{run} ?include_conversations=bool
GET /api/v2/runs/{run}/timeline ?scope=run|node&node=ID
GET /api/v2/runs/{run}/conversations/{id}
GET /api/v2/runs/{run}/artifacts/{id}
GET /api/v2/events # SSE; fresh snapshot per connection
GET /api/v2/projects # runs grouped by project, as `onepipeline runs` groups them
GET /api/v2/projects/{project}
GET /api/v2/runs/{run}/channel # the channel, consuming nothing
POST /api/v2/runs/{run}/channel/next # claim the next surface
POST /api/v2/runs/{run}/channel/reply # the envelope's bytes, verbatim; ?correlation=C
POST /api/v2/runs/{run}/channel/surface
POST /api/v2/runs/{run}/attest
POST /api/v2/runs/{run}/stop # as the session `--session` names
POST /api/v2/runs/{run}/adopt # retains this binary as the driver
POST /api/v2/runs/{run}/shutdown # `onepipeline shutdown RUN`; {grace?, force?}
POST /api/v2/shutdown # `--mine` or `--host`; {scope, grace?, force?}
GET /api/v2/runs/{run}/watch # SSE over `onepipeline watch`
GET /api/v2/unwatched
GET /api/v2/host
GET /api/v2/runs/{run}/status
GET /api/v2/runs/{run}/results
GET /api/v2/goals
GET /api/v2/runs/{run}/goals
GET /api/v2/runs/{run}/transcript ?node=ID
GET /api/v2/runs/{run}/telemetry
GET /api/v2/runs/{run}/agents # every oneharness session the run launched
GET /api/v2/runs/{run}/nodes/{node}/agents
GET /api/v2/projects/{project}/agents # the union over the project's runs
The first seven are the read surface the browser view was written against;
the rest are every verb the onepipeline CLI has once a plan is running,
wrapped — each a thin call into onepipeline::verbs, never a re-implementation
and never the binary. Launching a plan and driving the planning stage are
outside this API; a reply on any run's channel is inside it. The server acts as
one launching session (--session ID, else ONEPIPELINE_LAUNCHER_SESSION),
which is what its stops, adoptions and shutdowns are judged by.
Every successful response carries the schema-version preamble —
api_version, telemetry_schema_version (20), observed_at — with the payload
flattened alongside it. Every failure carries {"error": {"code", "message"}}.
Payloads themselves come from the onepipeline SDK. Anything presentation-worthy lands there first, so the agent reading the CLI sees at least what the human in the UI sees; this crate owns the envelope, not the records.
The view declares no schema, event name, or API path of its own —
packages/dag-model holds the contract's client half, packages/telemetry-client
is the only thing that speaks HTTP, and packages/dag-layout is the graph geometry.
Install
Two deliverables, split by what they contain.
The read API, as the same prebuilt binary on three registries:
cargo install onepipeline-ui --locked # from crates.io
pip install onepipeline-api-cli # prebuilt wheel, no Rust toolchain
npm install -g onepipeline-api-cli # prebuilt binary, no Rust toolchain
All three install one command, onepipeline-api:
onepipeline-api serve --runs-root ./runs # the read API
onepipeline-api serve --runs-root ./runs --ui # and the browser view, on the same address
--ui serves the DAG Observatory at / beside the API, with /api/v2/… and
/healthz unchanged and every path the bundle has no file for answered with
its index.html, so a deep link opens. The view is built into the binary
— the prebuilt wheels, npm packages and release archives all carry the bundle
of their own release — so a host that installed only the command needs no npm
package to open it. cargo install from crates.io compiles from source and
embeds the view only where apps/dag-ui/dist has been built beforehand; a
binary without one refuses --ui and says so. --ui-dist DIR serves a bundle
on disk instead, for developing the view against a real runs root.
The view is also published on its own, as a static bundle on npm:
npm install onepipeline-ui # the built frontend under dist/
That package installs no command — it is dist/, to be served statically or
handed to --ui-dist. It is the same bundle --ui serves.
Prebuilt archives and their .sha256 checksums are also attached to every
GitHub Release.
Develop
just bootstrap # from a clean clone; also activates the visual pre-push guard
just check # the deterministic gate, every project
just gate # `check` plus the llmlint LLM-judge tier — the pre-push bar
just dag-ui-screens # re-photograph every screen above, in the pinned browser container
just --list is the full command surface. AGENTS.md is the
durable instruction layer for humans and agents working here, and
apps/dag-ui-e2e/AGENTS.md is the note on the
screens: what they are, why the capture is byte-reproducible, and what to do when
the view legitimately changes.
License
MIT. See LICENSE.
Release files for onepipeline-api-cli 0.13.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| onepipeline_api_cli-0.13.0-py3-none-win_amd64.whl | Python 3 | none | Windows x86-64 | Details |
| onepipeline_api_cli-0.13.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | Python 3 | none | Linux glibc 2.17+ x86-64 | Details |
| onepipeline_api_cli-0.13.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | Python 3 | none | Linux glibc 2.17+ ARM64 | Details |
| onepipeline_api_cli-0.13.0-py3-none-macosx_11_0_arm64.whl | Python 3 | none | macOS 11.0+ ARM64 | Details |
| onepipeline_api_cli-0.13.0-py3-none-macosx_10_12_x86_64.whl | Python 3 | none | macOS 10.12+ x86-64 | Details |
Total release size: 59.4 MB
Release files / onepipeline_api_cli-0.13.0-py3-none-win_amd64.whl
| Download URL | onepipeline_api_cli-0.13.0-py3-none-win_amd64.whl |
|---|---|
| Size | 13.0 MB |
| Tags | Python 3 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
88a963d09fc47a42e9bcc94643ccf022ce32b198661d65aeee16fd34aed46df0
|
|
BLAKE2b-256 checksum How to use checksums |
0e78196fa2119ef5f5795fb10ad9d9a63f5dadbb0857fc544cddd5db74edb626
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / onepipeline_api_cli-0.13.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | onepipeline_api_cli-0.13.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 12.2 MB |
| Tags | Linux glibc 2.17+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
d61efaaa4af222dd2eaae72889c416205ca76df9aae2b337162c984ba258870f
|
|
BLAKE2b-256 checksum How to use checksums |
1fed3c96f4d71571ae41534cbb7699e2e41b86436c6a8dc08b890d52db1a6f84
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / onepipeline_api_cli-0.13.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | onepipeline_api_cli-0.13.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 11.3 MB |
| Tags | Linux glibc 2.17+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
80689bb7f30b33d91a9c827f0cdac4e76a452dd4bcefa93bbcdf1ce429a356e6
|
|
BLAKE2b-256 checksum How to use checksums |
fe889ebf4414b08c7f62096c3189150a84502ffebc2ad3d0530b657cf9490d0e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / onepipeline_api_cli-0.13.0-py3-none-macosx_11_0_arm64.whl
| Download URL | onepipeline_api_cli-0.13.0-py3-none-macosx_11_0_arm64.whl |
|---|---|
| Size | 11.1 MB |
| Tags | Python 3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
c9c8e87751b17538253353b8face2b10723a689d0aec2a61e1b76386f58383f6
|
|
BLAKE2b-256 checksum How to use checksums |
1eec8a07c17731ae6a55ea682111c6b4d58720fd150dd46edd8d63ab42409191
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / onepipeline_api_cli-0.13.0-py3-none-macosx_10_12_x86_64.whl
| Download URL | onepipeline_api_cli-0.13.0-py3-none-macosx_10_12_x86_64.whl |
|---|---|
| Size | 11.9 MB |
| Tags | Python 3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
a6a0ef63b67557055cac94bf40b812bc442df35a42f0111e5bb74a6db9ea17b6
|
|
BLAKE2b-256 checksum How to use checksums |
288636e8a1c95fb4978c4f70402330d26d82734941ce35fbd50b7b167fc9ddbf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|