Skip to main content

onepipeline-ui

The DAG Observatory at desktop width: a dark three-column shell with the projects and runs rail on the left, a header of telemetry tiles over the selected run, and the graph timeline drawn underneath as a single collapsed line of coloured work segments across the run's clock

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

The Graph view: a directed graph of node cards laid out left to right on a dark canvas, edges joining them, each card headed by its node id and its state — green where a node succeeded, red where one failed, and an acid highlight around the one still running

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

The node view for a node named dashboard: a breadcrumb back to the graph, a legend of event categories, a collapsed timeline plot of that node's work across its own clock, and underneath it the node's transcript as a list of turn and event rows

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

A conversation open in the right panel: its heading naming the worker · judge session and reading still running, a plot of that session's own turns, then the turns themselves — a prompt, the model's reply, and a row of input, output, cache and cost readings under it

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

The project list the app opens on: a grid of cards, each naming a plan and its qualified id, how many runs it holds, their states counted, and when it last wrote — with a card headed "(no project)" among them for the runs whose launch recorded none

A single project's page: its name and id, then the DAGs launched against it as rows, most recent first, each carrying its settlement, its nodes counted, what is driving it and when it last wrote

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 Channel tab: the queue showing a waiting surface with its kind, its source, a blocking badge and its age, the replies written under it, and a reply composer with a free-text editor and the verdict shortcuts above it

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 same overall view at phone width: the two columns of the shell stacked into one, the run's telemetry tiles wrapped to fit, and the graph timeline still plotted whole across the narrow column

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)

Table of built distributions (wheels) for onepipeline-api-cli 0.13.0
File
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

Release history Release notifications | RSS feed

This release

0.13.0 This release

5 release files

0.12.1

5 release files

0.11.2

5 release files

0.11.1

5 release files

0.11.0

5 release files

0.10.1

5 release files

0.9.0

5 release files

0.8.0

5 release files

0.7.3

5 release files

0.7.2

5 release files

0.7.1

5 release files

0.7.0

5 release files

0.6.5

5 release files

0.6.4

5 release files

0.6.3

5 release files

0.6.2

5 release files

0.6.1

5 release files

0.6.0

5 release files

0.5.0

5 release files

0.4.0

5 release files

0.3.4

5 release files

0.3.3

5 release files

0.3.2

5 release files

0.3.1

5 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page