opsview

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 3, 2026 License: Apache-2.0 Imports: 23 Imported by: 0

README

ops view

The ops view is the operator's live page of every harness session on this machine: one card per session, read from the run directory the harness keeps for it and updated the instant a line lands in its event log. It is the first live version of the view the Workbench will grow into; the name is provisional until the view term lands.

Run it

The harness binary hosts it as a second process, separate from harness serve so the view starts, stops and restarts without touching running sessions. It reads the same state directory serve writes.

harness view                                   # http://127.0.0.1:14121/ for development
harness view -listen 127.0.0.1:14121 -listen <tailnet address>:14121 -detach
harness view -stop                             # ends the one recorded in <state>/view.json

Port 14121 is the view's: the next port after the harness's own 14120. Each listen address is accepted as a browser Origin; -origin adds another. On a tailnet the operator opens http://<tailnet address>:14121/ on a phone; the page is a single column there and a grid on a wider screen. Nothing here adds a public route, a proxy or a firewall rule: binding the tailnet address is the whole of the exposure, and that address is a flag, never a file in this tree.

What a card shows

Every field comes from two files under <state>/<assignment id>/: run.json, the run record, and events.jsonl, the event log the harness and its turn executor append to.

Field Source
agent, assignment, branch, ticket, turns the run record
status: running, finished, failed, closed the harness's own records: a turn requested, a turn finished, a turn failed, the turn executor closed
model the first assistant message
tool calls every tool_use block in assistant messages
gate denials session gate decisions that denied
pull request the turn's receipt, or the executor's code_change_published
elapsed first record to last record, at minute resolution
recent events the last few of: tool calls, gate denials, the executor's own denials, the operator's messages, turn results, harness records; a card shows five and holds twenty, and "show earlier" is the one thing a browser may ask

Elapsed time is read from the log's own timestamps rather than a clock, so a render stays a pure function of state; a running session logs every few seconds, so the label is current to the minute.

How it stays live

The view is a service in the host app's web layer: it owns no listener and no process. harness view grants it two capabilities over the state directory, the file capability to read and the watch capability to be told of changes, and binds the listener.

Each browser connection is one live UI session with one follow effect. The effect reads every run directory once, then waits on the kernel's change notification: a write to a session's event log re-reads that log from where the last read stopped, folds the new lines into the session's card, and emits the card as an internal event addressed to the card's own region. The card is a widget in a keyed collection, so only that card's region is patched; the board re-renders only when a session appears or the order changes. There is no polling loop and no page refresh, and a browser cannot post a card of its own: the event is internal, never registered.

Proof

  • go test -race ./services/opsview/ runs the unit specs over real record shapes and the integration specs, which drive the page over the real wire with a gomock watcher: a card appears, only that card patches when a line lands, a run directory that appears later is adopted, and a failing watch is reported on the page.
  • The browser conformance spec, labelled browser, runs headless Chromium in the gotth-live bench image against a real listener, a real watch and a real file: the card's tool-call count moves from 1 to 3 on one appended line with no page reload.

Not done

Later slices: the fleet panel from Warden, the ouroboros ring, the heap, operator actions (accept and reject), the compounding chart.

Documentation

Overview

Package opsview is the ops view: a gotth-live page that shows every harness session on this machine as a live card, read from the run directories under the harness state directory. Each card is a widget SDK widget in a keyed collection; cards update the moment a line lands in a session's event log, because the page follows the files through the kernel's change notification rather than polling them.

It is a service: it owns no listener and no process. The harness host app grants it the file and watch capabilities over the state directory, mounts it into the host runtime and binds the listener.

Index

Constants

View Source
const (
	PagePath = "/"
	LivePath = "/live"

	// BoardRegion is the parent region every card lives in: the keyed
	// collection's region, so a card's region is BoardRegion:<assignment>.
	BoardRegion = "opsview.sessions"
)

Routes: the page and the live mount under it. The live handler serves its own runtime script beneath the mount.

View Source
const (
	KindTool    = "tool"
	KindGate    = "gate"
	KindHarness = "harness"
	KindResult  = "result"
	KindMessage = "message"
)

The kinds of recent event a card lists, which are also its CSS classes.

View Source
const (
	WidgetName = "SessionCard"
	// EventSession carries one whole card, as JSON in the card field. It is
	// internal: the follow effect emits it, and a browser may not, because a
	// browser posting one would be forging the event log's own truth.
	EventSession = "opsview.session"
	FieldCard    = "card"
	// EventExpand is the one event a browser may send: show or hide the rest
	// of a card's recent events. It reads nothing and changes no session.
	EventExpand = "opsview.expand"
)

The session widget's identity on the wire. Every card is one instance of this definition under the board's keyed collection, at region opsview.sessions:<assignment>; the board region is the collection's own.

Variables

View Source
var (
	// ErrNoFiles reports a view built without the file capability.
	ErrNoFiles = errors.New("ops view: the file capability over the state directory is required")
	// ErrNoWatcher reports a view built without the watch capability.
	ErrNoWatcher = errors.New("ops view: the watch capability over the state directory is required")
)

Functions

func CardEvent

func CardEvent(region string, card SessionCard) (live.Event, error)

CardEvent is the event the follow effect emits for one session, addressed to that session's own region so the collection routes it to the member.

func PageURL

func PageURL(base string) string

PageURL is the view's page under base, the host's address.

Types

type OpsView

type OpsView struct {
	// contains filtered or unexported fields
}

OpsView is the live application and its routes.

func NewOpsView

func NewOpsView(files ipcfs.IFiles, watcher ipcfs.IWatcher, origins []string, logger *slog.Logger) (*OpsView, error)

NewOpsView builds the view over the harness state directory: files reads it and watcher reports its changes. origins is the browser Origin allowlist, one per address the host serves; nothing else is accepted.

func (*OpsView) Register

func (view *OpsView) Register(router gin.IRouter)

Register mounts the page and the live routes on the caller's router.

func (*OpsView) Start

func (view *OpsView) Start(scope *runtime.Scope) error

Start starts the live application's connection scope.

type RecentEvent

type RecentEvent struct {
	Time string `json:"time"`
	Kind string `json:"kind"`
	Text string `json:"text"`
}

RecentEvent is one of the last few typed events a card shows.

type SessionCard

type SessionCard struct {
	Assignment     string    `json:"assignment"`
	Agent          string    `json:"agent"`
	Branch         string    `json:"branch"`
	TicketURL      string    `json:"ticket_url"`
	PullRequestURL string    `json:"pull_request_url"`
	Model          string    `json:"model"`
	Status         Status    `json:"status"`
	Turns          int       `json:"turns"`
	ToolCalls      int       `json:"tool_calls"`
	GateDenials    int       `json:"gate_denials"`
	StartedAt      time.Time `json:"started_at"`
	// LastAt is the follow effect's own bookkeeping for Elapsed and is not on
	// the wire: a line that moves nothing a card shows then moves nothing on
	// the page, and the executor logs such lines several times a second.
	LastAt  time.Time `json:"-"`
	Elapsed string    `json:"elapsed"`
	Error   string    `json:"error"`
	// Recent is the last few typed events, newest last. A card shows the
	// last recentShown of them until the browser asks for the rest.
	Recent []RecentEvent `json:"recent"`
	// Expanded is the one thing a browser decides: whether the card shows
	// every recent event it holds. It survives the card being replaced.
	Expanded bool `json:"expanded"`
}

SessionCard is everything the ops view shows about one harness session, derived from its run record and its event log and nothing else. It is the session widget's state: a pure projection, replaced whole whenever the follow effect reads more of the log.

func Fold

func Fold(card SessionCard, line []byte) (SessionCard, bool)

Fold applies one event log line to the card and reports whether it read a record. It is pure: equal cards and equal lines fold to equal cards.

type Status

type Status string

Status is where a session stands, read from its event log.

const (
	StatusRunning  Status = "running"
	StatusFinished Status = "finished"
	StatusFailed   Status = "failed"
	StatusClosed   Status = "closed"
)

The statuses a card shows. A session is running from its first turn request until the harness records the turn's end; a finished session keeps its turn executor open for the next message until the harness closes it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL