Ovvi

Architecture

The pieces of the app and how they reach each machine

A call goes from the views to HostStore (one per open session), to HerdrClient (the Multiplexer), to the machine's Exec: ProcessExec on This Mac, SSHExec and the relay on a remote machine. Requests and the event stream go to herdr's API socket (on a remote machine through a socket the SSH connection forwards); each streamed pane runs a terminal session.

Pieces

PieceJob
HerdrKit (Swift package)Exec, the Multiplexer interface and its herdr implementation: call(), the event stream, snapshot decoding, the split-tree rebuild, the remote command envelope and the relay; Files and Git, the plugin cards' file and git data over Exec; PluginManifest, PluginCalls (the plugin API's calls on a machine) and PluginPackages (plugin sources and installs); AgentRequest, the ovvi command's request and its mailbox runs
ProcessExecProcess with pipes, for This Mac
SSHExeca remote machine: its ControlMaster, the askpass prompts and the relay that carries every run
HostStorethe app's live model of one open session: snapshot, events, streams, seen state, git state, and which window controls it. One per session, shared by every window that shows it
Window stateone per window: its machine, its open pages and its selection (page, space, tabs, floating panes, sidebar and its width), restored with @SceneStorage; the keyboard card and zoom stay in memory
PaneViewRegistryowns terminal, browser and plugin views by terminal id, so scrolling never destroys them
Plugin cardsRegistry (the browser's manifest and every package's), Plugin and its WebCard (one web view and the ovvi-plugin:// scheme), Bridge (the plugin API, one per card), Header, and the installs, builds, defaults and confirmations; the API's runtime and types in web/ovvi/, the default plugins and the template in plugins/builtin/, the extra ones (not in the app) in plugins/extra/ (Plugins)
Agent commandsAgentCommands in Ovvi/Agent/: the one parser and every command that the ovvi command asks for, run against the asking session's HostStore; the script itself, ovvi.sh (Agent control)
Viewstitle row, sidebar pages (space and agent rows), page dots and Archived Sessions, tab bar, tab page, cards, overview, floating panes, panels and dialogs

Exec and Multiplexer are HerdrKit's only protocols; the app adds one, ChatAdapter, for the chat view's agents. HerdrKit is a separate package, so its single test target runs with swift test.

The Multiplexer interface

Multiplexer is the Swift protocol that every multiplexer implements (D49). herdr is the first and only implementation. Rex (superlogical.com) and tmux are candidates (Future work). The views use only this interface and the app's own model types, never herdr's JSON or argv.

PartWhat it gives the appherdr implementation
Machine connectionone session on one machine, through that machine's Execherdr on each machine, Checks on connect, Health check
Snapshotevery space, tab, pane, label and split tree, in the app's model typessession.snapshot, Reconcile, Layout
Events"the state changed, read the snapshot again"events.subscribe, Events
Terminal streamsone pane's screen as ANSI frames; keys, resize, scroll and mouse back; control or watchterminal session control/observe, Terminal plane
Actionscreate, split, move, swap, close, rename, resize; read a pane's textWrites are herdr calls
Agent statusper agent pane: working, needs you, idle, and a finish counteragent_status, completion_seq, Status

Agent status comes only from the interface, never from escape sequences in the app's terminal surfaces (D55, Status).

Multiplexer lives in HerdrKit/Multiplexer.swift next to HerdrClient, its only conformer, and has only the methods the app uses. The machine connection is not a method: HostStore makes the HerdrClient (the one place that names herdr) with the path from the machine's Exec.herdr() (herdr on each machine). The model types (Snapshot, Session, HerdrError, ...) stay in HerdrKit until a second multiplexer needs its own.

Simpler choice: the interface has the shape of herdr's features. A second implementation reshapes it where that multiplexer differs.

On this page