opsview

package
v0.4.0 Latest Latest
Warning

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

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

README

ops view, the Workbench control plane

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. Granted the CSF service's operations it is the Workbench control plane: the same page, now able to act on every session it shows. It stands beside the Copilot-era Workbench Kanban and does not replace it.

Run it

csf serve mounts the page at / on its own listen addresses, beside the generated operations under /api/harness/ and at /mcp, so the page, the CLI and every MCP client reach one process:

csf serve -listen 127.0.0.1:14120 -workbench-recipes <directory of recipe templates>
csf serve -listen 127.0.0.1:14120 -listen <tailnet address>:14120 -detach

Each listen address is accepted as a browser Origin; -origin adds another. On a tailnet the operator opens http://<tailnet address>:14120/ 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.

Every address csf serve has served is in the endpoint registry, and csf serve refuses to start without serving each one that has no retirement record. An old address keeps working as a redirect alias: -redirect 127.0.0.1:14121 answers every request there with a permanent redirect to the same path on the first listen address's port. The page's endpoints panel lists every endpoint at each address, how it is served and who uses it, and every retired address with where it moved. Only the operator retires an address:

csf endpoint retire -address 127.0.0.1:14121 -moved-to 127.0.0.1:14120 -acknowledgement '<the operator's words>'

What the operator can do

Every action is one generated operation of the CSF service: the page calls it in process, csf <verb> calls it over HTTP, and an agent calls it as the MCP tool of the same name at /mcp. No action exists only in the page.

  • Send a message from the card's composer: SendAgentSessionMessage with operator_authored set, so the harness vets the operator's terms and the reply gate holds the reply to them (csf send -operator).
  • Cancel: CancelAgentSession (csf cancel).
  • Mark the pull request ready: ReadyAgentSessionPullRequest (csf ready).
  • Merge it: MergeAgentSessionPullRequest (csf merge), which runs the worktree's tools/merge-pr.sh when there is one, so an operator merge takes the same merge path as every other, and gh's squash merge otherwise. It waits for the path's checks, so the card says "Merging" for minutes; the page must stay open until it reports. Agent self-merge rules are unchanged.
  • Open the pull request and the ticket from the card's links.
  • Launch a session: pick a ticket URL and a recipe template, see the admission check (CheckAgentSessionAdmission, csf check), then launch exactly the recipe that was checked (SubmitAgentSession, csf submit).

The harness records every one of these in the session's events.jsonl as a typed harness_control_action record with its action (submit, send, cancel, ready or merge), operator_authored and turn_id for a send, the pull request for ready and merge, and level ERROR with the error when the operation was refused. The card lists them among its recent events, whoever the client was.

A template is a directory under -workbench-recipes holding agent.json and the brief it names: the format csf submit reads. The launch form fills the ticket URL, a fresh assignment identifier and a branch of the template's own with the assignment's first eight characters appended.

The host panel

At the top of the page, below the strip, the host panel shows what runs on the machine and controls it. CSF knows no repository's services here: it reads the host's containers through the container capability and the profiles the operator defines.

  • The gauges: one-minute load against cores, free memory, and free disk on the state directory's filesystem.
  • Every container: name, image, Compose project, state, cpu and memory. Containers are grouped as CSF work or everything else. A container is CSF work when the harness's records claim it: it carries a session container's csf.assignment label naming a run directory, or it mounts a path inside one, which is how a session's build containers are found. Stopped containers are folded away under each group.
  • Start, stop, pause and unpause, per container and per group, and a protect mark per container. A protected container is never stopped or paused by anything on the panel.
  • The profiles, each a host profile. The page starts with "only CSF work", which stops everything that is not CSF work; the operator adds others, such as "essentials", a named set to keep running, from the editor under the profiles. Applying one shows its diff before one confirm. The last applied profile is undone in one tap.
  • The load guard: when the load passes 1.5 times the cores, the panel says so and offers "only CSF work" and a hold on new sessions (the slice dispatcher's pause). It never acts on its own.

Every button on the panel is a verified action. Its operation is dry-run against the live host when the panel is first drawn and again on every refresh, five seconds apart. A button whose check fails is drawn disabled with the reason. A stop, a pause, a profile, an undo, or a change to more than one container lists the containers it changes and asks for one confirm. The operation plans again at the press and refuses if the host moved since the diff was shown. After acting, it reads the host back and fails unless each container reached the state its action leaves.

Each control is one typed operation, served over HTTP under /api/host/ and as the MCP tool of the same name at /mcp: get_host, control_containers, apply_host_profile, undo_host_profile, put_host_profile and protect_containers. Each change takes dry_run, and its confirm names exactly what the dry run listed. The container capability the panel is granted has no remove and no volume call, so nothing here can remove a container or touch a volume.

Two files under the state directory hold the operator's records: host.json, the profiles and protected names, and host.jsonl, one line per applied profile or undo with exactly the changes made. A profile that changed nothing is not recorded, so it never stands between the operator and the undo of one that did.

The first screen

Phone-first, top to bottom: a strip with the running sessions, the merges the control plane made today and the session spend today, with the fixers' spend against the mining loop's daily cap beside it; the launch form; the cards, running sessions first; the loop panel; the miners panel; and the dispatch queue. Today is the newest UTC day the page has read anything for, so the strip needs no clock. A session's spend is folded from its result records the way the loop folds a fixer's cost.

The dispatch queue panel reads dispatch.json under the state directory, the snapshot the slice dispatcher in services/dispatch writes on every pass: running slices, then the queue in dispatch order with why each one waits, then the held ones, with the capacity and whether the dispatcher is paused. Until that file exists the panel says so.

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, waiting, finished, suspended, failed, closed the harness's own records: a turn requested, a turn finished, the session suspended, a turn failed, the turn executor closed; waiting is a finished turn with background tasks running
resumes the session resumed after a suspend; the resumed turn's record names its time to first token
background the executor's latest background_tasks_changed; background results
model the first assistant message
executor the run record; Claude Code for a run recorded without one
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

A waiting session is not stranded. Its turn has ended, but the executor still runs background tasks, and the completion of each one starts a turn with no Send. The harness records that turn as a background result and counts it. The card shows how many tasks are running and how many turns they woke.

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.

What the resident panel shows

Above the miners, one panel for what the harness holds in memory: the harness's own resident set and the resident set of its executors and everything they started, the open sessions, the executors alive, how many sessions were resumed after a suspend, the latest resumed turn's time to first token, and the derived idle bound with the quantile it sits at. The source is resident.jsonl at the root of the state directory, which the harness samples once a minute from the process table it is granted and rewrites with the last day of samples. The panel follows the file the way the miners panel follows its series. Until a sample exists the panel is empty.

What the miners panel shows

Above the cards, one row per Ouroboros miner: its latest mutation score and every earlier one, as a series. The source is one file at the root of the state directory, mutation.jsonl, one record per line (Mutation in services/ouroboros/contract/records.proto). A miner's mutate --json verb prints the record; whoever runs it appends the line:

bazel-bin/services/ouroboros/miners/_template/miner.exe mutate --json \
  services/ouroboros/miners/_template/fixtures/labels.tsv \
  'services/ouroboros/miners/_template/fixtures/*/events.jsonl' >> <state>/mutation.jsonl

A point reads killed/counted = score, green when the gate accepted the miner and red when it rejected it; a rejected point lists the surviving mutants. The panel follows the file the way the cards follow their logs: a write re-reads it and patches the panel alone. Until a record exists the panel is empty.

The labeler panel

Above the board, one panel shows the labeler's run record, <state>/labeler.json, which the harness binary's label verb replaces after every batch: the model, the phase (labeling, yielding or finished), the ticket in hand, how many tickets were labeled and how many gained a real instance, the labels proposed, accepted and rejected, the precision of the proposed positives under the acceptance rule, labels per hour, the GPU's utilization and memory, the keep-alive the last request carried with the two measurements it derives from, and how often the labeler yielded the GPU. The panel is its own fragment, so a replaced record patches the panel and nothing else, and a machine with no record shows the panel saying so.

How it stays live

The view is a service in the host app's web layer: it owns no listener and no process. csf serve grants it two capabilities over the state directory, the file capability to read and the watch capability to be told of changes, the CSF service's operations and the template directory, 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, a failing watch is reported on the page, a mutation record landing patches the miners panel alone, and a replaced labeler record patches the labeler panel alone.
  • 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.
  • The host specs drive the host operations over a gomock Engine holding a table of containers. CSF work is grouped by label and by mount. "only CSF work" applies only after the exact confirm and is undone from the ledger. A protected container refuses to stop and its button is drawn disabled with the reason. A confirm made before the host moved is refused. A satisfied profile is a no-op that records nothing. A change the Engine accepted but did not make fails the acceptance check.
  • The host phone spec, labelled browser, applies "only CSF work" on a 390x844 phone: the diff, the confirm, the containers stopping, then one tap to undo and the containers starting, with no page reload.
  • The live run, the opt-in acceptance suite in host_acceptance_test.go, points the panel at the machine's own Engine, process table and state directory. It applies the operator's "essentials" while the host already satisfies them. It passes no confirm, so a host that did not satisfy them would be refused, never changed.

The loop panel

Above the cards sits the mining loop's panel: the struggle rate of the week with its interval, the compounding rate per week with its interval and the weeks it was fitted on beside the baseline to beat, the per-day early read, the internal check's exponent with its week table, the miners, generic or tenant, the findings, the fixers with their spend against the daily budget and the cost of a ready pull request, the merge train's record, the labeler's queue, one row per miner and the last fourteen days. It is read from ouroboros.json, the snapshot services/ouroboros writes into the state directory on every measure, and follows that file through the same watch the cards use; a state directory with no snapshot shows the panel empty.

Installed widgets

Between the panels and the cards sits every widget installed from the widgets directory of the checkout csf serve runs from (-widgets DIR names another), drawn over the loop's snapshot. The page watches that directory and each definition in it through the watch capability: a definition that lands is checked and drawn with no restart, one that is removed disappears, and one that fails the check is shown refused with every reason and never drawn. widgets/README.md is the format and the checks; operations.go serves list_widgets, check_widget and propose_widget, which csf serve exposes over MCP, and recipe/ is the template an agent session makes a widget from.

Not done

Later slices: the fleet panel from Warden, the heap, accepting and rejecting a miner from the page, the compounding chart over the series, and a ticket picker that lists open tickets instead of taking a URL.

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 (
	// CertificateRegion is the panel's region.
	CertificateRegion = "opsview.certificate"
	// EventCertificate carries the certificate, as its JSON, in the
	// certificate field. It is internal: the follow effect emits it, and a
	// browser may not.
	EventCertificate = "opsview.certificate"
	// FieldCertificate is the field EventCertificate carries the JSON in.
	FieldCertificate = "certificate"
)

The certificate panel: the choice-verification certificate a bootstrap archive carries (csf/prod/certificate), read from certificate.json under the state directory. It shows why the bootstrap's choices are right — the options it induced and the picks it made — one row per check, every threshold read from the data rather than typed in.

View Source
const (
	EventSend   = "opsview.send"
	EventCancel = "opsview.cancel"
	EventReady  = "opsview.ready"
	EventMerge  = "opsview.merge"
	// FieldExecutor and FieldModel are the default executor form's fields.
	FieldExecutor = "executor"
	FieldModel    = "model"
	// EventExecutor switches the default executor and model, from the launch
	// panel; EventExecutorSet reports the switch back.
	EventExecutor    = "opsview.executor"
	EventExecutorSet = "opsview.executor-set"
	// EventActed carries an action's outcome back to its card, in FieldNotice.
	EventActed   = "opsview.acted"
	FieldMessage = "message"
	FieldNotice  = "notice"

	// EventCheck is the launch form's submission: FieldTicket and
	// FieldTemplate. Its effect prepares the recipe and runs the admission
	// check; EventLaunch submits the recipe that was checked.
	EventCheck    = "opsview.check"
	EventLaunch   = "opsview.launch"
	EventChecked  = "opsview.checked"
	EventLaunched = "opsview.launched"
	EventRefused  = "opsview.refused"
	// EventTemplates lists the recipe templates, one name per line.
	EventTemplates = "opsview.templates"
	FieldTicket    = "ticket"
	FieldTemplate  = "template"
	FieldRecipe    = "recipe"
	FieldCheck     = "check"
	FieldHeld      = "held"
	FieldTemplates = "templates"
	FieldAssigned  = "assignment"

	// RecipeFile and the brief it may name are a template's files, under
	// <templates>/<name>/: the agent.json + brief.md format csf submit reads.
	RecipeFile = "agent.json"
)

The control events on the wire. A card's actions and the launch form are browser events; what their effects report back is internal.

View Source
const (
	CostsRegion = "opsview.costs"
	// EventCosts carries the report, as its JSON, in the report field. It is
	// internal: the follow effect emits it, and a browser may not.
	EventCosts  = "opsview.costs"
	FieldReport = "report"
)

The cost panel: the session operations' cost model, fed by the report the costs verb replaces under the state directory (services/harness/costs, ReportFile).

View Source
const (

	// The kernel's pressure stall information, one file per resource under
	// pressureDirectory; the gauges read the share of the last 10 s some task
	// waited on it.
	PressureCPU    = "cpu"
	PressureMemory = "memory"
	PressureIO     = "io"
)

The kernel files the gauges read from the process table, and the load guard. The guard's factor is the operator's (#360): a run queue half again longer than the cores is when the panel offers to shed work.

View Source
const (
	GetHostOperation           = "get_host"
	ControlContainersOperation = "control_containers"
	ApplyHostProfileOperation  = "apply_host_profile"
	UndoHostProfileOperation   = "undo_host_profile"
	PutHostProfileOperation    = "put_host_profile"
	ProtectContainersOperation = "protect_containers"

	// HostSettingsFile holds the operator's host profiles and protected
	// containers, under the state directory.
	HostSettingsFile = "host.json"
	// HostLedgerFile is every applied profile and undo, one record per line.
	HostLedgerFile = "host.jsonl"
	// OnlyCSFWork is the profile every host starts with: stop everything that
	// is not CSF work.
	OnlyCSFWork = "only CSF work"
)

The host operations: what runs on the machine, and the operator's controls over it. Each is one typed operation, served over HTTP here and over MCP by the host app, and the Workbench's host panel is a client of the same calls.

View Source
const (
	HostRegion = "opsview.host"
	// EventHost carries the panel, as JSON, in FieldHost. It is internal.
	EventHost = "opsview.host"
	// EventHostDone carries a press's outcome in FieldNotice. It is internal.
	EventHostDone = "opsview.host.done"
	// EventHostPress is a verified button: FieldAction names it.
	EventHostPress = "opsview.host.press"
	// EventHostConfirm runs the action awaiting its confirm, FieldAction.
	EventHostConfirm = "opsview.host.confirm"
	// EventHostDismiss closes the confirm without acting.
	EventHostDismiss = "opsview.host.dismiss"
	// EventHostProfile is the profile editor's submission.
	EventHostProfile = "opsview.host.profile"

	FieldHost        = "host"
	FieldAction      = "action"
	FieldProfileName = "name"
	FieldProfileKeep = "keep"
	FieldKeepCSF     = "keep_csf_work"
	FieldStopOthers  = "stop_others"
	FieldRemove      = "remove"
)

The host panel's identity on the wire: one fragment at the top of the Workbench, fed by an effect that reads the host and verifies every button.

View Source
const (
	JevRegion = "opsview.jev"
	// EventJev carries the record, as its JSON, in FieldLedger. It is
	// internal: the follow effect emits it, and a browser may not.
	EventJev = "opsview.jev"
)

The JEV panel: the local decision model's runs, as `csf decide --ledger` records them. It follows the record replaced whole under the state directory (jev.DecideLedgerFile), and shows the day's decisions and tokens, the two numbers the ask names.

View Source
const (
	LabelerRegion = "opsview.labeler"
	// EventLabeler carries the run record, as its JSON, in the run field. It
	// is internal: the follow effect emits it, and a browser may not.
	EventLabeler = "opsview.labeler"
	FieldRun     = "run"
)

The labeler panel's identity on the wire: one fragment above the board, fed by the run record the ouroboros labeler replaces under the state directory (services/ouroboros/labeler, RunFile).

View Source
const (
	// MutationFile is the series file, one record per line, newest last.
	MutationFile = "mutation.jsonl"
	// MinersRegion is the panel's region.
	MinersRegion = "opsview.miners"
	// EventMutation carries the whole series, as JSON in the series field. It
	// is internal: the follow effect emits it and a browser may not.
	EventMutation = "opsview.mutation"
	FieldSeries   = "series"
)

The miners panel: every ouroboros miner's mutation score as a series, read from one file at the root of the state directory. A miner's mutate verb prints the record (Mutation in services/ouroboros/contract/records.proto) as one JSON line, and whoever runs it appends the line:

miner.exe mutate --json LABELS ITEM... >> <state>/mutation.jsonl
View Source
const (
	// The operations' names, which are also their MCP tool names.
	ListWidgetsOperation   = "list_widgets"
	CheckWidgetOperation   = "check_widget"
	ProposeWidgetOperation = "propose_widget"

	// WidgetsDirectory is where definitions live in a checkout.
	WidgetsDirectory = "widgets"
)

The widget operations: how an agent makes a widget for CSF. It lists the Workbench's widgets, checks a definition with the same check the Workbench runs before installing one, and proposes a checked definition from its harness session's worktree, which commits it there and opens the session's pull request through the harness. Each is one typed operation, served over HTTP here and over MCP by the host app.

View Source
const (
	CloudRegion = "opsview.cloud"
	// EventCloud carries the record, as JSON in FieldLedger. It is internal:
	// the follow effect emits it, and a browser may not.
	EventCloud = "opsview.cloud"
	// EventCloudStop is a row's Stop: the job in FieldJob.
	EventCloudStop = "opsview.cloud.stop"
	// EventCloudStopped carries a Stop's outcome back, in FieldNotice.
	EventCloudStopped = "opsview.cloud.stopped"
	FieldLedger       = "ledger"
	FieldJob          = "job"
)

The Cloud panel: every paid cloud job CSF launched, phone-first. Totals at the top (the day's spend against the day's cap, jobs running), one row per job with its Stop, and the latest notices. It follows the record the cloud service replaces under the state directory (cloud.LedgerFile), and its Stop is the service's own: cancel at the provider, then the provider's job list read back.

View Source
const (
	// DreamerRegion is the dreamer's panel: its state, its strategy with the
	// held-out comparison, and its decision records.
	DreamerRegion = "opsview.dreamer"
	// DreamerFile is the snapshot the dreamer projects into the state
	// directory.
	DreamerFile = dreamer.SnapshotFile
	// EventDreamer carries the snapshot as JSON in FieldDreamer. Internal.
	EventDreamer = "opsview.dreamer"
	FieldDreamer = "dreamer"
	// EventControl is a queue or dreamer button: FieldAction names the
	// verified action it runs.
	EventControl = "opsview.control"
	// EventControlled carries the control's outcome in FieldNotice. Internal.
	EventControlled = "opsview.controlled"
)

The dreamer panel and the queue's controls on the wire.

View Source
const (
	GitHubRegion = "opsview.github"
	// EventGitHub carries the panel, as JSON in FieldPanel. It is internal:
	// the follow effect emits it, and a browser may not.
	EventGitHub = "opsview.github"
	FieldPanel  = "panel"
)

The GitHub panel: what CSF heard from GitHub. The latest typed events with where each was routed, the deliveries refused or failed, and, when a csf release was published after this host started, the notice that csf upgrade installs it. It follows the GitHub event stream, the events.jsonl of the run directory intake.StreamAssignment.

View Source
const (
	// GoldenRegion is the panel's region.
	GoldenRegion = "opsview.golden_metrics"
	// EventGolden carries the gate's verdict, as its JSON, in the
	// golden_metrics field. It is internal: the follow effect emits it, and a
	// browser may not.
	EventGolden = "opsview.golden_metrics"
	// FieldGolden is the field EventGolden carries the JSON in.
	FieldGolden = "golden_metrics"
)

The golden metrics panel: the merge quality gate's verdict (csf/prod), read from golden_metrics.json under the state directory. The operator's ruling made the code metrics the quality gate — the seed files, the seed breaks, the chief violations per item, and the derived share, each compared between main and the merge result — so the panel shows the four numbers on each side and whether the gate refused the merge.

View Source
const (
	// LineRegion is the line panel's region.
	LineRegion = "opsview.line"
	// StagePR and StageLive are the board's two stages past the
	// dispatcher's: a running slice whose session opened its pull request,
	// and a merged slice the build serving this page contains.
	StagePR   dispatch.Stage = "pr"
	StageLive dispatch.Stage = "live"
)

The line panel: the value stream as a board, the slice graph, the workers against capacity and the mining loop as a ring, one region drawn from the state the page already holds.

View Source
const (
	// EventLoop carries the panel as JSON in FieldLoop. Internal: the follow
	// effect emits it, a browser may not.
	EventLoop = "opsview.loop"
	FieldLoop = "loop"
	// LoopFile is the snapshot the loop writes, under the state directory.
	LoopFile = ouroboros.SnapshotFile
)

The loop panel on the wire: one internal event carrying the panel whole, read from the snapshot the mining loop projects into the state directory.

View Source
const (
	// EventRefreshMerges asks for the merges on main to be read again: when
	// the page connects, and whenever a session ends a turn, closes or has its
	// pull request merged, which is when a merge can have happened.
	EventRefreshMerges = "opsview.refresh_merges"
	// EventMerges carries the pull requests merged into main today, as JSON
	// in FieldMerges.
	EventMerges = "opsview.merges"
	FieldMerges = "merges"
	// EventToday carries the UTC day by the view's clock, in FieldDay.
	EventToday = "opsview.today"
	FieldDay   = "day"
)

The merges tile and list on the wire. Both are internal events: the follow effect asks for a refresh, and the refresh effect delivers what the forge reports.

View Source
const (
	// EventPulls carries the sessions' open pull requests' diff stat and
	// checks, as JSON in FieldPulls.
	EventPulls = "opsview.pulls"
	FieldPulls = "pulls"
)

The open pull requests on the wire, and what gh is asked for them.

View Source
const (
	ChecksPassing = "passing"
	ChecksFailing = "failing"
	ChecksPending = "pending"
)

The checks of a pull request, rolled up as a row shows them.

View Source
const (
	// QueueRegion is the dispatch queue's panel.
	QueueRegion = "opsview.queue"
	// QueueFile is the snapshot the slice dispatcher projects into the state
	// directory. The panel is empty until the file exists.
	QueueFile = dispatch.SnapshotFile
	// EventQueue carries the snapshot as JSON in FieldQueue, empty for none.
	// Internal.
	EventQueue = "opsview.queue"
	FieldQueue = "queue"
	// SummaryRegion is the first screen's tiles: running sessions against
	// capacity, merges on main today and spend today against the cap.
	SummaryRegion = "opsview.summary"
)

The dispatch queue panel and the summary strip on the wire.

View Source
const (
	// EventRefreshSessions asks the session service for its sessions again.
	EventRefreshSessions = "opsview.refresh_sessions"
	// EventSessionCounts carries the counts, as JSON in FieldCounts.
	EventSessionCounts = "opsview.session_counts"
	FieldCounts        = "counts"
	// EventLoaded marks the follow effect's first pass done. Internal.
	EventLoaded = "opsview.loaded"
)

The sessions tile on the wire. Both events are internal: the follow effect asks for a count whenever a session's status moves, and the count effect delivers what the session service reports.

View Source
const (
	// EventInternals shows or hides a card's internals and raw activity.
	EventInternals = "opsview.internals"
	// EventCompose opens or closes a card's composer.
	EventCompose = "opsview.compose"
	// EventConfirm asks a card to confirm FieldAction (the host panel's
	// field), or, empty, to stop
	// asking.
	EventConfirm = "opsview.confirm"
	// EventOthers opens or folds the idle and finished list.
	EventOthers = "opsview.others"
	// EventFilter narrows that list to sessions whose name, branch, ticket or
	// activity contain FieldFilter, and to the status in FieldShow.
	EventFilter = "opsview.filter"
	FieldFilter = "filter"
	FieldShow   = "show"
	// EventSection unfolds or folds the section FieldSection.
	EventSection = "opsview.section"
	FieldSection = "section"
	// EventDefine shows a tile's definition, FieldTile, or hides it when it is
	// already showing.
	EventDefine = "opsview.define"
	FieldTile   = "tile"
)

The view events a browser sends. Each changes only the viewer's view.

View Source
const (
	// WidgetsRegion is the installed widgets' panel.
	WidgetsRegion = "opsview.widgets"
	// EventWidgets carries every definition's files, as JSON in FieldWidgets.
	// It is internal: the widgets effect emits it and a browser may not, since
	// a browser posting one would be installing a widget.
	EventWidgets = "opsview.widgets"
	FieldWidgets = "widgets"
)

Installed widgets: every definition directory in the widgets directory of the checkout the Workbench runs from, checked and drawn the moment it lands and gone the moment it is removed, with no restart. A definition is data (pkg/widget's definition files), so installing one loads no code.

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"
	// LoopRegion is the mining loop's panel: the compounding number and the
	// loop's yields, read from the snapshot the loop projects into the state
	// directory.
	LoopRegion = "opsview.loop"
	// LaunchRegion is the launch form: a ticket and a recipe template in, the
	// admission check shown, then the launch.
	LaunchRegion = "opsview.launch"
)

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

View Source
const (
	// ResidentRegion is the panel's region.
	ResidentRegion = "opsview.resident"
	// EventResident carries the whole series, as JSON in the series field. It
	// is internal: the follow effect emits it and a browser may not.
	EventResident = "opsview.resident"
)

The resident panel: what the harness and its executors hold in memory, how many sessions are open and how many executors are alive, the executors resumed after a suspend and the latest resumed turn's time to first token. The harness samples the series into one file at the root of the state directory (harness.ResidentFile) and the panel follows it the way the miners panel follows the mutation series.

View Source
const (
	// RulingsRegion is the panel's region.
	RulingsRegion = "opsview.rulings"
	// EventRulings carries the ruling records as the file holds them, in the
	// rulings field. It is internal: the follow effect emits it and a browser
	// may not.
	EventRulings = "opsview.rulings"
	// FieldRulings is the field the ruling records travel in.
	FieldRulings = "rulings"
)

The rulings panel: every operator ruling in force, with the gate that enforces it or the UNENFORCED flag, and how many a gate enforces. The harness keeps the ruling records in one file at the root of the state directory (session.RulingsFile) and the panel follows it the way the resident panel follows its series.

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.

View Source
const ChatPathPrefix = "/chat/"

ChatPathPrefix is where csf serve mounts a session's chat: the prefix followed by the assignment. The chat service names its route from it, and every Workbench card links there.

View Source
const CloudConstraint = "" /* 270-byte string literal not displayed */

CloudConstraint is said on the panel, beside the totals: where the limit a cloud session runs into comes from.

View Source
const (
	EndpointsRegion = "opsview.endpoints"
)

EndpointsRegion is the endpoints panel: every operator-facing endpoint of the endpoint registry at each of its addresses, and every retired address with where it moved, so the operator has one page that says where everything is.

View Source
const ViewerCookie = "csf_workbench_viewer"

ViewerCookie names the browser session cookie that tells one viewer's view from another's. It carries a random identifier and nothing else; it ends when the browser session does.

Variables

View Source
var (
	// ErrBriefConflict reports a template with both an inline task and a brief.
	ErrBriefConflict = errors.New("ops view: the template sets both task and workspace.brief_path; keep one")
	// ErrBriefOutside reports a template whose brief is not beside it.
	ErrBriefOutside = errors.New("ops view: a template's brief must be a relative path inside its directory")
	// ErrNoOperations reports an option given a nil control plane.
	ErrNoOperations = errors.New("ops view: the operations are required")
	// ErrNoTemplates reports an option given a nil template capability.
	ErrNoTemplates = errors.New("ops view: the template capability is required")
)
View Source
var (
	// ErrUnconfirmed reports a change that takes something away, or changes
	// more than one container, without the confirm naming exactly what it
	// changes on the host now.
	ErrUnconfirmed = errors.New("confirm by naming exactly the containers it changes")
	// ErrNoProfile reports a profile name the settings do not hold.
	ErrNoProfile = errors.New("no host profile has that name")
	// ErrNothingToUndo reports an undo with no applied profile left to undo.
	ErrNothingToUndo = errors.New("no applied profile is left to undo")
	// ErrInvalidProfile reports a profile record that cannot be kept.
	ErrInvalidProfile = errors.New("a host profile needs a one-line name of at most 64 characters, and container names that are not empty")
	// ErrAcceptance reports a change the host did not end up in.
	ErrAcceptance = errors.New("acceptance check failed")
)
View Source
var (
	// ErrNoDefinitions reports operations built without the Workbench's
	// widgets directory.
	ErrNoDefinitions = errors.New("widget operations: the widgets directory is required")
	// ErrInvalidWidgetName reports a widget name that is not a directory name
	// of the widgets directory.
	ErrInvalidWidgetName = errors.New("widget operations: a widget name is lower-case letters, digits and hyphens")
	// ErrInvalidAssignment reports an assignment identifier that is not one
	// run directory's name.
	ErrInvalidAssignment = errors.New("widget operations: not an assignment identifier")
	// ErrNoSessions reports a session-scoped operation on operations granted
	// no harness state directory or no launcher.
	ErrNoSessions = errors.New("widget operations: proposing needs the harness state directory and the launcher")
	// ErrNoNeed reports a proposal that does not say what the widget shows.
	ErrNoNeed = errors.New("widget operations: say what the widget shows in need")
)
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")
)
View Source
var ErrNoClock = errors.New("ops view: the clock is required")

ErrNoClock reports WithClock given no clock.

View Source
var ErrNoDefinitionWatcher = errors.New("ops view: widget definitions need both the file and the watch capability over the widgets directory")

ErrNoDefinitionWatcher reports widget definitions granted without their watch capability.

View Source
var ErrNoHostContainers = errors.New("host operations: the container capability is required")

ErrNoHostContainers reports host operations built without the container capability.

View Source
var ErrNoLauncher = errors.New("ops view: the process capability is required to read merges")

ErrNoLauncher reports WithGitHub given no process capability.

View Source
var ErrProtected = errors.New("protected by the operator")

ErrProtected reports a change to a container the operator protected.

View Source
var HostGroups = []HostGroup{GroupCSF, GroupOther}

HostGroups are the groups in the order the panel shows them.

View Source
var PressureResources = []string{PressureCPU, PressureMemory, PressureIO}

PressureResources are the resources the pressure gauges read, in the order the panel shows them.

Functions

func Activity added in v0.3.0

func Activity(tool string, raw json.RawMessage, worktree string) string

Activity is the sentence a card shows for one tool call: what the session is doing, in words, never the raw command. Paths are relative to the worktree and a home directory is never shown.

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 CertificateEvent added in v0.3.0

func CertificateEvent(content []byte) live.Event

CertificateEvent is the event the follow effect emits when the certificate changed, addressed to the panel's own region.

func CloudEvent added in v0.3.0

func CloudEvent(record []byte) live.Event

CloudEvent is the event the follow effect emits when the record changed.

func CostsEvent added in v0.3.0

func CostsEvent(report []byte) live.Event

CostsEvent is the event the follow effect emits when the report changed, addressed to the panel's own region.

func DreamerEvent added in v0.3.0

func DreamerEvent(snapshot *dreamer.Snapshot) (live.Event, error)

DreamerEvent is the event the follow effect emits when the dreamer's snapshot changes; nil is no snapshot.

func GitHubEvent added in v0.3.0

func GitHubEvent(panel GitHubPanel) (live.Event, error)

GitHubEvent is the event the follow effect emits when the stream grew.

func GoldenEvent added in v0.3.0

func GoldenEvent(content []byte) live.Event

GoldenEvent is the event the follow effect emits when the gate's verdict changed, addressed to the panel's own region.

func HostEvent added in v0.3.0

func HostEvent(panel HostPanel) (live.Event, error)

HostEvent is the event the effect emits with a fresh panel.

func HumanError added in v0.3.0

func HumanError(raw string, worktree string) string

HumanError is a failure as a card says it: what happened, in a sentence, with the turn it happened on. The raw text stays behind the card's details.

func JevEvent added in v0.3.0

func JevEvent(record []byte) live.Event

JevEvent is the event the follow effect emits when the record changed, addressed to the panel's own region.

func LabelerEvent added in v0.3.0

func LabelerEvent(record []byte) live.Event

LabelerEvent is the event the follow effect emits when the run record changed, addressed to the panel's own region.

func ListTemplates added in v0.3.0

func ListTemplates(templates stdfs.FS) ([]string, error)

ListTemplates names every directory under templates that holds a recipe.

func LoopEvent added in v0.3.0

func LoopEvent(panel LoopPanel) (live.Event, error)

LoopEvent is the event the follow effect emits when the loop's snapshot changes.

func PageURL

func PageURL(base string) string

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

func PressureSomeAvg10 added in v0.3.0

func PressureSomeAvg10(processes iofs.IFiles, resource string) float64

PressureSomeAvg10 reads the "some avg10=" field of one resource's /proc/pressure file from the process table, as a percent, or -1 when the kernel reports no pressure information for it.

func QueueEvent added in v0.3.0

func QueueEvent(snapshot *dispatch.Snapshot) (live.Event, error)

QueueEvent is the event the follow effect emits when the queue snapshot changes; nil is no snapshot.

func RawActivity added in v0.3.0

func RawActivity(tool string, raw json.RawMessage, worktree string) string

RawActivity is the call as the executor sent it, for the raw view: the tool and the first line of its input's leading field, home paths removed.

func RecipeFromTemplate added in v0.3.0

func RecipeFromTemplate(templates stdfs.FS, name string, ticket string, assignment string) (*pb.AgentAssignmentRecipe, error)

RecipeFromTemplate reads the template <name>/agent.json, and the brief it names, from templates, and makes it this ticket's recipe: the ticket URL, the assignment identifier, and a work branch of the template's own with the assignment's first characters appended, so two launches from one template never share a branch.

func ResidentEvent added in v0.3.0

func ResidentEvent(samples []harness.ResidentSample) (live.Event, error)

ResidentEvent is the event the follow effect emits when the series file changed, addressed to the panel.

func RulingsEvent added in v0.3.0

func RulingsEvent(content []byte) live.Event

RulingsEvent is the event the follow effect emits when the ruling records changed, addressed to the panel.

func Scrub added in v0.3.0

func Scrub(text string, worktree string) string

Scrub removes the worktree, scratch directories and any home directory from text: what every line the Workbench shows of a session goes through.

func SeriesEvent added in v0.3.0

func SeriesEvent(series []MinerSeries) (live.Event, error)

SeriesEvent is the event the follow effect emits when the series file changed, addressed to the panel.

func Stylesheet added in v0.3.0

func Stylesheet() string

Stylesheet is the Workbench's token set and stylesheet, for the other pages CSF serves beside it — the harness chat — so they share one design system.

func Target added in v0.3.0

func Target(tool string, raw json.RawMessage, worktree string) string

Target is what one tool call acts on, for a transcript's tool row: the file, the command line's first line, the pattern or the address, relative to the worktree with home directories removed, on one bounded line.

func TodayEvent added in v0.3.0

func TodayEvent(day string) live.Event

TodayEvent tells the page which UTC day is today.

func WidgetSources added in v0.3.0

func WidgetSources() widget.Sources

WidgetSources are the sources an installed widget can bind, by the name its stream declares: the mining loop's snapshot, whose schema is the loop's own Snapshot type.

func WidgetsEvent added in v0.3.0

func WidgetsEvent(definitions []DefinitionFiles) (live.Event, error)

WidgetsEvent is the event the widgets effect emits when a definition changed, addressed to the panel.

Types

type AppliedProfile added in v0.3.0

type AppliedProfile struct {
	At      time.Time         `json:"at"`
	Profile string            `json:"profile"`
	Changes []ContainerChange `json:"changes"`
	// Undoes is the time of the record this one undid; empty on an apply.
	Undoes *time.Time `json:"undoes,omitempty"`
}

AppliedProfile is one ledger record: a profile applied, or an undo of one, with exactly the changes made.

type ApplyHostProfileInput added in v0.3.0

type ApplyHostProfileInput struct {
	Name    string   `json:"name" jsonschema:"the profile's name"`
	Confirm []string `json:"confirm,omitempty" jsonschema:"the containers it changes, exactly as a dry run listed them"`
	DryRun  bool     `json:"dry_run,omitempty" jsonschema:"show the diff and change nothing"`
}

ApplyHostProfileInput applies one profile.

type Build added in v0.3.0

type Build struct {
	Revision string    `json:"revision"`
	Time     time.Time `json:"time"`
}

Build is the source revision the host serving the page was built from and that commit's time: a pull request merged at or before Time is in it.

func BuildOf added in v0.3.0

func BuildOf(info *debug.BuildInfo, known bool) Build

BuildOf is the build go build stamped into a binary: its revision and that commit's time. A binary built with no version control information, or with no build information at all, is an unknown build.

type CertificatePanel added in v0.3.0

type CertificatePanel struct {
	Recorded bool
	Repo     string
	Revision string
	Created  string
	Pass     bool
	Checks   []CertificateRow
}

CertificatePanel is what the view shows of the certificate: a pure projection of it, every number already rendered.

type CertificateRow added in v0.3.0

type CertificateRow struct {
	// Name is the check.
	Name string
	// Value is the measured value.
	Value string
	// Threshold is how the threshold was read: the value, the quantile it
	// sits at, and the size of the sample it was read from.
	Threshold string
	// Method is how the threshold was derived: "knee", or "none" when the
	// reference sample was too small to have a curve.
	Method string
	// Pass is the verdict.
	Pass bool
}

CertificateRow is one certificate check, every number already rendered.

type CheckWidgetInput added in v0.3.0

type CheckWidgetInput struct {
	Name         string `json:"name" jsonschema:"the definition's directory name under widgets/"`
	AssignmentID string `` /* 146-byte string literal not displayed */
}

CheckWidgetInput names one definition, in a session's worktree or, with no assignment, the Workbench's own checkout.

type ContainerAction added in v0.3.0

type ContainerAction string

ContainerAction is one of the four state changes the panel makes.

const (
	ActionStart   ContainerAction = "start"
	ActionStop    ContainerAction = "stop"
	ActionPause   ContainerAction = "pause"
	ActionUnpause ContainerAction = "unpause"
)

type ContainerChange added in v0.3.0

type ContainerChange struct {
	Name   string          `json:"name"`
	Action ContainerAction `json:"action"`
	// From is the state the container was in when the change was planned.
	From string `json:"from"`
}

ContainerChange is one state change of one container.

type ControlContainersInput added in v0.3.0

type ControlContainersInput struct {
	Action  ContainerAction `json:"action" jsonschema:"start, stop, pause or unpause"`
	Names   []string        `json:"names,omitempty" jsonschema:"container names; or give group"`
	Group   HostGroup       `` /* 144-byte string literal not displayed */
	Confirm []string        `` /* 167-byte string literal not displayed */
	DryRun  bool            `json:"dry_run,omitempty" jsonschema:"plan against the live host and change nothing"`
}

ControlContainersInput is one action on named containers, or on every container of a group it applies to.

type CostDayRow added in v0.3.0

type CostDayRow struct {
	Day          string
	SessionHours string
	// ByOperation follows costColumns, then everything else.
	ByOperation [5]string
	HFleet      string
	Saving      string
}

CostDayRow is one day of the series, every number rendered.

type CostParameterRow added in v0.3.0

type CostParameterRow struct {
	Name   string
	Value  string
	Chosen bool
}

CostParameterRow is one parameter the hypervisor reads.

type CostPolicyRow added in v0.3.0

type CostPolicyRow struct {
	Decision string
	Policy   string
	USD      string
	Saving   string
	Note     string
}

CostPolicyRow is one decision's chosen policy against today's.

type CostsPanel added in v0.3.0

type CostsPanel struct {
	Recorded   bool
	Updated    string
	Runs       string
	Days       []CostDayRow
	Policies   []CostPolicyRow
	Parameters []CostParameterRow
}

CostsPanel is what the view shows of the cost model: a pure projection of its report, every number already rendered.

type DefinitionFiles added in v0.3.0

type DefinitionFiles struct {
	Name  string            `json:"name"`
	Files map[string]string `json:"files"`
}

DefinitionFiles is one definition directory's files as the effect read them, by file name. A file that could not be read is absent, and the check says so.

func ReadDefinitions added in v0.3.0

func ReadDefinitions(files iofs.IFiles) ([]DefinitionFiles, error)

ReadDefinitions reads every definition directory beneath files' root: its three definition files, whichever exist. A directory holding none of them is not a definition, which is also what a definition being created looks like before its first file lands.

type GetHostInput added in v0.3.0

type GetHostInput struct{}

GetHostInput takes nothing.

type GitHubEventRow added in v0.3.0

type GitHubEventRow struct {
	At      time.Time `json:"at"`
	Time    string    `json:"time"`
	EventID string    `json:"event_id"`
	Kind    string    `json:"kind"`
	Where   string    `json:"where"`
	Actor   string    `json:"actor"`
	Summary string    `json:"summary"`
	URL     string    `json:"url"`
	Routed  string    `json:"routed"`
}

GitHubEventRow is one typed event as the panel shows it.

type GitHubPanel added in v0.3.0

type GitHubPanel struct {
	Recorded bool             `json:"recorded"`
	Events   []GitHubEventRow `json:"events"`
	Failures []GitHubRefusal  `json:"failures"`
	Accepted int              `json:"accepted"`
	Refused  int              `json:"refused"`
	Release  *GitHubEventRow  `json:"release,omitempty"`
	Notice   string           `json:"notice,omitempty"`
	// contains filtered or unexported fields
}

GitHubPanel is the panel's data, read from the end of the stream.

func ReadGitHubPanel added in v0.3.0

func ReadGitHubPanel(records []byte, hostStart time.Time) GitHubPanel

ReadGitHubPanel folds the stream's records, oldest first, into the panel; hostStart decides whether the newest csf release is news.

type GitHubRefusal added in v0.3.0

type GitHubRefusal struct {
	Time     string `json:"time"`
	Event    string `json:"event"`
	Delivery string `json:"delivery"`
	Outcome  string `json:"outcome"`
	Why      string `json:"why"`
}

GitHubRefusal is one delivery the receiver refused or failed.

type GoldenPanel added in v0.3.0

type GoldenPanel struct {
	Recorded      bool
	Gate          string
	MainRevision  string
	MergeRevision string
	Rows          []GoldenRow
	Refused       bool
	Reasons       []string
}

GoldenPanel is what the view shows of the merge quality gate's verdict: a pure projection of it, every number already rendered.

type GoldenRow added in v0.3.0

type GoldenRow struct {
	// Name is the metric: seed files, seed breaks, chief violations, or derived
	// share.
	Name string
	// Main is the value on main, already rendered.
	Main string
	// Merge is the value on the merge result, already rendered.
	Merge string
	// Refuses reports whether this metric alone refuses the merge.
	Refuses bool
}

GoldenRow is one of the gate's four golden metrics, each number on both sides of the merge already rendered.

type HostChangeOutput added in v0.3.0

type HostChangeOutput struct {
	DryRun  bool              `json:"dry_run"`
	Changes []ContainerChange `json:"changes"`
	Stop    []string          `json:"stop"`
	Start   []string          `json:"start"`
	// Result is the change set in words: the expected result.
	Result string `json:"result"`
	// Confirm is what the change asks to be confirmed; empty when none.
	Confirm []string `json:"confirm"`
}

HostChangeOutput is a change set: planned on a dry run, made otherwise.

type HostContainer added in v0.3.0

type HostContainer struct {
	ID      string    `json:"id"`
	Name    string    `json:"name"`
	Image   string    `json:"image"`
	Project string    `json:"project,omitempty" jsonschema:"the Compose project, when the container has one"`
	State   string    `json:"state"`
	Status  string    `json:"status"`
	Group   HostGroup `json:"group"`
	// Assignment is the harness run a CSF work container belongs to.
	Assignment string `json:"assignment,omitempty"`
	Protected  bool   `json:"protected"`
	// CPUPercent is the share of one cpu used since the previous reading, or
	// -1 before there are two readings.
	CPUPercent  float64 `json:"cpu_percent"`
	MemoryBytes uint64  `json:"memory_bytes"`
}

HostContainer is one container on the machine.

type HostGauges added in v0.3.0

type HostGauges struct {
	Cores                int     `json:"cores"`
	LoadOneMinute        float64 `json:"load_one_minute"`
	MemoryTotalBytes     uint64  `json:"memory_total_bytes"`
	MemoryAvailableBytes uint64  `json:"memory_available_bytes"`
	DiskTotalBytes       uint64  `json:"disk_total_bytes"`
	DiskFreeBytes        uint64  `json:"disk_free_bytes"`
	// The pressure gauges are the percent of the last 10 s in which some task
	// waited for cpu, memory or io, or -1 where the kernel reports none.
	PressureCPU    float64 `json:"pressure_cpu_some_avg10"`
	PressureMemory float64 `json:"pressure_memory_some_avg10"`
	PressureIO     float64 `json:"pressure_io_some_avg10"`
	// Overloaded is true when the load passed the guard: 1.5 times the cores.
	Overloaded bool `json:"overloaded"`
	// Findings are the gauges that could not be read.
	Findings []string `json:"findings,omitempty"`
}

HostGauges are the machine's own numbers: load against cores, memory and the state directory's disk.

type HostGroup added in v0.3.0

type HostGroup string

HostGroup is which side of the panel a container is on.

const (
	// GroupCSF is CSF work: the harness's own sessions and their build
	// containers, recognized from the harness's run directories.
	GroupCSF HostGroup = "csf"
	// GroupOther is every other container on the machine.
	GroupOther HostGroup = "other"
)

type HostOperation added in v0.3.0

type HostOperation string

HostOperation names what a host request does.

const (
	OperationControl HostOperation = "control"
	OperationProfile HostOperation = "profile"
	OperationUndo    HostOperation = "undo"
	OperationProtect HostOperation = "protect"
	OperationHold    HostOperation = "hold"
)

type HostOperations added in v0.3.0

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

HostOperations is the host operations over the capabilities they need.

func NewHostOperations added in v0.3.0

func NewHostOperations(options ...HostOperationsOption) (*HostOperations, error)

NewHostOperations validates the option set before building the operations.

func (*HostOperations) ApplyProfile added in v0.3.0

func (operations *HostOperations) ApplyProfile(ctx context.Context, input ApplyHostProfileInput) (HostChangeOutput, error)

ApplyProfile makes the host match one profile and records what it changed.

func (*HostOperations) Check added in v0.3.0

func (operations *HostOperations) Check(ctx context.Context, request HostRequest) (widget.Expectation, error)

Check is a request's acceptance check: the exact operation dry-run against the live host, which is what each of the panel's buttons is verified by.

func (*HostOperations) Control added in v0.3.0

func (operations *HostOperations) Control(ctx context.Context, input ControlContainersInput) (HostChangeOutput, error)

Control starts, stops, pauses or unpauses containers.

func (*HostOperations) Host added in v0.3.0

func (operations *HostOperations) Host(ctx context.Context, input GetHostInput) (HostReport, error)

Host reads the machine now.

func (*HostOperations) Panel added in v0.3.0

func (operations *HostOperations) Panel(ctx context.Context) HostPanel

Panel reads the host and verifies every button the panel draws against that same reading: each button's request is dry-run and its expected result kept, or its refusal.

func (*HostOperations) Press added in v0.3.0

func (operations *HostOperations) Press(ctx context.Context, request HostRequest, confirm []string) (string, error)

Press runs one request as the panel's button does: confirm is what the operator was shown and confirmed, and the operation refuses if the host has moved since.

func (*HostOperations) Protect added in v0.3.0

func (operations *HostOperations) Protect(ctx context.Context, input ProtectContainersInput) (HostSettings, error)

Protect marks containers protected, or clears the mark.

func (*HostOperations) PutProfile added in v0.3.0

func (operations *HostOperations) PutProfile(ctx context.Context, input PutHostProfileInput) (HostSettings, error)

PutProfile adds or replaces the profile of its name, or removes it.

func (*HostOperations) Register added in v0.3.0

func (operations *HostOperations) Register(router gin.IRouter)

Register serves the host operations over HTTP, each a POST of its input as JSON answered with its output.

func (*HostOperations) Undo added in v0.3.0

func (operations *HostOperations) Undo(ctx context.Context, input UndoHostProfileInput) (HostChangeOutput, error)

Undo reverses the last applied profile not yet undone, and records that.

type HostOperationsOption added in v0.3.0

type HostOperationsOption func(operations *HostOperations) error

HostOperationsOption configures HostOperations.

func WithHostClock added in v0.3.0

func WithHostClock(source clock.IClock) HostOperationsOption

WithHostClock grants the clock ledger records are stamped by.

func WithHostContainers added in v0.3.0

func WithHostContainers(containers IHostContainers) HostOperationsOption

WithHostContainers grants the container capability. Required.

func WithHostState added in v0.3.0

func WithHostState(state *iofs.HostFiles) HostOperationsOption

WithHostState grants the harness state directory: its run directories are the records CSF work is recognized from, its filesystem is the disk gauge, and it holds the operator's settings and the ledger.

func WithProcessTable added in v0.3.0

func WithProcessTable(processes iofs.IFiles) HostOperationsOption

WithProcessTable grants /proc, which the load and memory gauges read.

func WithSessionHold added in v0.3.0

func WithSessionHold(hold func(ctx context.Context, reason string) error) HostOperationsOption

WithSessionHold grants the hold the load guard offers: hold, with a reason, stops new sessions being launched.

type HostPanel added in v0.3.0

type HostPanel struct {
	Report  HostReport                     `json:"report"`
	Actions []widget.Verified[HostRequest] `json:"actions"`
	Error   string                         `json:"error,omitempty"`
}

HostPanel is what the effect delivers: the host read, and every button with its check's verdict.

type HostProfile added in v0.3.0

type HostProfile struct {
	Name string `json:"name" jsonschema:"the profile's name, as the panel shows it"`
	// Keep names containers to keep running: each that is stopped starts.
	Keep []string `json:"keep,omitempty" jsonschema:"container names to keep running; each one that is stopped starts"`
	// KeepCSFWork leaves CSF work running when the profile stops the rest.
	KeepCSFWork bool `json:"keep_csf_work,omitempty" jsonschema:"leave the harness's sessions and their build containers running"`
	// StopOthers stops every running or paused container the profile does not
	// keep. Protected containers are never stopped.
	StopOthers bool `` /* 133-byte string literal not displayed */
}

HostProfile is one operator profile: a named set of containers to keep running, started when stopped, and whether everything else stops.

type HostReport added in v0.3.0

type HostReport struct {
	HostSnapshot
	Settings HostSettings `json:"settings"`
	// Undoable is the applied profile an undo reverses, when there is one.
	Undoable *AppliedProfile `json:"undoable,omitempty"`
	// Holds is true when sessions can be held from the panel.
	Holds bool `json:"holds"`
}

HostReport is the machine now: its gauges and containers, the operator's settings, and the applied profile an undo would reverse.

type HostRequest added in v0.3.0

type HostRequest struct {
	Operation HostOperation   `json:"operation"`
	Action    ContainerAction `json:"action,omitempty"`
	Names     []string        `json:"names,omitempty"`
	Group     HostGroup       `json:"group,omitempty"`
	Profile   string          `json:"profile,omitempty"`
	Protected bool            `json:"protected,omitempty"`
}

HostRequest is one host operation as the panel's buttons carry it: the exact request each button's check dry-runs and its press runs.

type HostSettings added in v0.3.0

type HostSettings struct {
	Profiles  []HostProfile `json:"profiles"`
	Protected []string      `json:"protected"`
}

HostSettings is the operator's host record: the profiles and the containers nothing on the panel may stop or pause.

type HostSnapshot added in v0.3.0

type HostSnapshot struct {
	Gauges     HostGauges      `json:"gauges"`
	Containers []HostContainer `json:"containers"`
	// Resumes is the resume queue the last restart recorded: the open runs it
	// resumed and the ones the launch check holds, or nil before any restart.
	Resumes *harness.ResumeQueue `json:"resumes,omitempty"`
}

HostSnapshot is the machine at one reading.

type IDreamerControls added in v0.3.0

type IDreamerControls interface {
	Pause(ctx context.Context, input dreamer.ControlInput) (dreamer.Snapshot, error)
	Resume(ctx context.Context, input dreamer.ControlInput) (dreamer.Snapshot, error)
}

IDreamerControls pauses and resumes the dreamer. *dreamer.Dreamer satisfies it.

type IHostContainers added in v0.3.0

IHostContainers is the container capability the host panel is granted: list every container, the four state changes, and a usage sample. *docker.ContainerHost satisfies it. It has no remove and no volume operation, so nothing built on it can remove a container or touch a volume.

type IHostDisk added in v0.3.0

type IHostDisk interface {
	DiskUsage() (iofs.DiskUsage, error)
}

IHostDisk is the filesystem the state directory lives on; *iofs.HostFiles satisfies it.

type ISliceControls added in v0.3.0

type ISliceControls interface {
	Hold(ctx context.Context, input dispatch.SliceControlInput) (dispatch.Snapshot, error)
	Release(ctx context.Context, input dispatch.SliceControlInput) (dispatch.Snapshot, error)
}

ISliceControls holds and releases one slice of the dispatcher's queue. *dispatch.DispatchService satisfies it.

type IWorkbenchOperations added in v0.3.0

type IWorkbenchOperations interface {
	SubmitAgentSession(ctx context.Context, request *harnessv1.SubmitAgentSessionRequest) (*harnessv1.SubmitAgentSessionResponse, error)
	SendAgentSessionMessage(ctx context.Context, request *harnessv1.SendAgentSessionMessageRequest) (*harnessv1.SendAgentSessionMessageResponse, error)
	CancelAgentSession(ctx context.Context, request *harnessv1.CancelAgentSessionRequest) (*harnessv1.CancelAgentSessionResponse, error)
	CheckAgentSessionAdmission(ctx context.Context, request *harnessv1.CheckAgentSessionAdmissionRequest) (*harnessv1.CheckAgentSessionAdmissionResponse, error)
	ReadyAgentSessionPullRequest(ctx context.Context, request *harnessv1.ReadyAgentSessionPullRequestRequest) (*harnessv1.ReadyAgentSessionPullRequestResponse, error)
	MergeAgentSessionPullRequest(ctx context.Context, request *harnessv1.MergeAgentSessionPullRequestRequest) (*harnessv1.MergeAgentSessionPullRequestResponse, error)
	SetAgentExecutorDefault(ctx context.Context, request *harnessv1.SetAgentExecutorDefaultRequest) (*harnessv1.SetAgentExecutorDefaultResponse, error)
	ListAgentSessions(ctx context.Context, request *harnessv1.ListAgentSessionsRequest) (*harnessv1.ListAgentSessionsResponse, error)
	// GetWorkbenchTheme is the operator's workbench-theme.css, applied after
	// the page's token set so it can override any token.
	GetWorkbenchTheme(ctx context.Context, request *pb.GetWorkbenchThemeRequest) (*pb.GetWorkbenchThemeResponse, error)
}

IWorkbenchOperations is the control plane the Workbench acts through: the generated harness operations of the CSF service, the same ones the csf CLI calls over HTTP and an agent calls over MCP. The page holds no action of its own; every button is one of these calls. *csf.Service satisfies it in process and *csf.Client over HTTP.

type InstalledWidget added in v0.3.0

type InstalledWidget struct {
	Name    string
	Reasons []string
	// contains filtered or unexported fields
}

InstalledWidget is one definition as the view holds it: the checked definition, or every reason it was refused.

func InstallWidgets added in v0.3.0

func InstallWidgets(previous []InstalledWidget, definitions []DefinitionFiles, sources widget.Sources) []InstalledWidget

InstallWidgets checks every definition against the sources and returns them in name order, reusing the previous check of a definition whose files did not change. Two definitions may not claim one region or one widget name; the second in name order is refused. It is pure.

func (InstalledWidget) Installed added in v0.3.0

func (installed InstalledWidget) Installed() bool

Installed reports whether the widget is drawn.

type JevPanel added in v0.3.0

type JevPanel struct {
	Recorded        bool
	Day             string
	Model           string
	Updated         string
	Runs            string
	TokensPerDay    string
	DecisionsPerDay string
}

JevPanel is what the view shows of the decision record: a pure projection, every number already rendered, so the fragment's dirty check is a comparison of strings.

type LabelerPanel added in v0.3.0

type LabelerPanel struct {
	Recorded  bool
	Model     string
	Phase     string
	Current   string
	Tickets   string
	Labels    string
	Precision string
	Rate      string
	GPU       string
	KeepAlive string
	Yields    string
	Updated   string
}

LabelerPanel is what the view shows of the labeler: a pure projection of its run record, every number already rendered, so the fragment's dirty check is a comparison of strings.

type Line added in v0.3.0

type Line struct {
	Cards []LineCard `json:"cards"`
	// Graph is every node of the slice graph, the board's and the finished
	// ones the board leaves out.
	Graph   []LineCard `json:"graph"`
	Workers []Worker   `json:"workers"`
	// Running is how many real sessions run a turn; Capacity the dispatcher's
	// admission, Binding the limit that sets it and Quota whether that limit
	// is the provider's or the budget's rather than the machine's.
	Running  int              `json:"running"`
	Capacity int              `json:"capacity"`
	Limits   []dispatch.Limit `json:"limits,omitempty"`
	Binding  string           `json:"binding,omitempty"`
	Quota    bool             `json:"quota"`
	Snapshot bool             `json:"snapshot"`
	Loop     []LoopHop        `json:"loop"`
	Build    Build            `json:"build"`
}

Line is the panel's model: a pure function of the page's state and the build, compared whole to decide whether the panel moved.

type LineCard added in v0.3.0

type LineCard struct {
	Key            string         `json:"key"`
	Title          string         `json:"title"`
	Stage          dispatch.Stage `json:"stage"`
	TicketURL      string         `json:"ticket_url,omitempty"`
	PullRequestURL string         `json:"pull_request_url,omitempty"`
	// PullRequest is how far the control plane moved the pull request.
	PullRequest PullRequestStage `json:"pull_request,omitempty"`
	// Why is why the slice stands where it does: its rank on the frontier,
	// what it waits on, what it contends with.
	Why string `json:"why,omitempty"`
	// Owner is the virtual session carrying the slice; Model and Executor its
	// real session's, Activity its current tool row.
	Owner    string `json:"owner,omitempty"`
	Model    string `json:"model,omitempty"`
	Executor string `json:"executor,omitempty"`
	Activity string `json:"activity,omitempty"`
	Elapsed  string `json:"elapsed,omitempty"`
	Cost     string `json:"cost,omitempty"`
	Frontier bool   `json:"frontier,omitempty"`
	// DependsOn and Contends are the slice's edges in the slice graph.
	DependsOn []string `json:"depends_on,omitempty"`
	Contends  []string `json:"contends,omitempty"`
}

LineCard is one slice on the board: the dispatcher's slice, or the virtual session carrying one, or a pull request merged today.

type ListWidgetsInput added in v0.3.0

type ListWidgetsInput struct{}

ListWidgetsInput takes nothing.

type ListWidgetsOutput added in v0.3.0

type ListWidgetsOutput struct {
	Widgets []WidgetStatus `json:"widgets"`
	// Sources are the source names a widget's stream may bind.
	Sources []string `json:"sources"`
}

ListWidgetsOutput is every definition in the Workbench's widgets directory.

type LoopHop added in v0.3.0

type LoopHop struct {
	Name     string `json:"name"`
	Count    *int   `json:"count,omitempty"`
	PilesUp  bool   `json:"piles_up,omitempty"`
	Recorded bool   `json:"recorded"`
}

LoopHop is one hop of the mining loop's ring with its count, absent when nothing records it yet.

type LoopPanel added in v0.3.0

type LoopPanel struct {
	Present  bool               `json:"present"`
	Snapshot ouroboros.Snapshot `json:"snapshot"`
}

LoopPanel is what the ops view shows of the mining loop: the loop's snapshot, present once the loop has written one.

type MergedPullRequest added in v0.3.0

type MergedPullRequest struct {
	Number   int       `json:"number"`
	Title    string    `json:"title"`
	URL      string    `json:"url"`
	MergedAt time.Time `json:"mergedAt"`
}

MergedPullRequest is one pull request merged into main, as gh lists it.

type MinerSeries added in v0.3.0

type MinerSeries struct {
	Miner  string          `json:"miner"`
	Points []MutationPoint `json:"points"`
}

MinerSeries is one miner's measurements in file order.

func ReadSeries added in v0.3.0

func ReadSeries(content []byte) []MinerSeries

ReadSeries folds the series file into one series per miner, miners in name order and points in file order. A line that is not a record is skipped: the file is appended by hand and by the loop, and one bad line must not hide every other miner. It is pure.

type MutationPoint added in v0.3.0

type MutationPoint struct {
	At        time.Time `json:"at"`
	Killed    int       `json:"killed"`
	Survived  int       `json:"survived"`
	Excluded  int       `json:"excluded"`
	Score     float64   `json:"score"`
	Accepted  bool      `json:"accepted"`
	Surviving []string  `json:"surviving"`
}

MutationPoint is one measurement of one miner's test.

type OpenPullRequest added in v0.3.0

type OpenPullRequest struct {
	URL          string `json:"url"`
	Additions    int    `json:"additions"`
	Deletions    int    `json:"deletions"`
	ChangedFiles int    `json:"changedFiles"`
	// Checks is the rollup: failing if any check failed, pending if any has
	// not finished, passing if all passed, empty with no checks.
	Checks string `json:"checks"`
}

OpenPullRequest is one open pull request's diff stat and checks.

type OpsView

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

OpsView is the live application and its routes.

func NewOpsView

func NewOpsView(files iofs.IFiles, watcher iofs.IWatcher, origins []string, logger *slog.Logger, options ...Option) (*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. WithOperations makes it the Workbench, the page that acts.

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 Option added in v0.3.0

type Option func(view *OpsView) error

Option configures the view beyond its required capabilities.

func WithBuild added in v0.3.0

func WithBuild(build Build) Option

WithBuild tells the line which build the host runs, so merged work shows as live or as waiting for csf upgrade. Without it nothing is shown live.

func WithClock added in v0.3.0

func WithClock(source clock.IClock) Option

WithClock replaces the clock that says which UTC day is today.

func WithCloudStop added in v0.3.0

func WithCloudStop(stop func(ctx context.Context, input cloud.StopCloudJobInput) (cloud.CloudJob, error)) Option

WithCloudStop grants the cloud service's Stop, which the panel's buttons call. Without it the panel shows the jobs and offers no Stop.

func WithEndpoints added in v0.3.0

func WithEndpoints(registry endpoint.Registry) Option

WithEndpoints grants the page the endpoint registry as csf serve registered it at start. The registry changes only when a csf serve starts or the operator retires an address before restarting one, so the panel is drawn from this value and never re-read.

func WithGitHub added in v0.3.0

func WithGitHub(launcher proc.ILauncher) Option

WithGitHub lets the page read the pull requests merged into main today from the forge, through gh started by launcher, for every repository a session's pull request lives in. Without it the merges tile says it has no source.

func WithHostOperations added in v0.3.0

func WithHostOperations(operations *HostOperations) Option

WithHostOperations gives the Workbench its host panel, a client of operations.

func WithHostStart added in v0.3.0

func WithHostStart(startedAt time.Time) Option

WithHostStart tells the page when the host serving it started, so a session whose log still says running but whose last record is older reads as stalled.

func WithOperations added in v0.3.0

func WithOperations(operations IWorkbenchOperations) Option

WithOperations makes the page the Workbench: every card gains its actions and the page its launch form, each a call to operations. Without it the page is a read-only ops view.

func WithQueueControls added in v0.3.0

func WithQueueControls(slices ISliceControls, dreams IDreamerControls) Option

WithQueueControls gives the queue a hold or release button on every slice and the dreamer panel its pause and resume, each a verified action.

func WithRecipeTemplates added in v0.3.0

func WithRecipeTemplates(templates iofs.IFiles) Option

WithRecipeTemplates grants the directory the launch form's templates are read from: one <name>/agent.json (and the brief it names) per template.

func WithWidgetDefinitions added in v0.3.0

func WithWidgetDefinitions(files iofs.IFiles, watcher iofs.IWatcher) Option

WithWidgetDefinitions grants the widgets directory: files reads its definitions and watcher reports their changes. Without it the panel stays empty.

type ProposeWidgetInput added in v0.3.0

type ProposeWidgetInput struct {
	Name         string `json:"name" jsonschema:"the definition's directory name under widgets/"`
	AssignmentID string `json:"assignment_id" jsonschema:"the harness assignment whose worktree holds widgets/<name>"`
	Need         string `json:"need" jsonschema:"what the widget shows, one line; it becomes the commit subject"`
}

ProposeWidgetInput names one definition in a session's worktree and what it shows.

type ProposeWidgetOutput added in v0.3.0

type ProposeWidgetOutput struct {
	WidgetStatus
	Commit         string `json:"commit,omitempty"`
	PullRequestURL string `json:"pull_request_url,omitempty"`
}

ProposeWidgetOutput is the proposal: the commit and the pull request, or every reason the check refused it, in which case nothing was committed.

type ProtectContainersInput added in v0.3.0

type ProtectContainersInput struct {
	Names     []string `json:"names"`
	Protected bool     `json:"protected" jsonschema:"true protects them; false clears the mark"`
}

ProtectContainersInput marks containers protected, or clears the mark.

type PullRequestStage added in v0.3.0

type PullRequestStage string

PullRequestStage is how far the control plane has moved a session's pull request.

const (
	PullRequestReady PullRequestStage = "ready"
	// PullRequestMerging is a merge the control plane started and has not
	// finished: the merge path is running its checks.
	PullRequestMerging PullRequestStage = "merging"
	PullRequestMerged  PullRequestStage = "merged"
)

type PutHostProfileInput added in v0.3.0

type PutHostProfileInput struct {
	Profile HostProfile `json:"profile"`
	Remove  bool        `json:"remove,omitempty" jsonschema:"remove the profile of this name instead"`
}

PutHostProfileInput adds, replaces or removes one profile.

type RecentEvent

type RecentEvent struct {
	Time string `json:"time"`
	Kind string `json:"kind"`
	// Text is the event in words; Raw is the record as the executor or the
	// harness wrote it, home directories removed, for the raw view.
	Text string `json:"text"`
	Raw  string `json:"raw,omitempty"`
}

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"`
	// Executor is the turn executor the session runs on.
	Executor    string `json:"executor"`
	Status      Status `json:"status"`
	Turns       int    `json:"turns"`
	ToolCalls   int    `json:"tool_calls"`
	GateDenials int    `json:"gate_denials"`
	// Resumes counts the session's resumes after a suspend.
	Resumes int `json:"resumes"`
	// Background is how many tasks the executor last reported running in the
	// background; BackgroundTurns how many turns a background completion
	// started.
	Background      int       `json:"background"`
	BackgroundTurns int       `json:"background_turns"`
	StartedAt       time.Time `json:"started_at"`
	// Worktree is the session's working tree, which activity lines are
	// relative to. It is the fold's input, not something the page shows.
	Worktree string `json:"-"`
	// Activity is what the session is doing now, in words: its latest tool
	// call or harness step.
	Activity string `json:"activity,omitempty"`
	// Said is the first line of the last thing the session wrote to the
	// operator, and Question is whether it ends by asking something.
	Said     string `json:"said,omitempty"`
	Question bool   `json:"question,omitempty"`
	// LastDay is the UTC day of the newest record read: a card moves to
	// another day at most once a day.
	LastDay string `json:"last_day,omitempty"`
	// Partial is set when the card was folded from the end of its event log
	// only, so its counts and spend cover that window; the follow effect
	// reads the whole log when the session moves or its card is opened.
	Partial bool `json:"partial,omitempty"`
	// Problem is Error in words.
	Problem string `json:"problem,omitempty"`
	// 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"`
	// Launch is how the session was launched, container or host, from its
	// launch receipt once it closes.
	Launch string `json:"launch,omitempty"`
	// CPU and MemoryPeak are a container or sandboxed session's cgroup
	// receipt, shown once the session closes; empty for a plain host session.
	CPU        string `json:"cpu,omitempty"`
	MemoryPeak string `json:"memory_peak,omitempty"`
	// PullRequest is where the session's pull request stands as far as the
	// control plane moved it: empty, ready, or merged.
	PullRequest PullRequestStage `json:"pull_request,omitempty"`
	// MergedOn is the UTC day the control plane merged the pull request.
	MergedOn string `json:"merged_on,omitempty"`
	// CostByDay is the session's spend in USD per UTC day, folded from its
	// result records the way the mining loop folds a fixer's cost.
	CostByDay map[string]float64 `json:"cost_by_day,omitempty"`

	// Notice is the outcome of the last action the page took on the card. Like
	// Expanded it is the page's, and survives the card being replaced, as do
	// the fields after it up to Recent.
	Notice string `json:"notice,omitempty"`
	// Internals shows the card's identifiers, raw counts and raw activity;
	// Composing shows its composer.
	Internals bool `json:"internals,omitempty"`
	Composing bool `json:"composing,omitempty"`
	// Confirm is the action the card is asking the operator to confirm, and
	// Pending the action whose typed result the card is waiting for.
	Confirm string `json:"confirm,omitempty"`
	Pending string `json:"pending,omitempty"`
	// Landed is set when the merges read from the forge list the card's pull
	// request as merged into main today.
	Landed bool `json:"landed,omitempty"`
	// Forge is the card's open pull request as the forge last listed it: its
	// diff stat and checks.
	Forge OpenPullRequest `json:"forge"`
	// 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"`
	// contains filtered or unexported fields
}

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 SessionCounts added in v0.3.0

type SessionCounts struct {
	Present  bool `json:"present"`
	Virtual  int  `json:"virtual"`
	Running  int  `json:"running"`
	Open     int  `json:"open"`
	Starting int  `json:"starting"`
	Canceled int  `json:"canceled"`
	Failed   int  `json:"failed"`
	Closed   int  `json:"closed"`
	// Suspended counts the open virtual sessions whose real session is
	// closed until their next message.
	Suspended int `json:"suspended"`
	Real      int `json:"real"`
}

SessionCounts is the host's sessions, of both kinds. A virtual_session is one harness session (one assignment) as the session service holds it, by phase. A real_session is the executor process a virtual session runs its turns on: one is alive for every virtual session that is starting, running, open or canceling and not suspended. A suspended session closed its executor while idle and opens a new one on its next message.

func CountSessions added in v0.3.0

func CountSessions(sessions []*harnessv1.AgentSessionState) SessionCounts

CountSessions counts the session service's sessions by phase, and the real sessions they keep alive.

type Status

type Status string

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

const (
	StatusRunning   Status = "running"
	StatusFinished  Status = "finished"
	StatusSuspended Status = "suspended"
	// StatusWaiting is a finished turn whose executor still runs background
	// tasks: the completion of one wakes the session with no Send, so it is
	// not stranded.
	StatusWaiting Status = "waiting"
	StatusFailed  Status = "failed"
	StatusClosed  Status = "closed"
	// StatusStalled is a session whose log says running but whose last
	// record is older than the host now serving the page: the host that ran
	// its turn stopped, and no host is running it.
	StatusStalled Status = "stalled"
)

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 idle, after which the session is suspended: open on its conversation with no executor process until the next message resumes it.

type UndoHostProfileInput added in v0.3.0

type UndoHostProfileInput struct {
	Confirm []string `json:"confirm,omitempty" jsonschema:"the containers it changes, exactly as a dry run listed them"`
	DryRun  bool     `json:"dry_run,omitempty" jsonschema:"show the diff and change nothing"`
}

UndoHostProfileInput undoes the last applied profile not yet undone.

type ViewPrefs added in v0.3.0

type ViewPrefs struct {
	// Expanded, Internals and Composing are assignments, sorted.
	Expanded  []string
	Internals []string
	Composing []string
	// OthersOpen shows the idle and finished sessions as a list rather than
	// a count; Filter and Show narrow that list.
	OthersOpen bool
	Filter     string
	Show       Status
	// Opened are the lower sections the viewer unfolded, sorted; each is
	// folded to one line until then.
	Opened []string
	// Defined is the tile whose definition is showing, if any.
	Defined string
}

ViewPrefs is one viewer's view of the page: which cards are open, which show their internals or their composer, the idle list's filter, and which sections are folded away. The server owns it, so it survives every patch, and it is remembered per viewer, so it survives a reload.

type ViewerIdentity added in v0.3.0

type ViewerIdentity struct {
	Viewer string
}

ViewerIdentity is who a connection is: the viewer the cookie names, or nobody for a client that sent none, whose view is not remembered.

func (ViewerIdentity) Subject added in v0.3.0

func (identity ViewerIdentity) Subject() string

Subject is the viewer, for the library's logs.

type WidgetOperations added in v0.3.0

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

WidgetOperations is the three operations over the capabilities they need.

func NewWidgetOperations added in v0.3.0

func NewWidgetOperations(options ...WidgetOperationsOption) (*WidgetOperations, error)

func (*WidgetOperations) Check added in v0.3.0

func (operations *WidgetOperations) Check(ctx context.Context, input CheckWidgetInput) (WidgetStatus, error)

Check runs the Workbench's install check on one definition.

func (*WidgetOperations) List added in v0.3.0

func (operations *WidgetOperations) List(ctx context.Context, input ListWidgetsInput) (ListWidgetsOutput, error)

List checks every definition the Workbench would install.

func (*WidgetOperations) Propose added in v0.3.0

func (operations *WidgetOperations) Propose(ctx context.Context, input ProposeWidgetInput) (ProposeWidgetOutput, error)

Propose checks one definition in a session's worktree and, when it is clean, commits widgets/<name> there and publishes the session's branch through the harness, which opens its pull request when it has none.

func (*WidgetOperations) Register added in v0.3.0

func (operations *WidgetOperations) Register(router gin.IRouter)

Register serves the three operations over HTTP, each a POST of its input as JSON answered with its output.

type WidgetOperationsOption added in v0.3.0

type WidgetOperationsOption func(operations *WidgetOperations) error

WidgetOperationsOption configures WidgetOperations.

func WithGitHubClient added in v0.3.0

func WithGitHubClient(client *github.GitHubClient) WidgetOperationsOption

NewWidgetOperations validates the option set before building the operations. WithGitHubClient grants the GitHub protocol client a proposal's draft pull request is opened through.

func WithInstalledDefinitions added in v0.3.0

func WithInstalledDefinitions(files iofs.IFiles) WidgetOperationsOption

WithInstalledDefinitions grants the Workbench checkout's widgets directory. Required.

func WithSessionWorktrees added in v0.3.0

func WithSessionWorktrees(state iofs.IFiles, launcher proc.ILauncher) WidgetOperationsOption

WithSessionWorktrees grants the harness state directory, whose run directories hold each session's record and worktree, and the launcher git and gh start through. Without it propose and a session-scoped check are refused.

type WidgetStatus added in v0.3.0

type WidgetStatus struct {
	Name string `json:"name" jsonschema:"the definition's directory name under widgets/"`
	// Installable is true when every check passed.
	Installable bool     `json:"installable" jsonschema:"true when every check passed and the Workbench draws it"`
	Source      string   `json:"source,omitempty" jsonschema:"the source its stream binds"`
	Reasons     []string `json:"reasons,omitempty" jsonschema:"every reason the check refused it"`
}

WidgetStatus is one definition and its check.

type Worker added in v0.3.0

type Worker struct {
	Key      string `json:"key"`
	Owner    string `json:"owner"`
	State    string `json:"state"`
	On       string `json:"on"`
	Model    string `json:"model"`
	Executor string `json:"executor"`
	Elapsed  string `json:"elapsed"`
}

Worker is one real session's slot: the virtual session it carries and whether it runs, waits or idles.

Jump to

Keyboard shortcuts

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