olympus

package module
v0.35.0 Latest Latest
Warning

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

Go to latest
Published: Oct 5, 2026 License: MIT Imports: 29 Imported by: 0

README

Olympus

A terminal you can drive from code.

Olympus creates, drives, observes and tears down real terminal sessions, the kind that survive you closing your laptop. It does not embed a multiplexer. It drives one you already have, and exposes that through three equal doors: a Go package, a CLI and a stdio MCP server.

What it does

  • Keeps sessions alive. A session outlives the command that made it. Come back to it from another shell, another process, or tomorrow.
  • Runs commands and reports their exit code. run waits for a command and returns its status and output, or detaches and lets you poll.
  • Drives interactive programs. Type, send, press keys, paste, and wait for a pattern on screen, against a REPL or a full-screen program.
  • Reads screens. One or several sessions in one call, with scrollback.
  • Finds coding agents in panes. agents lists which agent runs where, and whether it is working, idle or blocked on a person.
  • Hands a terminal to a person. attach gives the live session to whoever is at the keyboard.
  • Says what it cannot do. doctor and capabilities report each backend's limits, and a degraded operation warns instead of failing quietly.

Requirements

  • macOS or Linux.
  • Go 1.26.5 or newer, to install with go install. A release archive needs no Go.
  • At least one multiplexer. Olympus picks the first one installed, in this order:
Backend Version floor
zmx (default) 0.6.0
tmux 3.3
meja 0.0.25
herdr 0.8.2

--backend or OLYMPUS_BACKEND picks one explicitly. The floors are reported by olympus doctor, not enforced.

Install

go install github.com/husniadil/olympus/cmd/olympus@latest

Or take an archive from GitHub Releases. Each is built for darwin and linux on amd64 and arm64, and carries the binary, its man pages and its shell completions.

Quickstart

Check what Olympus found:

olympus doctor

It prints which backends are installed, which one answers and why, where its sessions live, and what each can do. It never fails: when nothing is installed, explaining that is its job.

Then start a session and run something in it:

olympus start build
olympus run build 'echo hello from a real terminal'
olympus screen build
olympus stop build

build is a name you choose.

Three doors, one vocabulary

Every operation has one name, one set of options and one result shape. The CLI verb, the Go method and the MCP tool are three spellings of the same thing. docs/api.md §1 has the full table.

The CLI
olympus start build --dir /repo
olympus send build 'make test'        # types it, confirms it landed, submits it
olympus wait build 'ok|FAIL'          # block until the output says something
olympus screen build api docs         # several sessions in one call
olympus run 'go build ./...'          # no target: a throwaway session
olympus agents                        # coding agents in panes, with status
olympus attach build                  # hand this terminal over

olympus --help lists every verb, and each verb's --help explains the parts that are not obvious. Add --json to any verb for a stable envelope:

olympus ls --json | jq '.data[].name'
The Go package
ol, err := olympus.Open()
defer ol.Close()

s, err := ol.Session(ctx, "build", olympus.In("/repo"))

res, err := s.Exec(ctx, "go test ./...")
fmt.Println(res.ExitCode, res.Output)

job, err := s.Start(ctx, "make deploy")   // detached
status, err := job.Poll(ctx)

if errors.Is(err, olympus.ErrNotFound) { … }

Session is create-or-reuse, so there is no separate "does it exist yet" step.

The MCP server
{
  "mcpServers": {
    "olympus": { "command": "olympus", "args": ["mcp"] }
  }
}

olympus mcp serves over stdio only. It targets MCP revision 2026-07-28 and still answers clients that use the older initialize handshake.

Things worth knowing

Sessions belong to a backend

A session created on zmx is invisible from tmux, and the reverse. Sessions never migrate. olympus doctor and every --json envelope say which backend answered.

The backends are not equivalent
zmx tmux meja herdr
Views no yes no no
Corpse on exit no yes no no
Server environment no yes no no
Control keys no yes yes yes
Start on a command yes yes yes no

zmx is the default and the least capable. herdr panes run the shell its own configuration names, so start <name> -- <command> is refused there rather than typed into a shell.

olympus doctor shows the full capability matrix, and olympus capabilities shows it for the backend in use.

Typing and submitting are separate

type places text without pressing Enter. send confirms the text landed on screen, then submits it.

A failing command is not an error

olympus run reports the command's own exit code. With --json it is in data.exit_code and the process exits 0. Without --json the process exits with the command's status, so it composes in a pipeline.

run needs a shell

run marks a command's start and end with shell syntax, so pointed at a REPL it times out. Drive a REPL or a full-screen program with send, press and wait, and read it with screen.

Wait for the program, not your prompt

wait matches per line. A pattern like '\$\s*$' matches only your own prompt and fails under zsh, fish or a themed prompt. Match what the command prints, and never require a trailing space: ^>>>\s*$, not ^>>> $.

Full-screen programs need control keys

Every backend captures a full-screen program as it currently looks. zmx does not deliver control keys reliably, so an editor there can be typed into but not saved or exited. olympus capabilities reports this as control_keys.

Where sessions live differs
  • tmux and herdr: Olympus uses its own socket, so its sessions do not appear in your own tmux ls or herdr.
  • zmx: sessions are global to your daemon and appear in zmx list.
  • meja: your default profile, so sessions appear in meja ls, unless you pass --socket-path.

olympus doctor states which is in effect.

Servers are the level above sessions

olympus servers lists the servers a backend can see, and --server <name> points any verb that addresses a backend at one. olympus servers stop <name> takes one down with every session on it. meja cannot enumerate its servers.

Agents are found in panes

olympus agents lists the coding agents running in panes, on every backend, with status working, idle, blocked or unknown. olympus kinds lists the agents it knows and the executables each is matched on.

herdr maps onto sessions, windows and panes

A herdr workspace is a session, a tab is a window and a pane is a pane. Point --socket-path at a herdr you already run to list, drive and attach to its panes. See spec §3.6.

Your tmux config still applies

A private socket is not a private configuration: your tmux.conf reaches Olympus's sessions. On servers it starts, Olympus pins only default-command and history-limit, and doctor names both. See spec §17.5.

Exit codes

Code Meaning
0 success
1 something unexpected; retrying will not help
2 usage: one corrected argument fixes it
3 the session or pane does not exist
4 the backend could not be reached
5 timed out
6 someone else holds the session
7 the backend has no such concept
8 a send was refused because the agent is waiting on a person; nothing was submitted

Two verbs differ, and say so in their --help: run reports the command's exit code, and attach reports the multiplexer client's.

Learn more

If you want to Read
Know how Olympus drives a multiplexer docs/terminal-behavior.md
Know the contract the three doors share docs/api.md
Add a backend docs/adding-a-backend.md
Build, test or contribute CONTRIBUTING.md and CLAUDE.md
See what is still outstanding docs/known-issues.md
See what changed in each release CHANGELOG.md

If you are an AI agent helping someone with Olympus

  • Run olympus doctor first. It says which backend answers and what that backend cannot do. Do not assume tmux behavior on zmx.
  • Read skills/olympus/SKILL.md for which verb fits which situation, and the traps. With Claude Code, copy the directory to ~/.claude/skills/olympus/.
  • Use --help on the verb you need. It matches the installed build.
  • Use --json whenever you parse output. Human output may change in any release.
  • Before changing code, read CLAUDE.md and the section of docs/terminal-behavior.md you touch.

Status

Pre-1.0. The --json envelope, the error codes, the CLI verb and flag names and the MCP tool and parameter names are semver-bound: additive only, never repurposed or removed within a major version. Human-readable output is not stable.

License

MIT. See LICENSE.

Agent status manifests under internal/agentstate/manifests/ are herdr's, Apache 2.0, © herdr authors, with the license text beside them and the vendored commit recorded in NOTICE.

Documentation

Overview

Package olympus drives real terminal sessions on top of a multiplexer it does not embed.

It is the ergonomic layer: the place where defaults are decided, once (behavior §17.3). The mechanical contract lives in package backend, and the rules both layers implement are specified in docs/terminal-behavior.md.

Index

Constants

View Source
const (
	// DefaultCols and DefaultRows size a session that does not ask.
	DefaultCols = 80
	DefaultRows = 24

	// DefaultRunTimeout bounds a synchronous run.
	DefaultRunTimeout = 60 * time.Second
	// DefaultRunPoll is how often a run checks for its completion marker.
	DefaultRunPoll = 250 * time.Millisecond

	// DefaultWaitTimeout and DefaultWaitPoll bound waiting for a pattern.
	DefaultWaitTimeout = 30 * time.Second
	DefaultWaitPoll    = 250 * time.Millisecond

	// DefaultVerifyBudget is ONE attempt's window; a verified send spends it
	// twice before failing.
	DefaultVerifyBudget = 5 * time.Second
	DefaultVerifyPoll   = 100 * time.Millisecond

	// DefaultScrollLines is how far a view scrolls when the caller does not
	// say.
	DefaultScrollLines = 10

	// DefaultLockWait is how long a writer waits for a contended session
	// before reporting a conflict.
	DefaultLockWait = 10 * time.Second

	// LockWaitEnv overrides DefaultLockWait, read at call time.
	LockWaitEnv = "OLYMPUS_LOCK_WAIT"
)

The default values of behavior §17.3.

ONE place decides these. A door that invents its own has created a second contract, and the two will drift — so the CLI, the MCP server and the library all read them from here rather than each having an opinion.

Two are per-attempt rather than total, and the distinction is not cosmetic: the verified-send budget is spent TWICE (§7.4), and the graceful-kill timeout bounds only the poll phase, so total wall time there is presses*gap + timeout (§2.8).

View Source
const BackendEnv = "OLYMPUS_BACKEND"

BackendEnv names the environment variable that selects a backend.

View Source
const WarningDegraded = "DEGRADED"

WarningDegraded is the code every degraded-operation disclosure carries.

Variables

View Source
var (
	ErrUsage       = backend.ErrUsage
	ErrNotFound    = backend.ErrNotFound
	ErrUnavailable = backend.ErrUnavailable
	ErrTimeout     = backend.ErrTimeout
	ErrConflict    = backend.ErrConflict
	ErrUnsupported = backend.ErrUnsupported
	ErrBlocked     = backend.ErrBlocked
)

The typed errors of api §3, re-exported so a caller never has to import the mechanical layer just to branch on a failure.

View Source
var Version = devVersion

Version is the one literal every door reports: the CLI verb, the MCP tool, and the MCP server's own identity. Sharing it is what stops two doors disagreeing about what is running.

A var rather than a const so the release can stamp the tag into it. It was a const, and the release configuration injected nothing — which meant every published binary would have reported this development placeholder whatever version it actually was. api §7 makes this the literal a consumer floor-checks against, so a wrong answer here is not cosmetic: it breaks the one check a client has, and it puts the wrong version on every bug report.

Treat it as read-only. It is a var for the linker's benefit, not the caller's.

Functions

func CodeOf

func CodeOf(err error) backend.Code

CodeOf classifies any error into the semver-bound vocabulary of §12.

func ExitCode

func ExitCode(code backend.Code) int

ExitCode maps a code to its process exit status.

func Kinds added in v0.14.0

func Kinds() []backend.AgentKind

Kinds is the agent vocabulary: every canonical name the agent listing can report, with the tokens that identify it, in alphabetical order by name (behavior §3.7).

It is a package-level function rather than a method for the same reason Self is one: the answer does not depend on how a caller configured a handle. The vocabulary is Olympus's own table, identical on every backend and readable with no multiplexer installed at all, so requiring a resolved backend would invent a dependency the answer does not have — and would make the verb fail on exactly the machine where a caller is trying to find out what Olympus knows.

Both lists are derived from the detection tables themselves, so the verb cannot disagree with detection: there is no second list to keep in step. Executables carry the canonical spelling first and the remaining aliases sorted, since a map has no order to preserve. Muse's versioned launcher (`muse-bin-<version>`) is a shape rather than a token, so it is not enumerable here.

func ResolvedBackendOf added in v0.34.0

func ResolvedBackendOf(err error) (backend.Name, bool)

ResolvedBackendOf reports the backend Open had resolved before it failed. It reports false for a failure that came before any backend was chosen.

func TypedOf added in v0.29.0

func TypedOf(err error) bool

TypedOf reports whether a send refused as AGENT_BLOCKED had already typed its text (behavior §7.5).

Types

type AgentOption added in v0.17.0

type AgentOption func(*agentOpts)

An AgentOption asks the listing for something beyond the row itself.

func WithLast added in v0.17.0

func WithLast() AgentOption

WithLast fills each row's Last: the one line of its own output the agent row stands for. Opt-in, because it is not free — a row whose status came from the backend was never captured, and this captures it, one call per row. A caller that only wants to know what is running should not pay for a caller that wants to know what it said.

type AttachOption

type AttachOption func(*backend.AttachSpec)

An AttachOption configures Attach.

func AsBare added in v0.2.5

func AsBare() AttachOption

AsBare asks for a plain pane with no chrome. What it means depends on the backend, and both meanings are decided here rather than in a door:

  • herdr: the session client with its chrome hidden. It implies WithSessionClient, since chrome is the session client's to hide, and the target is the same workspace, tab or pane any other verb takes.
  • tmux: a view (behavior §9) onto the session, attached instead of the session itself and killed when the attach ends. A view is already bare by construction — no status bar, no prefix (§9.3) — and a grouped session keeps its own current window, so the target may be `<session>:<window>` to show one window without moving anybody else's. The window is an index or a name; `<session>` alone shows whatever the base is showing.

zmx and meja have neither a chrome-drawing client nor views, so a bare attach is refused there as unsupported.

func AsViewer

func AsViewer() AttachOption

AsViewer attaches read-only.

On a backend with one shared PTY per session this drops resize as well as input: a viewer's resize physically resizes the driver's terminal, which is a real disruption rather than a self-contained no-op (behavior §8.7).

func AttachSize

func AttachSize(cols, rows int) AttachOption

AttachSize sets the PTY's initial size, for a caller whose stdin is not a terminal and therefore carries no window to inherit one from.

func BareClientTag added in v0.26.0

func BareClientTag(tag string) AttachOption

BareClientTag names the client a bare attach launches on herdr, rather than letting Olympus generate a tag. A caller that asks where its client is while the attach runs — Clients with WithClientTag — needs its name, and an attach, being interactive, has no channel to report one back. The tag is one to 128 bytes with no control character, and it takes a herdr server that advertises `client_view_focus`, the only one that launches a client with a tag (behavior §8.10). Anything else — another backend, an attach that is not bare, a server without the capability, a malformed tag — is refused as usage before a client exists.

func BareViewName added in v0.5.0

func BareViewName(name string) AttachOption

BareViewName names the view a bare attach on tmux creates, rather than letting Olympus generate one. A caller that drives the view while the attach runs — `view scroll`, `view focus` — needs its name, and an attach, being interactive, has no channel to report one back. The name must carry the reserved view prefix (behavior §17.1); anything else is refused as usage before a view exists, and so is the option on a backend whose bare attach makes no view.

func BareWithoutMouse added in v0.5.0

func BareWithoutMouse() AttachOption

BareWithoutMouse creates the bare attach's view without mouse reporting, for a client that keeps its own text selection and scrolls the view through `view scroll` instead. Usage on a backend whose bare attach makes no view.

func KeepOtherClients

func KeepOtherClients() AttachOption

KeepOtherClients opts out of displacing prior clients.

Superseding is the default, mirroring what attaching to a multiplexer has always done; opting out is the explicit choice (behavior §8.4).

func WithSessionClient added in v0.2.5

func WithSessionClient() AttachOption

WithSessionClient asks for the multiplexer's own session client — its own UI, with selection, scrollback and copy — rather than a raw per-pane stream.

Only herdr distinguishes the two; the other backends always hand their session client, so this is a no-op there and Attach rejects it on a backend that has no separate session client. The target is an ordinary Olympus target — a workspace, a tab or a pane (behavior §3.6) — and the client is steered onto it before it is spawned (§8.10).

type BackendReport

type BackendReport struct {
	Name         backend.Name         `json:"name"`
	Installed    bool                 `json:"installed"`
	Version      string               `json:"version,omitempty"`
	Floor        string               `json:"floor"`
	BelowFloor   bool                 `json:"below_floor"`
	Capabilities backend.Capabilities `json:"capabilities"`
	// Isolation says where this backend's sessions live, because the posture
	// differs sharply between backends and a user who learns one will be
	// surprised by the other (behavior §17.2).
	Isolation string `json:"isolation"`
	// Problem explains why a backend that is on PATH could not be asked its
	// version.
	//
	// "On PATH" and "runnable" are different things, and a version-manager shim
	// left behind by an uninstalled tool is the case that proves it: it
	// satisfies a lookup and fails every call. Resolution stays a single lookup
	// with no subprocess (§0.2) and so cannot tell the difference; the
	// diagnostic already spends subprocesses and explaining exactly this is its
	// job. An empty version alone left the reader to guess between "not
	// runnable", "too slow to answer" and "never asked".
	Problem string `json:"problem,omitempty"`
	// Managed is every option Olympus pins on servers it starts, overriding
	// whatever the operator's configuration says.
	//
	// Disclosed rather than merely done. A socket of our own is not a
	// configuration of our own — the operator's tmux.conf reaches our sessions
	// — so a handful of options the protocol's correctness rests on are pinned
	// back. Doing that silently turns "my tmux.conf is being ignored" into an
	// unanswerable question, which is the exact failure this diagnostic exists
	// to prevent (behavior §17.5).
	Managed map[string]string `json:"managed_options,omitempty"`
}

A BackendReport is one backend's entry in the diagnostic.

type ClientsOption added in v0.26.0

type ClientsOption func(*clientsOpts)

A ClientsOption narrows the client listing.

func WithClientTag added in v0.26.0

func WithClientTag(tag string) ClientsOption

WithClientTag narrows the listing to the client carrying a tag: the one a caller gave its own bare attach with BareClientTag. No client carrying it is not-found, so a caller can tell "my client is not there" from "it is there, showing nothing".

type Diagnosis

type Diagnosis struct {
	Resolved     ResolvedReport  `json:"resolved"`
	Backends     []BackendReport `json:"backends"`
	InstallHints []string        `json:"install_hints"`
}

A Diagnosis is the whole diagnostic.

It is a first-class part of the contract, not a debugging aid: it is what every backend-unavailable error points at, and it is what turns "it does not work on my machine" into one command's output (behavior §0.6).

func Diagnose

func Diagnose(ctx context.Context, opts ...Option) Diagnosis

Diagnose reports the environment, without side effects.

It deliberately returns no error. A diagnostic that fails when nothing is installed is useless at exactly the moment it is most needed — that is the case it exists to explain.

type ExitReading added in v0.34.0

type ExitReading struct {
	Found    bool      `json:"found"`
	ExitCode *int      `json:"exit_code,omitempty"`
	Warnings []Warning `json:"-"`
}

An ExitReading is a completion marker read off the screen. It marshals to the exit-status payload (api §5), with ExitCode absent when the marker was not found.

type Identity

type Identity struct {
	// Inside is false when nothing in the environment claims this process.
	Inside bool `json:"inside"`
	// Backend is which multiplexer owns the session.
	Backend backend.Name `json:"backend,omitempty"`
	// Session is the session's name.
	Session string `json:"session,omitempty"`
	// Scope is the socket or directory the session lives on, which is what a
	// caller needs in order to address it from outside.
	Scope string `json:"scope,omitempty"`
	// Nested names every backend whose environment claims this process, and is
	// set only when more than one does. Backend, Session and Scope are then
	// left empty: any single answer would be a guess.
	Nested []backend.Name `json:"nested,omitempty"`
}

An Identity is what a process running inside a session can learn about where it is.

func Self

func Self(ctx context.Context) (Identity, error)

Self reports which session the CURRENT PROCESS is running inside.

It is a package-level function rather than a method because the answer does not depend on how a caller configured a handle: a handle pointed at one socket cannot change which session its own process is sitting in. Asking through a handle would invite exactly that confusion.

The use it exists for is a program telling another program where to reach it — "reply into this session" — which is impossible if a process cannot name its own.

type Info

type Info struct {
	// State is present, absent, or error. Absent is a real answer, not a
	// failure: collapsing it into an error would destroy the distinction a
	// reconciling caller needs between "definitely gone" and "could not ask"
	// (behavior §3.5).
	State backend.State `json:"state"`
	// Session and Panes are omitted when the target is not present.
	Session      *backend.Session     `json:"session,omitempty"`
	Panes        []backend.Pane       `json:"panes,omitempty"`
	Capabilities backend.Capabilities `json:"capabilities"`
	// Prefix is the prefix key of the server the session is on, in tmux's
	// spelling, for a present session on a backend that has one (§13.3).
	Prefix   string    `json:"prefix,omitempty"`
	Warnings []Warning `json:"-"`
}

An Info is a session's detail, and answers presence as a tri-state.

func (Info) MarshalJSON

func (i Info) MarshalJSON() ([]byte, error)

MarshalJSON keeps `panes` an array whenever the target is present.

`omitempty` alone conflates two different answers with the same key: a present session whose pane list came back empty — a listing racing a kill (§3.3) — and an absent target that has no panes to report. §5 shows `panes` as an array on the present shape, and a consumer iterating it without a guard is the normal way to write that, so the key disappearing underneath a present state is a crash on the rarest path.

Absent and error still omit it, along with `session`: there, the absence is the answer.

type Job

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

A Job is a detached run.

It holds no state of its own beyond the pair that identifies it. Nothing durable is written: the id is baked into the sentinel markers, and polling re-scans the scrollback for them. The scrollback IS the state (behavior §6.7).

func (*Job) ID

func (j *Job) ID() string

ID reports the run identifier. A caller resumes solely by re-presenting it with the target.

func (*Job) Poll

func (j *Job) Poll(ctx context.Context, opts ...RunOption) (PollResult, error)

Poll reports whether a detached run has finished.

It never takes the write lock, and it answers about the COMMAND rather than about the backend: a target that never existed and one that vanished are indistinguishable from a read-only vantage point, so both answer died (behavior §6.8).

type Olympus

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

An Olympus is a resolved backend plus the decisions made once around it.

func Open

func Open(opts ...Option) (*Olympus, error)

Open resolves a backend, proves it exists, and returns a handle.

The preflight happens HERE rather than at the first operation, so a missing backend fails with an actionable error at the point the caller can still do something about it (behavior §0.2).

func (*Olympus) Agents added in v0.10.0

func (o *Olympus) Agents(ctx context.Context, opts ...AgentOption) ([]backend.Agent, error)

Agents lists the agents running in panes on the resolved backend.

Every backend answers; this is never unsupported. A backend that detects agents itself (backend.AgentLister) reports rows with a status and a title, marked `status_source: "native"`. Everywhere else the rows are derived from the pane listing: a pane whose process subtree, or failing a known pid its foreground command, names a known agent is an agent, with `detected_by: "command"`, and its status is read off a capture of the pane by the agent's manifest, marked `status_source: "screen"`. A screen no rule recognises, an agent with no manifest, a capture that fails: all unknown, with no source — the listing MUST NOT invent a state it cannot see (behavior §3.7).

WithLast asks for one more thing per row and costs one capture per row to answer; see its own documentation.

func (*Olympus) Backend

func (o *Olympus) Backend() backend.Name

Backend reports the RESOLVED backend, which is what every door must disclose.

func (*Olympus) Capabilities

func (o *Olympus) Capabilities() backend.Capabilities

Capabilities reports the resolved backend's static facts, so a caller can feature-probe rather than branch on an unsupported error.

func (*Olympus) Clients added in v0.26.0

func (o *Olympus) Clients(ctx context.Context, opts ...ClientsOption) ([]backend.Client, error)

Clients lists the clients attached to the server this handle addresses, and what each shows: the session, window and pane (behavior §13.5).

It answers where a server keeps a view per client and says where each is. A backend without a listing, and a server that cannot say (a herdr that does not advertise `client_view_focus`), answer unsupported, distinct from an empty list. No server running is an empty list.

func (*Olympus) Close

func (o *Olympus) Close() error

Close releases what Open acquired. There is no daemon and no persistent state, so this exists for symmetry and for future-proofing rather than because anything is currently held open.

func (*Olympus) Create

func (o *Olympus) Create(ctx context.Context, name string, opts ...SessionOption) (*Session, error)

Create makes a NEW session and fails if the name is taken.

This is deliberately distinct from Session, which is ensure-semantics. Most callers want ensure — that is why it has the shorter name and the `start` verb — but a caller that means "this must not already exist" cannot express it through ensure, and finding out by reading the outcome afterwards is a race rather than a check.

func (*Olympus) CreateView

func (o *Olympus) CreateView(ctx context.Context, base string, opts ...ViewOption) (backend.View, error)

CreateView adds an independently-scrollable view onto an existing session.

A backend with no view concept answers unsupported — distinct from unavailable, and distinct from an empty result. Feature-probe Capabilities rather than branching on the error.

On a backend that does support views this is NOT a side-effect-free read: it defines a server-global key table (behavior §9.3). That table is inert to every session not pointing at it, so it does not change what an operator's own sessions do on a server Olympus is merely aimed at.

func (*Olympus) Focus added in v0.6.0

func (o *Olympus) Focus(ctx context.Context, target string) error

Focus steers the server's focus onto a target: the workspace, tab or pane its clients show (behavior §8.10).

It exists for a caller holding several clients onto several targets of one server. Each client shows the server's ONE focus, so the last attach steered wins for all of them, and bringing a client to the front means steering the server again — which is this, without attaching anything.

The target reaches the backend AS GIVEN, not resolved to its session: the point is precision below the session — a window, a pane — which §10.1's session-scoped resolution would discard. Presence is still gated through the resolved session, so a target that names nothing is not-found here rather than whatever the backend prints. A backend whose clients each select their own view has nothing to steer and answers unsupported; feature-probe Capabilities.Focus.

func (*Olympus) FocusView added in v0.4.4

func (o *Olympus) FocusView(ctx context.Context, view string, col, row int) (string, error)

FocusView selects the pane of a view's current window that contains the cell (col, row), 0-based within the client area, and reports its id.

A view attached with mouse reporting off never delivers a click to the multiplexer, so this is how a caller that knows the clicked cell moves the active pane. The active pane is the shared window's (behavior §9.4), so the base follows. A cell on a border or outside every pane selects nothing and reports an empty id, which is a real answer rather than an error. The view is resolved like every other target (§10).

func (*Olympus) Info

func (o *Olympus) Info(ctx context.Context, target string) (Info, error)

Info reports a session's detail. It MUST NOT error on an absent target: this is the only door onto the presence tri-state, so it has to preserve it.

func (*Olympus) Open

func (o *Olympus) Open(ctx context.Context, target string) (*Session, error)

Attach returns a handle to an existing session without creating anything.

Unlike Session it does not ensure: it is for a caller that already knows the session exists and does not want to bring one into being by asking about it.

func (*Olympus) OpenSessionName added in v0.2.5

func (o *Olympus) OpenSessionName(name string) *Session

OpenSessionName returns a handle addressing a backend session by its own name, WITHOUT resolving a target or probing Olympus's pane registry.

It exists for the bare attach on tmux, whose target is `<session>:<window>` — not a session, so the ordinary Open would reject it before the ergonomic layer could split it, resolve the session half and report a missing session or window itself (§8.9). It brings nothing into being.

func (*Olympus) PaneWarnings

func (o *Olympus) PaneWarnings() []Warning

PaneWarnings are the disclosures that apply to any pane listing.

func (*Olympus) Panes

func (o *Olympus) Panes(ctx context.Context, target string) ([]backend.Pane, error)

Panes lists panes: every pane on the backend when target is empty, or one session's when it is not.

Listing every pane is a different question from asking about one session, and a caller reconciling state needs it: a pane id is the only handle some consumers hold, and resolving one requires seeing them all.

func (*Olympus) Raw

func (o *Olympus) Raw() backend.Backend

Raw exposes the mechanical backend, for a caller that needs an operation this layer does not wrap. Everything this layer decides — defaults, locking, resolution — is bypassed by going through it.

func (*Olympus) Rename added in v0.7.0

func (o *Olympus) Rename(ctx context.Context, target, name string) error

Rename gives a target a new name in place (behavior §2.11): a session, or a window, tab or pane where the backend names those too.

The target reaches the backend AS GIVEN, as Focus does: the point is the level below the session that §10.1's resolution would discard. Presence is gated through the resolved session first, so a target naming nothing is not-found here. A backend whose names are fixed at creation answers unsupported; feature-probe Capabilities.Rename.

func (*Olympus) Resolution

func (o *Olympus) Resolution() Resolution

Resolution reports the resolved backend and the rule that chose it.

func (*Olympus) RunOnce

func (o *Olympus) RunOnce(ctx context.Context, command string, run []RunOption, session ...SessionOption) (Result, []Warning, error)

RunOnce runs a command in a session created for it and killed afterwards (behavior §6.10).

The session is killed on success, failure and timeout alike — a throwaway that only gets cleaned up on the happy path is a leak with extra steps.

A cleanup failure MUST NOT override the run's own result. It comes back as a warning instead: a session that failed to clean up is a leak to notice separately, not a reason to hide the answer the caller actually asked for.

Two different things are configurable here and the signature names both rather than making a caller guess which one a single variadic shapes: run bounds the run itself — the timeout above all — and session shapes the session created to hold it. A throwaway that silently dropped the run's own timeout would run every command on the default budget while reporting the caller's.

func (*Olympus) Screens

func (o *Olympus) Screens(ctx context.Context, targets []string, opts ...ScreenOption) (Screens, error)

Capture reads several targets in one call.

A pane on the alternate screen — a full-screen application — IS captured, and its visible grid is exactly what a caller driving that application needs. What the alternate screen genuinely lacks is scrollback, so a history request against one cannot be honoured and says so through a warning rather than by quietly returning less than was asked for (behavior §5.3).

func (*Olympus) ScrollView

func (o *Olympus) ScrollView(ctx context.Context, view string, lines int) error

ScrollView moves a view back into its history, leaving its base untouched.

The view is resolved like every other target (behavior §10). A view is a session, so a caller holding its pane id can address it the way they address any other — and this was the one target method that handed its argument straight to the backend instead.

func (*Olympus) ServerEnv

func (o *Olympus) ServerEnv(ctx context.Context, key string) (string, bool, error)

ServerEnv reads a key from the multiplexer server's global environment.

An unset key is a real negative answer — present false, no error — and is not the same as a backend with no such concept, which is unsupported (behavior §12).

func (*Olympus) Servers added in v0.3.0

func (o *Olympus) Servers(ctx context.Context) ([]backend.Server, error)

Servers lists the resolved backend's servers.

A backend that cannot enumerate them answers unsupported — distinct from unavailable, and distinct from an empty list. Feature-probe Capabilities.Servers rather than branching on the error.

func (*Olympus) Session

func (o *Olympus) Session(ctx context.Context, name string, opts ...SessionOption) (*Session, error)

Session makes a named session exist and be alive, and returns a handle.

This is ensure-semantics, matching the `start` verb: create, reuse, or replace-if-dead. There is deliberately no separate create-versus-open decision for a caller to get wrong.

func (*Olympus) Sessions

func (o *Olympus) Sessions(ctx context.Context) ([]backend.Session, error)

Sessions lists every session on the resolved backend.

Sessions are backend-scoped: this never includes sessions on another backend, because they are genuinely different sessions that cannot be addressed from here (behavior §0.4). Sessions lists the sessions a caller can address. Views are left out: a view is scaffolding Olympus built over a session (behavior §9.5), carries the reserved name shape of §17.1 so it can be told apart, and is enumerated by Views instead. Listing it here invites attaching a view onto a view.

func (*Olympus) SizeWarnings

func (o *Olympus) SizeWarnings() []Warning

SizeWarnings are the disclosures that apply to asking for a session size.

Exposed on the handle rather than returned from Create because a caller often wants to know BEFORE creating anything — the answer is a property of the resolved backend, not of any one session — and because Create already returns a Session rather than a result envelope. Feature-probing Capabilities is the other half: the capability says whether to ask, this says what happened.

func (*Olympus) StartServer added in v0.18.0

func (o *Olympus) StartServer(ctx context.Context, name string) (StartedServer, error)

StartServer brings one server up, without creating a session on it. An empty name means the backend's default row.

It exists for the machine that has just come back: a backend that restores what it was running does that when its server boots, and every other verb here refuses to boot one on purpose — a listing that started what it was asked to list would answer with a thing it had made (§13.4). This is the one verb that says come up, and it says only that.

A server that already answers is reported running and is left entirely alone: not restarted, not reconfigured, not claimed.

func (*Olympus) Stop

func (o *Olympus) Stop(ctx context.Context, target string, opts ...StopOption) (Stopped, error)

Stop ends a session by name, for a caller that does not hold a handle.

func (*Olympus) StopServer added in v0.3.0

func (o *Olympus) StopServer(ctx context.Context, name string) (StoppedServer, error)

StopServer stops a server by name, with every session on it.

The name is checked against the listing first, so an unknown name is not-found rather than whatever the multiplexer prints, and a server that is not running is reported gone without being told anything — the same idempotence Stop gives a session (behavior §2.8).

func (*Olympus) Views

func (o *Olympus) Views(ctx context.Context, base string) ([]backend.View, error)

Views lists views, for one base or for every session when base is empty.

type Option

type Option func(*config)

An Option configures Open.

func WithBackend

func WithBackend(name string) Option

WithBackend selects a backend explicitly. An explicit choice never falls back (behavior §0.3).

func WithLockWait

func WithLockWait(d time.Duration) Option

WithLockWait sets how long a writer waits for a contended session.

func WithServer added in v0.3.0

func WithServer(name string) Option

WithServer selects a server BY NAME for this handle — the level above sessions, where every backend can run several, each behind its own socket (behavior §13.2). Servers lists the names a backend answers to.

What a name resolves to is backend-local, and this option is the one place the resolution is decided: on tmux it is a socket name (`--socket`); on herdr it is one of the named sessions `herdr session list` reports, whose socket is looked up and addressed WITHOUT redirecting herdr's configuration and state; on zmx only "default" exists, since there is one directory; on meja it is unsupported, since nothing enumerates its profiles.

It is exclusive with WithSocket, WithSocketPath and WithZmxDir: a name and an explicit address are two answers to the same question, and letting one win silently would leave a caller on a server they did not mean.

func WithSocket

func WithSocket(name string) Option

WithSocket selects the tmux socket by NAME, which tmux resolves inside its own per-user directory. It has no meaning on other backends.

func WithSocketPath

func WithSocketPath(path string) Option

WithSocketPath selects the server socket by PATH, used verbatim. It applies to the tmux and meja backends, which both address a server that way.

A name lands in a directory shared with every other server the user runs; a path lets the socket live somewhere the caller controls — a project directory, a mounted volume, somewhere with tighter permissions. It is the counterpart to choosing a directory on a directory-addressed backend, and on tmux it overrides any name.

On meja and herdr it is the ONLY form offered. meja keeps a server's session recovery files beside its socket, so a named profile Olympus drove would leave persisted sessions in the operator's own store; herdr does the opposite, keeping them in its CONFIGURATION directory rather than beside the socket, so this option moves that directory too — pointing only the socket somewhere private would still have Olympus overwrite the operator's saved workspaces (§2.9).

func WithZmxDir

func WithZmxDir(dir string) Option

WithZmxDir selects the zmx socket directory. It has no meaning on other backends.

func WithoutLock

func WithoutLock() Option

WithoutLock disables the per-session write lock, for a caller that already serializes its own writes.

This must be an explicit choice. With it, two concurrent ensures of one name can both observe "absent" and both create, and the loser's outcome is backend-defined (behavior §2.6).

type PollResult

type PollResult struct {
	Status backend.Liveness `json:"-"`
	// State is pending, completed, or died.
	State string `json:"status"`
	// ExitCode is populated ONLY when completed, never a fake zero a naive
	// consumer could read as success. Branch on State first (behavior §6.7).
	ExitCode *int      `json:"exit_code,omitempty"`
	Output   string    `json:"output,omitempty"`
	Reason   string    `json:"reason,omitempty"`
	Warnings []Warning `json:"-"`
}

A PollResult is one poll of a detached run.

type Reason

type Reason string

A Reason names the resolution rule that applied, satisfying the disclosure requirement of behavior §0.4.

const (
	// ReasonFlag is an explicit selection: a flag, a library option, or an MCP
	// parameter.
	ReasonFlag Reason = "flag"
	// ReasonEnv is the environment variable.
	ReasonEnv Reason = "env"
	// ReasonDefault is the default, which was available.
	ReasonDefault Reason = "default"
	// ReasonFallback is the default being unavailable and another supported
	// backend being present.
	ReasonFallback Reason = "fallback"
)

type Resolution

type Resolution struct {
	Backend backend.Name
	Reason  Reason
}

A Resolution is which backend answered, and why.

The resolved backend — never the requested one — is what must be observable, because sessions are backend-scoped: they never migrate and never merge, and a session created on one backend is invisible from the other. A silent fallback would let a user create sessions, change their installed tooling, and find those sessions apparently vanished with nothing explaining why.

type ResolvedReport

type ResolvedReport struct {
	Backend backend.Name `json:"backend"`
	Reason  Reason       `json:"reason"`
	Scope   string       `json:"socket_or_dir"`
	// Pinned says whether Olympus configured the server answering right now.
	//
	// False means a server somebody else started. Olympus configures only
	// servers it starts, because pinning reaches every session on a server and
	// would change ones the caller never asked about (§17.5) — so on a found
	// server the settings below are whatever that server was given, and a
	// default-command among them can make a run report the wrong exit code.
	Pinned bool `json:"pinned"`
	// Effective is what the managed options are actually set to right now, as
	// opposed to what Olympus would pin. It is empty when no server is running.
	Effective map[string]string `json:"effective_options,omitempty"`
	// Problem explains why nothing resolved, when nothing did.
	Problem string `json:"problem,omitempty"`
}

A ResolvedReport is which backend answers right now, and why.

type Result

type Result struct {
	ExitCode int    `json:"exit_code"`
	Output   string `json:"output"`
	// Warnings never reaches the payload: the run's shape is semver-bound and
	// disclosure travels on the envelope, exactly as it does for a capture.
	Warnings []Warning `json:"-"`
}

A Result is a completed command.

type RunOption

type RunOption func(*engine.Runner)

A RunOption configures Exec and Start.

func PollWindow

func PollWindow(lines int) RunOption

PollWindow sets how deep into scrollback a detached poll looks for the completion marker. It is ignored where scrollback depth is the backend's own.

func RunInterval

func RunInterval(d time.Duration) RunOption

RunInterval sets how often a run checks for its completion marker. Zero or less leaves the default, rather than checking without a pause.

func RunTimeout

func RunTimeout(d time.Duration) RunOption

RunTimeout bounds how long a run waits for its command. Zero or less leaves the default, rather than timing the run out at once.

type Screen

type Screen struct {
	Text string             `json:"text"`
	Meta backend.ScreenMeta `json:"meta"`
	// Line is the first line that matched, on a result from WaitFor. A caller
	// waiting on a pattern almost always wants the line rather than the whole
	// screen, and finding it again themselves means re-implementing the match.
	Line     string    `json:"line,omitempty"`
	Matched  bool      `json:"matched,omitempty"`
	Warnings []Warning `json:"-"`
}

A Screen is a capture and what the text itself could not carry.

type ScreenOption

type ScreenOption func(*backend.ScreenOpts)

A ScreenOption configures Screen.

func WithColors

func WithColors() ScreenOption

WithColors keeps ANSI escapes in the captured text.

func WithHistory

func WithHistory(lines int) ScreenOption

WithHistory asks for scrollback above the visible screen.

type Screens

type Screens struct {
	Screens  map[string]string             `json:"screens"`
	Meta     map[string]backend.ScreenMeta `json:"meta"`
	Warnings []Warning                     `json:"-"`
}

Screens is a capture of several targets at once.

The two maps are parallel and keyed by target. A target on the alternate screen is captured like any other; its metadata says so, which is how a caller knows there is no scrollback behind the grid it was given.

func (Screens) MarshalJSON

func (s Screens) MarshalJSON() ([]byte, error)

MarshalJSON emits empty maps rather than nulls.

api §2 requires an empty collection to serialize as an empty collection, never null — and the case that forces this is the ZERO value, which is what a failing call hands back. A consumer indexing into the result must not have to nil-check a field the contract says is always an object.

type SendOption

type SendOption func(*sendConfig)

A SendOption configures a verified send.

func VerifyBudget

func VerifyBudget(d time.Duration) SendOption

VerifyBudget sets ONE attempt's window. A verified send spends it twice, so the worst case before failing is double this. Zero or less leaves the default, rather than failing every attempt at once.

func WithoutSubmit

func WithoutSubmit() SendOption

WithoutSubmit confirms the text landed but leaves it unsubmitted.

Verifying and submitting are independent: a caller may want the input line filled and left for a human, or for a terminator whose timing it controls itself.

type Session

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

A Session is a handle to one terminal session.

func (*Session) Attach

func (s *Session) Attach(ctx context.Context, in, out *os.File, errOut *os.File, opts ...AttachOption) (int, error)

Attach hands the caller's terminal to a session until the client exits, and returns the CLIENT's exit code.

Once the presence gate has passed this hands off, so the exit code follows the attach client's rather than Olympus's vocabulary: an attach exiting 3 is not necessarily not-found (behavior §12.1).

func (*Session) Exec

func (s *Session) Exec(ctx context.Context, command string, opts ...RunOption) (Result, error)

Exec runs a command and waits for it to finish.

A non-zero exit code is a RESULT, not an error: whether the protocol worked and what the command's own status was are two independent outcomes, and conflating them makes an ordinary failing command look like Olympus broke (behavior §12.1).

func (*Session) ExitStatus

func (s *Session) ExitStatus(ctx context.Context, marker string, lines int) (int, bool, error)

ExitStatus reads a caller-supplied completion marker off the screen.

The marker is always caller-supplied and there is deliberately no default: a fixed one would collide with ordinary output or stale scrollback, and weaken the caller-controlled uniqueness the design assumes (behavior §14).

It drops what the capture disclosed; ReadExitStatus is the same reading with its warnings kept.

func (*Session) Focus added in v0.6.0

func (s *Session) Focus(ctx context.Context) error

Focus steers the server onto this handle's target. A handle opened from a pane id on tmux addresses the owning session (§10.1), so a pane-precise focus there goes through Olympus.Focus with the id itself.

func (*Session) Name

func (s *Session) Name() string

Name reports the session's name.

func (*Session) Outcome

func (s *Session) Outcome() backend.Outcome

Outcome reports what Session did: created, reused, or reaped. It is empty for a handle that did not create anything.

func (*Session) Paste

func (s *Session) Paste(ctx context.Context, text string) error

Paste places multi-line text in the input line without submitting the final line.

Whether INTERMEDIATE lines execute is consumer-dependent and genuinely differs between backends (behavior §4.6). The cross-backend guarantee is only about the last line.

func (*Session) PasteAndSubmit

func (s *Session) PasteAndSubmit(ctx context.Context, text string) error

PasteAndSubmit pastes text and then submits the final line.

The two are one critical section, and the terminator is retried once. Once text is sitting in the input line, a failed terminator does not merely fail visibly — it leaves that text there, where the NEXT injection silently concatenates onto it and corrupts both (behavior §4.4).

func (*Session) Poll

func (s *Session) Poll(ctx context.Context, id string, opts ...RunOption) (PollResult, error)

Poll reports on a detached run by id, for a caller resuming from nothing but the pair.

func (*Session) Press

func (s *Session) Press(ctx context.Context, keys ...backend.Key) error

Press sends named keys.

func (*Session) ReadExitStatus added in v0.34.0

func (s *Session) ReadExitStatus(ctx context.Context, marker string, lines int) (ExitReading, error)

ReadExitStatus is ExitStatus with the capture's warnings kept, such as a history request clamped to the backend's ceiling (behavior §0.8).

func (*Session) Row

func (s *Session) Row() backend.Session

Row reports the session's listing row as of the handle's creation.

func (*Session) Screen

func (s *Session) Screen(ctx context.Context, opts ...ScreenOption) (Screen, error)

Screen reads the session's screen.

Reads never take the write lock. A read that blocks on a writer turns observation into contention, which is backwards: observing a busy session is the case that matters most (behavior §11.1).

func (*Session) Send

func (s *Session) Send(ctx context.Context, text string, opts ...SendOption) error

Send delivers text, waits until it is observed on screen, and only then submits it — holding the lock across all three (behavior §11.2).

Where the target holds an agent waiting on a person, or one that draws an input box and shows none, it types nothing and fails with ErrBlocked (§7.5), and where that agent draws an input box the echo is looked for inside it (§7.6).

func (*Session) SendAtomic

func (s *Session) SendAtomic(ctx context.Context, text string) error

SendAtomic delivers text and submits it as one caller-visible unit.

It does NOT verify: atomicity trades away the on-screen check. A caller needing both properties does not get them from one call — verify-then-submit cannot be atomic, because any cross-invocation retry re-types the text before checking and doubles it (behavior §4.7).

func (*Session) SetStatus

func (s *Session) SetStatus(ctx context.Context, status string) error

SetStatus records an opaque label on the session, for a process inside it to leave for whoever is driving it from outside.

Olympus never interprets the value, and deliberately defines no vocabulary of states. What counts as "busy" or "waiting" is a property of the program in the session, not of the terminal, and a fixed set would name the concerns of whatever is driving it rather than the thing being driven.

UNSUPPORTED on a backend with nowhere to keep it. That refusal is the point: silently accepting a write nobody can ever read back would leave a caller waiting forever for a state that cannot arrive.

func (*Session) Start

func (s *Session) Start(ctx context.Context, command string, opts ...RunOption) (*Job, error)

Start injects a command and returns without waiting.

func (*Session) Status

func (s *Session) Status(ctx context.Context) (string, error)

Status reports the session's label, empty when it has never been given one.

Empty is a real answer rather than an error, the same tri-state rule as presence (§3.5): a caller must be able to tell "has reported nothing" from "could not ask".

func (*Session) Stop

func (s *Session) Stop(ctx context.Context, opts ...StopOption) (Stopped, error)

Stop ends a session, trying to interrupt it before forcing.

func (*Session) Submit

func (s *Session) Submit(ctx context.Context) error

Submit sends the terminator alone.

func (*Session) Type

func (s *Session) Type(ctx context.Context, text string) error

Type places literal text in the input line WITHOUT submitting it.

Placing text and submitting it are separate operations on purpose: it keeps injection symmetric across backends and composable, and it means the retry discipline for a failed terminator belongs to whoever issues it (behavior §4.3).

func (*Session) TypeAndSubmit added in v0.1.2

func (s *Session) TypeAndSubmit(ctx context.Context, text string) error

TypeAndSubmit places text and then submits it, as one critical section with the terminator retried once (behavior §4.4).

It exists because composing Type and Submit at a door is exactly what §4.4 forbids: two lock acquisitions with a gap between them, and an unretried terminator that leaves the text sitting in the input line for the next injection to concatenate onto. Type followed by Submit remains available for a caller that genuinely wants the two apart; a door offering "type and press Enter" as one verb goes through here.

func (*Session) WaitFor

func (s *Session) WaitFor(ctx context.Context, pattern string, opts ...WaitOption) (Screen, error)

WaitFor blocks until the session's screen matches a regular expression, and returns the screen that matched.

func (*Session) WaitForStatus

func (s *Session) WaitForStatus(ctx context.Context, want string, opts ...WaitOption) (string, error)

WaitForStatus blocks until the session reports exactly want.

Exactly, not a pattern: the value is opaque to Olympus, so a partial match would be Olympus reading structure into a string it has promised not to interpret. A caller who wants looser matching owns the vocabulary and can poll Status themselves.

It polls rather than subscribing because there is nothing to subscribe to: the status lives in the backend's own store, written by a process Olympus does not run, and no backend offers a change feed for it.

func (*Session) Watch

func (s *Session) Watch(ctx context.Context, out io.Writer) error

Watch streams a session's output to a writer until the context is cancelled or the session ends.

This is not Screen in a loop. A capture shows the pane as it looks NOW, so anything printed and scrolled away between two polls is gone — which is precisely the output someone following a long build cares about. Watching taps the byte stream instead.

What arrives is raw terminal output, escape sequences included. It is a stream rather than a picture: a caller that wants to match on content should capture or wait instead, and one that wants to render it should pass it to something that understands a terminal.

type SessionOption

type SessionOption func(*backend.CreateSpec)

A SessionOption configures Session.

func Command

func Command(argv ...string) SessionOption

Command spawns the session directly onto an argv rather than a login shell. It is executed, never typed (behavior §2.3).

func In

func In(dir string) SessionOption

In sets the session's working directory.

func KeepCorpse

func KeepCorpse() SessionOption

KeepCorpse leaves a dead session to inspect after its command exits. Backends with no corpse concept reject it as unsupported, before doing anything.

func Size

func Size(cols, rows int) SessionOption

Size sets the session's initial size. It is ignored by backends with no spawn-time sizing concept, which is documented rather than papered over (behavior §2.1). A zero on either side leaves that side's default.

type Started

type Started struct {
	CommandID string `json:"command_id"`
}

A Started is what starting a detached run reports: the identifier a caller re-presents to poll it.

It lives here rather than in a door because both doors mirror the ergonomic layer (§15.6). Each used to spell this shape for itself — the CLI through an anonymous map, MCP through a private struct — which is two independent definitions of one semver-bound payload, agreeing by coincidence and with nothing to notice if either drifted.

type StartedServer added in v0.18.0

type StartedServer struct {
	Name string `json:"name"`
	// Outcome is running (it was already up and was left alone) or started.
	// Both are successes, mirroring StopServer's vocabulary.
	Outcome string `json:"outcome"`
}

A StartedServer reports what starting a server actually did.

type StopOption

type StopOption func(*stopSettings)

A StopOption configures Stop.

func Force

func Force() StopOption

Force skips the graceful attempt entirely. It wins over Presses and InterruptTimeout whichever order they are given in.

func InterruptTimeout

func InterruptTimeout(d time.Duration) StopOption

InterruptTimeout bounds the POLL phase only, so total wall time is presses*gap plus this.

func Presses

func Presses(n int) StopOption

Presses sets how many interrupts to send before waiting.

type Stopped

type Stopped struct {
	// Outcome is gone, graceful, or killed. All three are successes.
	Outcome  string    `json:"outcome"`
	Warnings []Warning `json:"-"`
}

A Stopped reports how a session ended.

type StoppedServer added in v0.3.0

type StoppedServer struct {
	Name string `json:"name"`
	// Outcome is gone (it was not running) or killed. Both are successes,
	// mirroring Stop's vocabulary for a session.
	Outcome string `json:"outcome"`
}

A StoppedServer reports what stopping a server actually did.

type ViewOption

type ViewOption func(*backend.ViewSpec)

A ViewOption configures CreateView.

func WithViewName

func WithViewName(name string) ViewOption

WithViewName sets the view's name instead of generating one. The reserved prefix is still required: enumerating views selects on it.

func WithViewWindow added in v0.3.0

func WithViewWindow(window string) ViewOption

WithViewWindow pins the view to one of the base's windows, by index or by name, instead of the window the base is showing. A grouped session keeps its own current window, so the base and every other view stay where they were (behavior §9.4). A window the base does not have is not-found.

func WithoutMouse

func WithoutMouse() ViewOption

WithoutMouse creates a view whose wheel does not scroll into history.

Mouse is on by default because a view is for reading and a wheel that scrolls is the point of one — but it is per-view, since on another it is an unwanted mode change.

type WaitOption

type WaitOption func(*waitConfig)

A WaitOption configures WaitFor.

func WaitInterval

func WaitInterval(d time.Duration) WaitOption

WaitInterval sets how often the screen is re-read while waiting. A shorter interval catches output that is overwritten quickly; a longer one costs the backend less on a session nobody is in a hurry about. Zero or less leaves the default, rather than re-reading without a pause.

func WaitTimeout

func WaitTimeout(d time.Duration) WaitOption

WaitTimeout bounds how long to wait for a pattern.

type Warning

type Warning struct {
	Code    string `json:"code"`
	Message string `json:"message"`
}

A Warning is a disclosure attached to a successful result.

These are not errors — the operation returned something real — but a caller unaware of the difference draws a wrong conclusion from a success (behavior §0.8). They are distinct from UNSUPPORTED, which covers an operation the backend has no concept of and which returns nothing at all: failing these outright would make the default backend refuse work it can genuinely do.

Directories

Path Synopsis
Package backend defines the mechanical layer: the vocabulary every terminal multiplexer backend speaks, and the interface it implements.
Package backend defines the mechanical layer: the vocabulary every terminal multiplexer backend speaks, and the interface it implements.
backendtest
Package backendtest is the executable definition of a correct backend.
Package backendtest is the executable definition of a correct backend.
herdr
Package herdr drives herdr.
Package herdr drives herdr.
meja
Package meja drives the meja multiplexer.
Package meja drives the meja multiplexer.
tmux
Package tmux drives tmux.
Package tmux drives tmux.
zmx
Package zmx drives zmx.
Package zmx drives zmx.
cmd
olympus command
Command olympus drives real terminal sessions from the command line.
Command olympus drives real terminal sessions from the command line.
internal
agentstate
Package agentstate reads a coding agent's state off its screen.
Package agentstate reads a coding agent's state off its screen.
cli
Package cli is the command-line door.
Package cli is the command-line door.
engine
Package engine holds the backend-agnostic logic that sits above the Backend interface: the sentinel run protocol, verified delivery, the per-session write lock, idempotent ensure, graceful kill, and exit-marker inspection.
Package engine holds the backend-agnostic logic that sits above the Backend interface: the sentinel run protocol, verified delivery, the per-session write lock, idempotent ensure, graceful kill, and exit-marker inspection.
mcp
Package mcp is the MCP door: a stdio server on the official Go SDK.
Package mcp is the MCP door: a stdio server on the official Go SDK.
privatedir
Package privatedir holds Olympus's per-user directories under a shared temp root to one rule: a real directory this user owns, private to it (behavior §11.1).
Package privatedir holds Olympus's per-user directories under a shared temp root to one rule: a real directory this user owns, private to it (behavior §11.1).
testhome
Package testhome gives a test binary a HOME of its own (behavior §2.9).
Package testhome gives a test binary a HOME of its own (behavior §2.9).
tools
gendoc command
Command gendoc writes the CLI's manual pages and shell completions.
Command gendoc writes the CLI's manual pages and shell completions.

Jump to

Keyboard shortcuts

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