Help us shape the future of Go! Take the 2026 Go Developer Survey

agentvisor

package module
v0.4.3 Latest Latest
Warning

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

Go to latest
Published: Nov 2, 2026 License: MIT Imports: 38 Imported by: 0

README

agent-visor

agent-visor keeps agent and terminal sessions alive and lets you attach to them. It does not sandbox them.

It is a Go library and a process. It sits one layer above agent-wire. agent-wire drives one vendor CLI over its structured protocol and keeps no state. agent-visor holds many sessions on one machine, keeps their events in a log, and survives a restart of the product that uses it.

Status: early. The library core works in the process. The socket, the CLI, and the holders come next.

What it does

  • Starts agent sessions over agent-wire, vendor TUIs in a PTY, shells, and scripts.
  • Keeps each session in a holder process, so a session survives a visor upgrade.
  • Keeps an event log with a sequence number. A client that connects again reads the events that it missed.
  • Lets a client attach to a session as a terminal or as a chat view, and hand a session over between the two.
  • Finds projects from paths and manages workdirs: the main checkout, git worktrees, and plain folders.
  • Detects, installs, updates, and logs in to the harnesses (Claude Code, Codex, and others), and lists their models.
  • Takes hook calls from sessions that a user starts outside the visor, and shows them as observed sessions. A hook call can carry labels, which join it to a session of a backend.
  • Takes optional backends. backend/orca runs sessions in the terminals of the Orca app.
  • Upgrades itself when no session needs it.
  • Keeps a short frame log of each wire session with no stream fragments. When a stream fails, it keeps the fragments in fragments/<id>.ndjson for 30 days (Options.KeepFragments). It forgets an exited session after 7 days (Options.KeepExited).
  • Purge removes an ended session at once: its events and its files. With Harness and VendorID, it also removes the transcript that the vendor keeps for that session in the harness home of the visor.

How a product uses it

Each product runs its own visor. Each visor has its own home, socket, harness installs, and logins. The product talks to the visor over a Unix socket with Dial, or it runs a Visor in its own process for tests.

c, err := agentvisor.Ensure(ctx, svc) // install or start the service, then dial
s, err := c.Start(ctx, agentvisor.StartSpec{Harness: "claude", WorkingDir: dir, Prompt: "..."})
stream, err := c.Events(ctx, agentvisor.Filter{Session: s.ID}, 0)

The generic CLI agent-visor uses the same API.

Optional backends

A product registers an optional backend in Options.Backends. A backend can also find sessions that it did not start (Discoverer), list folders that become projects (Catalog), give labels to its sessions (Labeler), and give a text terminal (TextTerminal).

backend/orca drives the orca CLI of the Orca app:

  • Start opens a terminal in an Orca workspace and runs the agent command in it. The env goes in a start script with mode 0700, which removes itself. The label orca.worktree picks the workspace, and the label orca.shell types the command into a shell that is open.
  • The backend polls the agent cards of Orca. A card gives the state, the tool, the prompt, and the permission requests of the session.
  • Answer reads the prompt on the screen and types the choice. Screen, Keys, and Paste use the Orca terminal.
  • A visor restart keeps the sessions: the bindings stay in Options.Dir.
  • With Discover, the backend reports the agent panes that it did not start, and the visor adopts them.
  • A hook call from an Orca pane joins its session when the hook sends orca.HookLabels(os.Getenv).

The live test runs a script in a new Orca terminal and touches only that terminal:

ORCA_LIVE_DIR=$HOME/src/app go test -tags live -run TestLive ./backend/orca/

CLI

agent-visor runs the visor and drives it. The default home is ~/.agent-visor; AGENT_VISOR_HOME and --home change it. The socket is <home>/visor.sock unless --socket gives another path. --json prints JSON.

agent-visor serve &                      # run the visor in the foreground
agent-visor status
agent-visor ls                           # projects, workdirs, and sessions as a tree
agent-visor session start --harness claude --dir . --prompt "Fix the tests" --label app.task=t1
agent-visor session logs <id> --follow   # seq, type, and a short text for each event
agent-visor session answer <id> <request-id> --allow
agent-visor session stop <id>
agent-visor harness ls

A product mounts the same command tree under its own binary, with its own home and socket:

root.Commands = append(root.Commands, cli.Command(cli.Options{
	Name: "visor", Home: home, Build: version,
	Configure: func(ctx context.Context, o *agentvisor.Options) error { o.Env = env; return nil },
}))

Platforms

macOS and Linux. Windows is a later step.

License

MIT

Documentation

Overview

Package agentvisor keeps agent and terminal sessions alive on one machine and lets a product attach to them. It does not sandbox them.

Index

Constants

View Source
const (
	EnvSession = "AGENT_VISOR_SESSION"
	EnvWorkdir = "AGENT_VISOR_WORKDIR"
	EnvPort    = "AGENT_VISOR_PORT"
	EnvSocket  = "AGENT_VISOR_SOCKET"
)

Env keys that the visor adds to each session.

View Source
const (
	AuthShared   = harness.AuthShared
	AuthSeparate = harness.AuthSeparate
	SourceVisor  = harness.SourceVisor
	SourceSystem = harness.SourceSystem
	AuthUnknown  = harness.AuthUnknown
	AuthOK       = harness.AuthOK
	AuthMissing  = harness.AuthMissing
	AuthExpired  = harness.AuthExpired

	LoginStarting  = harness.LoginStarting
	LoginBrowser   = harness.LoginBrowser
	LoginCode      = harness.LoginCode
	LoginVerifying = harness.LoginVerifying
	LoginDone      = harness.LoginDone
	LoginFailed    = harness.LoginFailed

	UpdatesAuto = harness.UpdatesAuto
	UpdatesKeep = harness.UpdatesKeep

	SideUser      = harness.SideUser
	SideHome      = harness.SideHome
	OwnFromUser   = harness.OwnFromUser
	OwnFromEmpty  = harness.OwnFromEmpty
	OwnFromBackup = harness.OwnFromBackup
)

Auth modes, harness sources, and auth states.

View Source
const (
	HookInstalled = hooks.StateInstalled
	HookMissing   = hooks.StateMissing
	HookOutdated  = hooks.StateOutdated
	// HookUntrusted means that the vendor runs the hooks only after the user
	// trusts them in the vendor CLI.
	HookUntrusted = hooks.StateUntrusted
)

Hook states.

View Source
const (
	WorkdirMain     = workdir.KindMain
	WorkdirWorktree = workdir.KindWorktree
	WorkdirFolder   = workdir.KindFolder
	WorkdirActive   = workdir.Active
	WorkdirArchived = workdir.Archived
)

Workdir kinds and states.

View Source
const (
	// MaxInFlight is the binary bytes that a client that acks can have
	// without an ack. A client that never acks has no limit.
	MaxInFlight = 512 << 10
)

Flow rules of one attachment.

View Source
const Protocol = "agent-visor/1"

Protocol is the socket protocol version.

Variables

View Source
var (
	ErrNotFound    = errors.New("agentvisor: not found")
	ErrInvalid     = errors.New("agentvisor: invalid request")
	ErrState       = errors.New("agentvisor: wrong session state")
	ErrBusy        = errors.New("agentvisor: busy")
	ErrClosed      = errors.New("agentvisor: closed")
	ErrUnsupported = errors.New("agentvisor: not supported")
	// ErrProtocol means that the two sides speak socket protocols with a
	// different major version.
	ErrProtocol = errors.New("agentvisor: unknown protocol")
	// ErrStale is a write with an old etag.
	ErrStale = errors.New("agentvisor: changed since the read")
)

Errors. The client maps a socket error code back to the same error.

Functions

func Listen

func Listen(ctx context.Context, socket string) (net.Listener, error)

Listen opens the Unix socket with mode 0600. It removes a stale socket file, and it fails when a visor already listens on it.

func ParseLabel

func ParseLabel(s string) (string, string, error)

ParseLabel reads one k=v (or k:v) label selector.

func Serve

func Serve(ctx context.Context, v *Visor, socket string) error

Serve serves v on socket until ctx ends. The socket has mode 0600.

func ServeListener

func ServeListener(ctx context.Context, v *Visor, ln net.Listener) error

ServeListener serves v on ln until ctx ends. When an upgrade is ready, it writes visor.restarting, stops the server, closes v, and runs the new binary in this process. It returns only when that fails.

Types

type Answer

type Answer struct {
	Allow   bool   `json:"allow"`
	Message string `json:"message,omitempty"`
	// UpdatedInput replaces the tool input, when the harness takes it.
	UpdatedInput json.RawMessage `json:"updated_input,omitempty"`
}

Answer decides an open request.

type AttachOptions

type AttachOptions struct {
	View AttachView `json:"view,omitempty"`
	// Cols and Rows are the size of the client. A client that gives a size
	// takes the size lease when nobody holds it.
	Cols int `json:"cols,omitempty"`
	Rows int `json:"rows,omitempty"`
	// After is the event sequence after which the chat view starts.
	After uint64 `json:"after,omitempty"`
}

AttachOptions configures an attachment. The empty value attaches the terminal of a session that has one, else the chat.

type AttachStream

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

AttachStream is one client on the terminal or the chat of a session. One goroutine calls Recv; others can call Handle, Input, and Close.

func (*AttachStream) Close

func (a *AttachStream) Close() error

Close ends the attachment. It gives back the size lease.

func (*AttachStream) Handle

func (a *AttachStream) Handle(ctx context.Context, f ClientFrame) error

Handle applies one frame from the client. A failed frame also queues an error frame, so a server can ignore each error except ErrClosed. On a Client, Handle only sends the frame, and a failure comes as an error frame.

func (*AttachStream) Input

func (a *AttachStream) Input(ctx context.Context, p []byte) error

Input writes bytes to the terminal.

func (*AttachStream) Recv

func (a *AttachStream) Recv(ctx context.Context) (Frame, error)

Recv waits for the next frame to the client. After the ended frame, it returns io.EOF.

func (*AttachStream) View

func (a *AttachStream) View() AttachView

View is the view of the attachment.

type AttachView

type AttachView string

AttachView is what an attachment shows.

const (
	ViewTerminal AttachView = "terminal"
	ViewChat     AttachView = "chat"
)

Attach views.

type Attachment

type Attachment struct {
	MIME string `json:"mime"`
	Path string `json:"path,omitempty"`
	Data []byte `json:"data,omitempty"`
}

Attachment is a file or an image that goes with a turn. Data wins over Path.

type AuthMode

type AuthMode = harness.AuthMode

AuthMode tells which login a harness uses.

type AuthState

type AuthState = harness.AuthState

AuthState is the login state of a harness.

type Backend

type Backend interface {
	Kind() Kind
	Caps(harness string) Caps
	Start(ctx context.Context, l Launch) (Handle, error)
	// Recover gives the sessions that lived through a visor restart.
	Recover(ctx context.Context) ([]Handle, error)
	Close(ctx context.Context) error
}

Backend hosts sessions of one kind. A product can register more backends in Options.Backends.

type Caps

type Caps struct {
	// Structured means typed events: tools, requests, and results.
	Structured bool `json:"structured"`
	// Terminal means a terminal view that a client can attach to.
	Terminal bool `json:"terminal"`
	// Permissions means typed permission requests and answers.
	Permissions bool `json:"permissions"`
	// Steer means a send during a turn joins the turn.
	Steer bool `json:"steer"`
	// Resume means a stopped session can continue with its vendor id.
	Resume bool `json:"resume"`
	// Survives means the session lives through a visor restart.
	Survives bool `json:"survives"`
}

Caps tells what a backend can do for one harness.

type Catalog added in v0.3.0

type Catalog interface {
	Folders(ctx context.Context) ([]string, error)
}

Catalog is a backend that knows project folders, for example the repos of another app. The visor makes a project for each folder at boot.

type Client

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

Client talks to a visor in another process over its socket. It has the same method set as Visor.

func Dial

func Dial(ctx context.Context, socket string) (*Client, error)

Dial connects to the visor on socket and checks its protocol.

func (*Client) Answer

func (c *Client) Answer(ctx context.Context, id, requestID string, a Answer) error

Answer decides an open request.

func (*Client) ArchiveWorkdir

func (c *Client) ArchiveWorkdir(ctx context.Context, id string) error

ArchiveWorkdir stops the sessions of a workdir and archives it.

func (*Client) Attach

func (c *Client) Attach(ctx context.Context, id string, o AttachOptions) (*AttachStream, error)

Attach attaches to the terminal or the chat of a session.

func (*Client) CancelHarnessLogin added in v0.2.0

func (c *Client) CancelHarnessLogin(ctx context.Context, name string) error

CancelHarnessLogin stops a running login.

func (*Client) CheckHarnesses added in v0.2.0

func (c *Client) CheckHarnesses(ctx context.Context) error

CheckHarnesses looks for new releases now and applies the update modes.

func (*Client) Close

func (c *Client) Close(context.Context) error

Close ends the event streams of the client and its connections. The visor keeps running.

func (*Client) EnsureWorkdir

func (c *Client) EnsureWorkdir(ctx context.Context, w WorkdirSpec) (Workdir, error)

EnsureWorkdir gives the workdir for w, and makes it once.

func (*Client) Events

func (c *Client) Events(ctx context.Context, f Filter, after uint64) (*EventStream, error)

Events gives the events after a sequence number that match f. The stream connects again after a drop or a visor restart, and continues after the last event that it gave.

func (*Client) ForgetProject

func (c *Client) ForgetProject(ctx context.Context, id string) error

ForgetProject removes a project with no workdirs.

func (*Client) Handover

func (c *Client) Handover(ctx context.Context, id string, to Kind) error

Handover moves a session between the wire and the pty backend.

func (*Client) Harness

func (c *Client) Harness(ctx context.Context, name string) (Harness, error)

Harness reads one harness.

func (*Client) HarnessFiles added in v0.2.0

func (c *Client) HarnessFiles(ctx context.Context, name string) ([]HomeFile, error)

HarnessFiles lists the home files of a harness and their share state.

func (*Client) HarnessLogin added in v0.2.0

func (c *Client) HarnessLogin(ctx context.Context, name string) (Login, error)

HarnessLogin gives the login that runs, or the last one for a minute after its end.

func (*Client) HarnessLoginCode added in v0.2.0

func (c *Client) HarnessLoginCode(ctx context.Context, name, code string) (Login, error)

HarnessLoginCode types a pasted code into a terminal login.

func (*Client) HarnessLoginToken added in v0.2.0

func (c *Client) HarnessLoginToken(ctx context.Context, name, token string) (Harness, error)

HarnessLoginToken keeps a token or an API key as the login of a harness.

func (*Client) HarnessModels

func (c *Client) HarnessModels(ctx context.Context, name string) ([]Model, error)

HarnessModels lists the models of a harness.

func (*Client) Harnesses

func (c *Client) Harnesses(ctx context.Context) ([]Harness, error)

Harnesses lists the harnesses that the visor knows.

func (*Client) Hello

func (c *Client) Hello(ctx context.Context, h Hello) (Info, error)

Hello tells the visor which product connects.

func (*Client) Hook

func (c *Client) Hook(ctx context.Context, call HookCall) (Session, error)

Hook applies one hook call. The session is empty when the call changes no session.

func (*Client) Hooks

func (c *Client) Hooks(ctx context.Context, spec HookSpec) ([]HookStatus, error)

Hooks gives the hook state of the vendor configs in spec.

func (*Client) Info

func (c *Client) Info(ctx context.Context) (Info, error)

Info describes the visor.

func (*Client) InstallHarness

func (c *Client) InstallHarness(ctx context.Context, name, version string) (Harness, error)

InstallHarness installs a visor copy of a harness. An empty version is the latest.

func (*Client) InstallHooks

func (c *Client) InstallHooks(ctx context.Context, spec HookSpec) ([]HookStatus, error)

InstallHooks adds or updates the hook entries of the visor in the vendor configs.

func (*Client) Interrupt

func (c *Client) Interrupt(ctx context.Context, id string) error

Interrupt stops the current turn.

func (*Client) Keys

func (c *Client) Keys(ctx context.Context, id string, data []byte) error

Keys writes data to the terminal of a session as typed keys.

func (*Client) LoginHarness

func (c *Client) LoginHarness(ctx context.Context, name string, spec LoginSpec) (Login, error)

LoginHarness starts the vendor login and gives the URL or the code.

func (*Client) LogoutHarness

func (c *Client) LogoutHarness(ctx context.Context, name string) error

LogoutHarness logs a harness out.

func (*Client) Output

func (c *Client) Output(ctx context.Context, id string) (string, error)

Output gives the end of the terminal output of a session as plain text.

func (*Client) OwnHarnessFile added in v0.2.0

func (c *Client) OwnHarnessFile(ctx context.Context, name, key string, start OwnStart) (HomeFile, error)

OwnHarnessFile gives the harness home its own copy of a file.

func (*Client) Paste

func (c *Client) Paste(ctx context.Context, id, text string) error

Paste writes text to the terminal of a session as one paste.

func (*Client) Projects

func (c *Client) Projects(ctx context.Context, f Filter) ([]Project, error)

Projects lists the projects.

func (*Client) Purge added in v0.4.0

func (c *Client) Purge(ctx context.Context, p PurgeSpec) error

Purge removes an ended session and the vendor files of it.

func (*Client) ReadHarnessFile added in v0.2.0

func (c *Client) ReadHarnessFile(ctx context.Context, name, key, side string) (FileContent, error)

ReadHarnessFile reads one side of a home file. An empty side is the one that a session uses.

func (*Client) RemoveHooks

func (c *Client) RemoveHooks(ctx context.Context, spec HookSpec) ([]HookStatus, error)

RemoveHooks takes the hook entries of the visor out of the vendor configs.

func (*Client) RemoveWorkdir

func (c *Client) RemoveWorkdir(ctx context.Context, id string, force bool) error

RemoveWorkdir removes a workdir.

func (*Client) RestoreWorkdir

func (c *Client) RestoreWorkdir(ctx context.Context, id string) (Workdir, error)

RestoreWorkdir makes an archived workdir active again.

func (*Client) Screen

func (c *Client) Screen(ctx context.Context, id string) (Screen, error)

Screen gives the terminal of a session as text.

func (*Client) Send

func (c *Client) Send(ctx context.Context, id string, in Input) (Delivery, error)

Send writes a user turn.

func (*Client) Session

func (c *Client) Session(ctx context.Context, id string) (Session, error)

Session reads one session.

func (*Client) Sessions

func (c *Client) Sessions(ctx context.Context, f Filter) ([]Session, error)

Sessions lists the sessions that match f, oldest first.

func (*Client) SetHarnessAuth

func (c *Client) SetHarnessAuth(ctx context.Context, name string, mode AuthMode) (Harness, error)

SetHarnessAuth moves a harness to a shared or a separate login.

func (*Client) SetHarnessEnv

func (c *Client) SetHarnessEnv(ctx context.Context, name string, env map[string]string) error

SetHarnessEnv replaces the env of a harness.

func (*Client) SetHarnessUpdates added in v0.2.0

func (c *Client) SetHarnessUpdates(ctx context.Context, name string, mode UpdateMode, version string) (Harness, error)

SetHarnessUpdates sets the update mode of a harness.

func (*Client) ShareHarnessFile added in v0.2.0

func (c *Client) ShareHarnessFile(ctx context.Context, name, key string) (HomeFile, error)

ShareHarnessFile makes the harness home use the user file.

func (*Client) Start

func (c *Client) Start(ctx context.Context, spec StartSpec) (Session, error)

Start starts a session.

func (*Client) Stop

func (c *Client) Stop(ctx context.Context, id string) error

Stop ends a session.

func (*Client) UpdateHarness

func (c *Client) UpdateHarness(ctx context.Context, name, version string) (Harness, error)

UpdateHarness updates a harness. An empty version is the latest.

func (*Client) Upgrade

func (c *Client) Upgrade(ctx context.Context, spec UpgradeSpec) (Info, error)

Upgrade asks the visor to replace itself with spec.Binary when it is quiet. See Visor.Upgrade.

func (*Client) Workdirs

func (c *Client) Workdirs(ctx context.Context, f Filter) ([]Workdir, error)

Workdirs lists the workdirs that match f.

func (*Client) WriteHarnessFile added in v0.2.0

func (c *Client) WriteHarnessFile(ctx context.Context, name, key, content, ifMatch string) (FileContent, error)

WriteHarnessFile replaces the own copy of a home file. An old etag gives ErrStale.

type ClientFrame

type ClientFrame struct {
	Type ClientFrameType `json:"type"`
	// View, Cols, Rows, and After belong to attach. Cols and Rows also
	// belong to control.
	View  AttachView `json:"view,omitempty"`
	Cols  int        `json:"cols,omitempty"`
	Rows  int        `json:"rows,omitempty"`
	After *uint64    `json:"after,omitempty"`
	// Seq is the binary sequence of an ack.
	Seq uint64 `json:"seq,omitempty"`
	// Text is the text of a send.
	Text string `json:"text,omitempty"`
	// Data is the bytes of an input.
	Data []byte `json:"-"`
}

ClientFrame is one frame from an attach client. Each is a JSON frame, except input, which is a binary frame with op OpInput.

func DecodeClientFrame

func DecodeClientFrame(isBinary bool, data []byte) (ClientFrame, error)

DecodeClientFrame reads one frame from an attach client.

func (ClientFrame) Encode

func (f ClientFrame) Encode() (isBinary bool, data []byte, err error)

Encode gives the frame as it goes on the socket.

func (ClientFrame) Options

func (f ClientFrame) Options() AttachOptions

Options gives the attach options of an attach frame.

type ClientFrameType

type ClientFrameType string

ClientFrameType is the type of a frame from an attach client.

const (
	ClientAttach    ClientFrameType = "attach"
	ClientAck       ClientFrameType = "ack"
	ClientControl   ClientFrameType = "control"
	ClientRelease   ClientFrameType = "release"
	ClientSend      ClientFrameType = "send"
	ClientInterrupt ClientFrameType = "interrupt"
	ClientInput     ClientFrameType = "input"
)

Client frame types.

type Delivery

type Delivery string

Delivery tells how a send reached the session.

const (
	// DeliveryPrompted means that a new turn starts, or that the vendor
	// queues it.
	DeliveryPrompted Delivery = Delivery(agentwire.DeliveryPrompted)
	// DeliverySteered means that the input joined the running turn.
	DeliverySteered Delivery = Delivery(agentwire.DeliverySteered)
	// DeliveryHeld means that the input starts a new turn when the running
	// turn ends.
	DeliveryHeld Delivery = Delivery(agentwire.DeliveryHeld)
)

Deliveries. The values are the agent-wire values.

type Discoverer added in v0.3.0

type Discoverer interface {
	// Found gives the new sessions. It closes when the backend closes.
	Found() <-chan Found
	// Adopt binds the found session with key to the visor session s.
	Adopt(ctx context.Context, s Session, key string) (Handle, error)
}

Discoverer is a backend that finds sessions that it did not start. The visor makes a session for each one and adopts it. An observed session with the same labels becomes the adopted session.

type EndReason

type EndReason string

EndReason tells why an attachment ended.

const (
	EndExited EndReason = "exited"
	EndClosed EndReason = "closed"
)

End reasons.

type Event

type Event struct {
	Seq     uint64    `json:"seq"`
	Session string    `json:"session,omitempty"`
	At      time.Time `json:"at"`
	Type    EventType `json:"type"`
	// State is the new state of a session.state event.
	State State `json:"state,omitempty"`
	// Turn counts the finished user turns of a wire session.
	Turn     int    `json:"turn,omitempty"`
	VendorID string `json:"vendor_id,omitempty"`
	Text     string `json:"text,omitempty"`
	// Input marks a user event that the visor wrote for a send or a first
	// prompt. A vendor echo of the turn has no mark.
	Input bool `json:"input,omitempty"`
	Delta bool `json:"delta,omitempty"`
	// Status is the activity hint of a status event.
	Status  string   `json:"status,omitempty"`
	Tool    *Tool    `json:"tool,omitempty"`
	Request *Request `json:"request,omitempty"`
	// RequestID names the request of a request.closed event.
	RequestID string  `json:"request_id,omitempty"`
	Result    *Result `json:"result,omitempty"`
	Usage     *Usage  `json:"usage,omitempty"`
	Limits    *Limits `json:"limits,omitempty"`
	Error     string  `json:"error,omitempty"`
	Code      string  `json:"code,omitempty"`
	EndReason string  `json:"end_reason,omitempty"`
	ExitCode  *int    `json:"exit_code,omitempty"`
	// Harness names the harness of a harness.changed event.
	Harness string `json:"harness,omitempty"`
	// Data is the payload of a hook event, the output of a script, or the
	// build of a restart.
	Data json.RawMessage `json:"data,omitempty"`
	// contains filtered or unexported fields
}

Event is one entry in the event log. Seq is global for one visor.

func (Event) Wire

func (e Event) Wire() (agentwire.Event, bool)

Wire converts the event back to an agent-wire event, so a product can feed its agent-wire tracker. ok is false for a visor event type.

type EventStream

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

EventStream gives the events after a sequence number: first the log, then the live events. It continues after a slow read with no gap.

func (*EventStream) C

func (s *EventStream) C() <-chan Event

C gives the events. It closes when the stream ends; Err then tells why.

func (*EventStream) Close

func (s *EventStream) Close() error

Close ends the stream and waits for its goroutine.

func (*EventStream) Err

func (s *EventStream) Err() error

Err is the reason that the stream ended, or nil.

func (*EventStream) Next

func (s *EventStream) Next(ctx context.Context) (Event, error)

Next waits for the next event.

type EventType

type EventType string

EventType is the type of an event.

const (
	EventSessionState   EventType = "session.state"
	EventInit           EventType = "init"
	EventAssistant      EventType = "assistant"
	EventThought        EventType = "thought"
	EventUser           EventType = "user"
	EventTool           EventType = "tool"
	EventRequest        EventType = "request"
	EventRequestClosed  EventType = "request.closed"
	EventUsage          EventType = "usage"
	EventLimits         EventType = "limits"
	EventStatus         EventType = "status"
	EventResult         EventType = "result"
	EventError          EventType = "error"
	EventExit           EventType = "exit"
	EventHook           EventType = "hook"
	EventScript         EventType = "workdir.script"
	EventHarnessChanged EventType = "harness.changed"
	EventRestarting     EventType = "visor.restarting"
)

Event types.

type FileContent added in v0.2.0

type FileContent = harness.FileContent

FileContent is the content of one side of a home file.

type Filter

type Filter struct {
	Session string            `json:"session,omitempty"`
	Project string            `json:"project,omitempty"`
	Workdir string            `json:"workdir,omitempty"`
	Key     string            `json:"key,omitempty"`
	Kind    Kind              `json:"kind,omitempty"`
	Role    Role              `json:"role,omitempty"`
	States  []State           `json:"states,omitempty"`
	Labels  map[string]string `json:"labels,omitempty"`
}

Filter selects sessions, workdirs, projects, or events. The empty value selects all.

type Found added in v0.3.0

type Found struct {
	// Key names the session in the backend.
	Key     string
	Harness string
	// Dir is the absolute working folder.
	Dir    string
	Title  string
	Labels map[string]string
}

Found is a session that a backend found and the visor did not start, for example an agent that the user started in another app.

type Frame

type Frame struct {
	Type FrameType `json:"type"`
	// Op, Seq, and Data belong to a binary frame. Seq counts the binary
	// bytes that the attachment sent, and an ack gives it back.
	Op   FrameOp `json:"-"`
	Seq  uint64  `json:"-"`
	Data []byte  `json:"-"`
	// View, Source, Writable, Resizable, and Title belong to attached.
	View      AttachView `json:"view,omitempty"`
	Source    Kind       `json:"source,omitempty"`
	Cols      int        `json:"cols,omitempty"`
	Rows      int        `json:"rows,omitempty"`
	Writable  bool       `json:"writable,omitempty"`
	Resizable bool       `json:"resizable,omitempty"`
	Title     string     `json:"title,omitempty"`
	// Holder belongs to lease.
	Holder LeaseHolder `json:"holder,omitempty"`
	// From, To, and Turns belong to turns.
	From  uint64 `json:"from,omitempty"`
	To    uint64 `json:"to,omitempty"`
	Turns []Turn `json:"turns,omitempty"`
	// Reason belongs to ended.
	Reason EndReason `json:"reason,omitempty"`
	// Code and Message belong to error.
	Code    string `json:"code,omitempty"`
	Message string `json:"message,omitempty"`
}

Frame is one frame to an attach client: a binary frame when Op is not zero, else a JSON frame of Type.

func DecodeFrame

func DecodeFrame(isBinary bool, data []byte) (Frame, error)

DecodeFrame reads one frame to an attach client.

func (Frame) Binary

func (f Frame) Binary() bool

Binary reports whether the frame is a binary frame.

func (Frame) Encode

func (f Frame) Encode() ([]byte, error)

Encode gives the frame as it goes on the socket.

type FrameOp

type FrameOp byte

FrameOp is the op of a binary frame: op (1 byte) | seq (8 bytes, big endian) | data.

const (
	OpSnapshot FrameOp = 1
	OpOutput   FrameOp = 2
	OpInput    FrameOp = 3
)

Binary frame ops.

type FrameType

type FrameType string

FrameType is the type of a JSON frame to an attach client.

const (
	FrameAttached FrameType = "attached"
	FrameResized  FrameType = "resized"
	FrameLease    FrameType = "lease"
	FrameTurns    FrameType = "turns"
	FrameEnded    FrameType = "ended"
	FrameError    FrameType = "error"
)

Frame types.

type Handle

type Handle interface {
	Session() string
	VendorID() string
	PID() int
	Send(ctx context.Context, in Input) (Delivery, error)
	Interrupt(ctx context.Context) error
	Answer(ctx context.Context, requestID string, a Answer) error
	Close(ctx context.Context) error
	Events() <-chan Event
}

Handle is one live session in a backend. Events closes when the session ends.

type Harness

type Harness = harness.Harness

Harness is one vendor agent CLI on this machine.

type HarnessFacts

type HarnessFacts = harness.Facts

HarnessFacts are the vendor facts that the inventory reads, for tests.

type HarnessOptions

type HarnessOptions = harness.Options

HarnessOptions configures the harness inventory.

type HarnessPolicy added in v0.2.0

type HarnessPolicy = harness.Policy

HarnessPolicy is the product policy for the harness homes.

type HarnessSource

type HarnessSource = harness.Source

HarnessSource tells where a harness binary comes from.

type HarnessUpdate added in v0.2.0

type HarnessUpdate = harness.Update

HarnessUpdate is one version change of a harness.

type Hello

type Hello struct {
	Client   string `json:"client"`
	Build    string `json:"build"`
	Protocol string `json:"protocol"`
	// Binary is the product binary that contains the visor build of Build.
	Binary string `json:"binary,omitempty"`
}

Hello is what a product sends when it connects.

type HomeFile added in v0.2.0

type HomeFile = harness.HomeFile

HomeFile is one file or folder of a harness home that can share the user's own setup.

type HookCall

type HookCall struct {
	Harness string `json:"harness"`
	// Session is the AGENT_VISOR_SESSION value of the hook process, or empty
	// for a session that started outside the visor.
	Session string `json:"session,omitempty"`
	// Labels find the session when Session is empty, for example the
	// terminal of another app. A new observed session gets them.
	Labels  map[string]string `json:"labels,omitempty"`
	Payload json.RawMessage   `json:"payload"`
	// At is when the hook ran. Zero is now.
	At time.Time `json:"at,omitzero"`
}

HookCall is one call of a vendor hook.

type HookSpec

type HookSpec struct {
	Harnesses []string `json:"harnesses,omitempty"`
	// Auth selects the login home: shared is the user login, separate is
	// the login of the visor. Empty selects both, and the visor login only
	// when its folder exists.
	Auth AuthMode `json:"auth,omitempty"`
	// Dir is a vendor home that replaces the login homes.
	Dir string `json:"dir,omitempty"`
}

HookSpec selects the vendor hook configs. The empty spec selects each harness with hook support in the user login and in the visor login.

type HookSpool

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

HookSpool keeps the hook calls that did not reach the visor. The visor applies them at its next start.

func NewHookSpool

func NewHookSpool(home string) *HookSpool

NewHookSpool gives the spool of the visor in home.

func (*HookSpool) Write

func (s *HookSpool) Write(c HookCall) error

Write keeps one call. The file name starts with the call time, so a replay keeps the order.

type HookState

type HookState = hooks.State

HookState is the hook state of one vendor config.

type HookStatus

type HookStatus struct {
	Harness string `json:"harness"`
	// Auth is empty when HookSpec.Dir selects the home.
	Auth  AuthMode  `json:"auth,omitempty"`
	Dir   string    `json:"dir"`
	State HookState `json:"state"`
}

HookStatus is the hook state of one harness in one vendor home.

type Info

type Info struct {
	Build    string `json:"build"`
	Protocol string `json:"protocol"`
	Client   string `json:"client,omitempty"`
	Home     string `json:"home"`
	Seq      uint64 `json:"seq"`
	Upgrade  string `json:"upgrade,omitempty"`
	PID      int    `json:"pid"`
}

Info describes a running visor.

type Input

type Input struct {
	Text string `json:"text"`
	// Kind is an opaque origin tag that the visor passes to the harness.
	Kind        string       `json:"kind,omitempty"`
	Attachments []Attachment `json:"attachments,omitempty"`
}

Input is one user turn.

type Kind

type Kind string

Kind is the kind of a session: the backend that hosts it.

const (
	KindWire     Kind = "wire"
	KindPTY      Kind = "pty"
	KindObserved Kind = "observed"
)

Session kinds.

type Labeler added in v0.3.0

type Labeler interface {
	Labels() map[string]string
}

Labeler is a handle that adds labels to its session, for example the terminal of another app. The visor reads them at attach and after each init event.

type Launch

type Launch struct {
	Session Session
	Spec    StartSpec
	// Dir is the working folder.
	Dir string
	// Env is the merged env: visor, harness, session, and the visor values.
	Env map[string]string
	// Binary is the harness program. Empty searches PATH.
	Binary string
	// Home is the harness home for a separate login. Empty uses the login of
	// the user.
	Home string
	// Resume continues the vendor session in Session.VendorID.
	Resume bool
	// Prompt is the first turn, or nil.
	Prompt *Input
}

Launch is what a backend needs to start one session. The visor resolves the workdir, the env layers, and the harness program first.

type LeaseHolder

type LeaseHolder string

LeaseHolder tells a client who holds the size lease.

const (
	LeaseYou   LeaseHolder = "you"
	LeaseOther LeaseHolder = "other"
	LeaseNone  LeaseHolder = "none"
)

Lease holders, as one client sees them.

type LimitWindow

type LimitWindow = harness.LimitWindow

LimitWindow is the use of one plan limit window.

type Limits

type Limits = harness.Limits

Limits is the plan limit state of the account behind a harness.

type Login

type Login = harness.Login

Login is the state of a vendor login.

type LoginPhase added in v0.2.0

type LoginPhase = harness.LoginPhase

LoginPhase is the step of a login.

type LoginSpec added in v0.2.0

type LoginSpec = harness.LoginSpec

LoginSpec asks for a login.

type MCPServer

type MCPServer struct {
	Name    string            `json:"name"`
	Command string            `json:"command,omitempty"`
	Args    []string          `json:"args,omitempty"`
	Env     map[string]string `json:"env,omitempty"`
	URL     string            `json:"url,omitempty"`
	Headers map[string]string `json:"headers,omitempty"`
}

MCPServer is one MCP server for a session. Command selects a stdio server; URL selects an HTTP server.

type Model

type Model = harness.Model

Model is one model that a harness offers.

type Options

type Options struct {
	// Home owns every path of the visor.
	Home string
	// Client is the product name that the harnesses see.
	Client        string
	ClientVersion string
	// Build is the build of this visor. Empty reads the module build info.
	Build string
	// Socket is the socket path that sessions get in AGENT_VISOR_SOCKET.
	Socket string
	// Env is the default env of each session.
	Env map[string]string
	// Backends are extra backends, for example an optional host of sessions.
	Backends []Backend
	// HolderCommand runs a holder for a pty or a wire session; the visor
	// adds the session id. Empty is this program with the argument hold.
	HolderCommand []string
	// HookCommand runs a vendor hook; the visor adds the harness name. Empty
	// is this program with the home and the argument hook.
	HookCommand []string
	// TerminalCommand builds the command of an agent session in a PTY. Nil
	// uses the harness program with ExtraArgs and has no resume command.
	TerminalCommand TerminalCommand
	// Drivers replace agent-wire drivers, for tests (for example the fake
	// harness with a script). A wire session of such a harness runs in the
	// visor process, not in a holder, so it does not survive a restart.
	Drivers map[string]agentwire.Driver
	// Harness configures the harness inventory. The visor sets its InUse,
	// OnChange, and Logger.
	Harness HarnessOptions
	Logger  *slog.Logger
	// KeepExited is how long the visor keeps an exited session and its
	// events. Zero keeps them for 7 days.
	KeepExited time.Duration
	// KeepFragments is how long the visor keeps the stream fragments of a
	// failed wire session. Zero keeps them for 30 days.
	KeepFragments time.Duration
	// UpgradeWait is how long an upgrade waits for a quiet visor. Zero is
	// 24 hours. A new protocol major waits 10 minutes at most.
	UpgradeWait time.Duration
	// Exec replaces the process with the upgrade binary. Nil is
	// syscall.Exec.
	Exec func(binary string, args, env []string) error
	// Now is the clock of the upgrade deadline. Nil is time.Now.
	Now func() time.Time
	// contains filtered or unexported fields
}

Options configures a visor.

type OwnStart added in v0.2.0

type OwnStart = harness.OwnStart

OwnStart is the first content of an own copy.

type Permissions

type Permissions struct {
	// Mode is ask, auto_edit, auto, or inherit. Empty is ask.
	Mode agentwire.PermissionMode `json:"mode,omitempty"`
	// AllowTools are tools that need no answer. A pattern can end in "*".
	AllowTools []string `json:"allow_tools,omitempty"`
}

Permissions is the permission policy of a session.

type Project

type Project = workdir.Project

Project is a repository root or a plain folder.

type PurgeSpec added in v0.4.0

type PurgeSpec struct {
	Session  string `json:"session,omitempty"`
	Harness  string `json:"harness,omitempty"`
	VendorID string `json:"vendor_id,omitempty"`
}

PurgeSpec names what Purge removes. Session is a visor session. Harness and VendorID name the vendor files to remove; without them, the vendor files stay, so that another session can resume the vendor session.

func (PurgeSpec) Validate added in v0.4.0

func (p PurgeSpec) Validate() error

Validate checks that p names a session or a vendor session.

type Request

type Request struct {
	ID        string   `json:"id"`
	Tool      string   `json:"tool,omitempty"`
	Kind      string   `json:"kind,omitempty"`
	Question  string   `json:"question,omitempty"`
	Input     string   `json:"input,omitempty"`
	Options   []string `json:"options,omitempty"`
	ToolUseID string   `json:"tool_use_id,omitempty"`
}

Request is an open permission or question.

type RestartMode

type RestartMode string

RestartMode tells what the visor does with a session that it lost.

const (
	RestartNotify RestartMode = "notify"
	RestartResume RestartMode = "resume"
)

Restart modes.

type RestartPolicy

type RestartPolicy struct {
	Mode RestartMode `json:"mode,omitempty"`
	// Prompt is the first turn after a resume.
	Prompt string `json:"prompt,omitempty"`
}

RestartPolicy applies when the visor finds a session lost at boot.

type Result

type Result struct {
	Subtype   string `json:"subtype,omitempty"`
	IsError   bool   `json:"is_error,omitempty"`
	Text      string `json:"text,omitempty"`
	VendorID  string `json:"vendor_id,omitempty"`
	Usage     Usage  `json:"usage"`
	EndReason string `json:"end_reason,omitempty"`
	Code      string `json:"code,omitempty"`
}

Result ends a turn.

type Role

type Role string

Role is what a session does.

const (
	RoleAgent  Role = "agent"
	RoleShell  Role = "shell"
	RoleScript Role = "script"
)

Session roles.

type Screen

type Screen struct {
	Cols      int      `json:"cols"`
	Rows      int      `json:"rows"`
	Lines     []string `json:"lines"`
	CursorRow int      `json:"cursor_row"`
	CursorCol int      `json:"cursor_col"`
}

Screen is the text of a terminal as a terminal shows it. A line has no trailing spaces. The cursor row and column start at 0.

type Server

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

Server serves one visor over HTTP on a Unix socket.

func NewServer

func NewServer(v *Visor) *Server

NewServer makes the HTTP handler for v.

func (*Server) ServeHTTP

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)

type Session

type Session struct {
	ID         string            `json:"id"`
	Project    string            `json:"project"`
	Workdir    string            `json:"workdir"`
	Kind       Kind              `json:"kind"`
	Role       Role              `json:"role"`
	Title      string            `json:"title,omitempty"`
	Harness    string            `json:"harness,omitempty"`
	Model      string            `json:"model,omitempty"`
	Effort     string            `json:"effort,omitempty"`
	WorkingDir string            `json:"working_dir"`
	State      State             `json:"state"`
	VendorID   string            `json:"vendor_id,omitempty"`
	PID        int               `json:"pid,omitempty"`
	Labels     map[string]string `json:"labels,omitempty"`
	// Pending holds the open permissions and questions.
	Pending []Request     `json:"pending,omitempty"`
	Restart RestartPolicy `json:"restart"`
	// EnvKeys lists the session env keys. The values never leave the visor.
	EnvKeys []string `json:"env_keys,omitempty"`
	// Seq is the sequence number of the last event of the session.
	Seq       uint64    `json:"seq"`
	Turns     int       `json:"turns,omitempty"`
	ExitCode  *int      `json:"exit_code,omitempty"`
	Error     string    `json:"error,omitempty"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

Session is one agent, shell, or script in a workdir.

type Skill

type Skill struct {
	// Name replaces the name in the SKILL.md front matter.
	Name string `json:"name,omitempty"`
	// Dir is the folder that holds SKILL.md.
	Dir string `json:"dir"`
}

Skill is one extra skill for a session.

type StartSpec

type StartSpec struct {
	// Kind is empty for wire when the harness has a driver, else pty.
	Kind Kind `json:"kind,omitempty"`
	// Role is empty for agent, or shell when there is no harness.
	Role    Role   `json:"role,omitempty"`
	Title   string `json:"title,omitempty"`
	Harness string `json:"harness,omitempty"`
	Model   string `json:"model,omitempty"`
	Effort  string `json:"effort,omitempty"`
	// Binary is the harness program. Empty uses the visor install, else
	// PATH.
	Binary string `json:"binary,omitempty"`
	// Workdir is a workdir id. Empty finds or makes it from WorkingDir.
	Workdir string `json:"workdir,omitempty"`
	// WorkingDir is a folder in the workdir. Empty is the workdir path.
	WorkingDir string `json:"working_dir,omitempty"`
	// Command is the shell or script command. Empty is the login shell.
	Command []string `json:"command,omitempty"`
	// Env wins over the harness env and the visor env.
	Env          map[string]string `json:"env,omitempty"`
	Instructions string            `json:"instructions,omitempty"`
	// Prompt is the first turn. Empty starts the session idle.
	Prompt      string      `json:"prompt,omitempty"`
	Permissions Permissions `json:"permissions"`
	MCPServers  []MCPServer `json:"mcp_servers,omitempty"`
	Skills      []Skill     `json:"skills,omitempty"`
	ExtraArgs   []string    `json:"extra_args,omitempty"`
	// ResumeID is a vendor session id to resume.
	ResumeID string            `json:"resume_id,omitempty"`
	Labels   map[string]string `json:"labels,omitempty"`
	Restart  RestartPolicy     `json:"restart"`
	Raw      map[string]any    `json:"raw,omitempty"`
	// LogFragments writes every stream fragment to the frame log of a wire
	// session. By default the frame log keeps fragments only when the
	// stream fails, in fragments/<id>.ndjson.
	LogFragments bool `json:"log_fragments,omitempty"`
}

StartSpec asks for a new session. The empty value starts a shell in the working folder of the visor process.

func (StartSpec) Validate

func (s StartSpec) Validate() error

Validate checks the spec before a start.

type State

type State string

State is the state of a session.

const (
	StateStarting  State = "starting"
	StateRunning   State = "running"
	StateWaiting   State = "waiting"
	StateIdle      State = "idle"
	StateSuspended State = "suspended"
	StateLost      State = "lost"
	StateExited    State = "exited"
)

Session states.

func (State) Busy

func (s State) Busy() bool

Busy reports whether the session is in a turn.

func (State) CanMove

func (s State) CanMove(to State) bool

CanMove reports whether the state machine allows the move.

func (State) Live

func (s State) Live() bool

Live reports whether a process can run for the session now.

type TerminalCommand

type TerminalCommand func(l Launch) ([]string, error)

TerminalCommand builds the command line of a vendor terminal program for an agent session in a PTY. l.Resume asks for the command that continues the vendor session l.Session.VendorID.

type TextTerminal added in v0.3.0

type TextTerminal interface {
	Screen(ctx context.Context) (Screen, error)
	Keys(ctx context.Context, data []byte) error
	Paste(ctx context.Context, text string) error
	// Output gives the end of the terminal output as plain text.
	Output(ctx context.Context) (string, error)
}

TextTerminal is a handle whose terminal the backend shows only as text, for example a terminal in another app. Screen, Keys, Paste, and Output use it.

type Tool

type Tool struct {
	ID       string   `json:"id"`
	Name     string   `json:"name"`
	Kind     string   `json:"kind,omitempty"`
	Input    string   `json:"input,omitempty"`
	Output   string   `json:"output,omitempty"`
	Status   string   `json:"status,omitempty"`
	Paths    []string `json:"paths,omitempty"`
	ExitCode *int     `json:"exit_code,omitempty"`
}

Tool is one tool call, as agent-wire reports it.

type Turn

type Turn struct {
	Seq  uint64    `json:"seq"`
	Role TurnRole  `json:"role"`
	At   time.Time `json:"at"`
	Text string    `json:"text,omitempty"`
	Tool *Tool     `json:"tool,omitempty"`
}

Turn is one turn of the chat view. A turn that changes comes again with the same Seq.

type TurnRole

type TurnRole string

TurnRole is the role of one turn of the chat view.

const (
	TurnUser      TurnRole = "user"
	TurnAssistant TurnRole = "assistant"
	TurnTool      TurnRole = "tool"
	TurnResult    TurnRole = "result"
)

Turn roles.

type UpdateMode added in v0.2.0

type UpdateMode = harness.UpdateMode

UpdateMode tells whether the visor updates a harness.

type UpgradeSpec

type UpgradeSpec struct {
	// Binary is the program of the new build. The visor runs it with its
	// own arguments and env.
	Binary   string `json:"binary"`
	Build    string `json:"build,omitempty"`
	Protocol string `json:"protocol,omitempty"`
}

UpgradeSpec names the visor build that replaces the running one.

type Usage

type Usage struct {
	Input         int64   `json:"input,omitempty"`
	Output        int64   `json:"output,omitempty"`
	CacheRead     int64   `json:"cache_read,omitempty"`
	CacheCreation int64   `json:"cache_creation,omitempty"`
	Model         string  `json:"model,omitempty"`
	CostUSD       float64 `json:"cost_usd,omitempty"`
}

Usage is the token and cost account of a turn, in vendor units.

type Visor

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

Visor holds the sessions of one product on one machine.

func New

func New(ctx context.Context, o Options) (*Visor, error)

New opens the visor in home, recovers the sessions of the last run, and applies the restart policies.

func (*Visor) Answer

func (v *Visor) Answer(ctx context.Context, id, requestID string, a Answer) error

Answer decides an open request.

func (*Visor) ArchiveWorkdir

func (v *Visor) ArchiveWorkdir(ctx context.Context, id string) error

ArchiveWorkdir stops the sessions of a workdir and archives it. The folder and the branch stay.

func (*Visor) Attach

func (v *Visor) Attach(_ context.Context, id string, o AttachOptions) (*AttachStream, error)

Attach attaches a client to the terminal or the chat of a session. The attachment lives until Close, the end of the session, or the end of the visor.

func (*Visor) CancelHarnessLogin added in v0.2.0

func (v *Visor) CancelHarnessLogin(ctx context.Context, name string) error

CancelHarnessLogin stops a running login.

func (*Visor) CheckHarnesses added in v0.2.0

func (v *Visor) CheckHarnesses(ctx context.Context) error

CheckHarnesses looks for new releases now and applies the update modes.

func (*Visor) Close

func (v *Visor) Close(ctx context.Context) error

Close stops the visor. A session in a holder keeps running. Of the other sessions, a session in a turn becomes lost, and an idle wire session becomes suspended, so the next visor resumes it.

func (*Visor) EnsureWorkdir

func (v *Visor) EnsureWorkdir(ctx context.Context, w WorkdirSpec) (Workdir, error)

EnsureWorkdir gives the workdir for w. With a key, it makes the workdir once and then gives the same one.

func (*Visor) Events

func (v *Visor) Events(ctx context.Context, f Filter, after uint64) (*EventStream, error)

Events gives the events after a sequence number that match f: first from the log, then live. Events of the visor itself (no session) match each filter without a session.

func (*Visor) ForgetProject

func (v *Visor) ForgetProject(ctx context.Context, id string) error

ForgetProject removes a project with no workdirs.

func (*Visor) Handover

func (v *Visor) Handover(ctx context.Context, id string, to Kind) error

Handover moves an agent session to another kind. The session id and the vendor session stay. A wire session moves to pty at the end of its turn; the terminal program continues the vendor session. A pty session moves to wire when its terminal program exits; Handover waits for that exit. One process at a time writes to the vendor session.

func (*Visor) Harness

func (v *Visor) Harness(ctx context.Context, name string) (Harness, error)

Harness reads one harness.

func (*Visor) HarnessFiles added in v0.2.0

func (v *Visor) HarnessFiles(ctx context.Context, name string) ([]HomeFile, error)

HarnessFiles lists the home files of a harness and their share state.

func (*Visor) HarnessLogin added in v0.2.0

func (v *Visor) HarnessLogin(ctx context.Context, name string) (Login, error)

HarnessLogin gives the login that runs, or the last one for a minute after its end.

func (*Visor) HarnessLoginCode added in v0.2.0

func (v *Visor) HarnessLoginCode(ctx context.Context, name, code string) (Login, error)

HarnessLoginCode types a pasted code into a terminal login.

func (*Visor) HarnessLoginToken added in v0.2.0

func (v *Visor) HarnessLoginToken(ctx context.Context, name, token string) (Harness, error)

HarnessLoginToken keeps a token or an API key as the login of a harness.

func (*Visor) HarnessModels

func (v *Visor) HarnessModels(ctx context.Context, name string) ([]Model, error)

HarnessModels lists the models of a harness.

func (*Visor) Harnesses

func (v *Visor) Harnesses(ctx context.Context) ([]Harness, error)

Harnesses lists the harnesses that the visor knows.

func (*Visor) Hello

func (v *Visor) Hello(ctx context.Context, h Hello) (Info, error)

Hello records the product that connects and describes the visor. When h has a binary of a newer build, the visor upgrades to it.

func (*Visor) Hook

func (v *Visor) Hook(ctx context.Context, c HookCall) (Session, error)

Hook applies one hook call. With a session id it updates that session and never makes one. Without, it makes or updates an observed session for the vendor session. The session is empty when the call changes no session.

func (*Visor) Hooks

func (v *Visor) Hooks(ctx context.Context, spec HookSpec) ([]HookStatus, error)

Hooks gives the hook state of the vendor configs in spec.

func (*Visor) Info

func (v *Visor) Info(context.Context) (Info, error)

Info describes the visor.

func (*Visor) InstallHarness

func (v *Visor) InstallHarness(ctx context.Context, name, version string) (Harness, error)

InstallHarness installs a visor copy of a harness. An empty version is the latest release. It returns ErrBusy when a live session uses the harness.

func (*Visor) InstallHooks

func (v *Visor) InstallHooks(ctx context.Context, spec HookSpec) ([]HookStatus, error)

InstallHooks adds or updates the hook entries of the visor in the vendor configs. The other entries and the rest of each file stay.

func (*Visor) Interrupt

func (v *Visor) Interrupt(ctx context.Context, id string) error

Interrupt stops the current turn.

func (*Visor) Keys

func (v *Visor) Keys(ctx context.Context, id string, data []byte) error

Keys writes data to the terminal of a session as typed keys, with no return added.

func (*Visor) LoginHarness

func (v *Visor) LoginHarness(ctx context.Context, name string, spec LoginSpec) (Login, error)

LoginHarness starts the vendor login and gives the URL or the code. A terminal login runs in a session with the label visor.login.

func (*Visor) LogoutHarness

func (v *Visor) LogoutHarness(ctx context.Context, name string) error

LogoutHarness logs out of a harness.

func (*Visor) Output

func (v *Visor) Output(ctx context.Context, id string) (string, error)

Output gives the end of the terminal output of a session as plain text, one ring long. It also works after the session ends.

func (*Visor) OwnHarnessFile added in v0.2.0

func (v *Visor) OwnHarnessFile(ctx context.Context, name, key string, start OwnStart) (HomeFile, error)

OwnHarnessFile gives the harness home its own copy of a file.

func (*Visor) Paste

func (v *Visor) Paste(ctx context.Context, id, text string) error

Paste writes text to the terminal of a session as one paste, with no return added. When the program asks for bracketed paste, the text goes in the paste markers, so that a newline in it does not submit.

func (*Visor) Projects

func (v *Visor) Projects(ctx context.Context, _ Filter) ([]Project, error)

Projects lists the projects.

func (*Visor) Purge added in v0.4.0

func (v *Visor) Purge(ctx context.Context, p PurgeSpec) error

Purge removes an ended session, its events and files, and the files that the vendor keeps for it in the harness home of the visor. It keeps the fragment file. A live session, or a live session with the same vendor session, is an ErrState.

func (*Visor) ReadHarnessFile added in v0.2.0

func (v *Visor) ReadHarnessFile(ctx context.Context, name, key, side string) (FileContent, error)

ReadHarnessFile reads one side of a home file. An empty side is the one that a session uses.

func (*Visor) RemoveHooks

func (v *Visor) RemoveHooks(ctx context.Context, spec HookSpec) ([]HookStatus, error)

RemoveHooks takes the hook entries of the visor out of the vendor configs.

func (*Visor) RemoveWorkdir

func (v *Visor) RemoveWorkdir(ctx context.Context, id string, force bool) error

RemoveWorkdir removes a workdir. A workdir with live sessions, or a worktree with changes, needs force.

func (*Visor) RestoreWorkdir

func (v *Visor) RestoreWorkdir(ctx context.Context, id string) (Workdir, error)

RestoreWorkdir makes an archived workdir active again.

func (*Visor) Screen

func (v *Visor) Screen(ctx context.Context, id string) (Screen, error)

Screen gives the terminal of a session as text.

func (*Visor) Send

func (v *Visor) Send(ctx context.Context, id string, in Input) (Delivery, error)

Send writes a user turn. It resumes a suspended or lost session first; a resume gives DeliveryPrompted.

func (*Visor) Session

func (v *Visor) Session(_ context.Context, id string) (Session, error)

Session reads one session.

func (*Visor) Sessions

func (v *Visor) Sessions(_ context.Context, f Filter) ([]Session, error)

Sessions lists the sessions that match f, oldest first.

func (*Visor) SetHarnessAuth

func (v *Visor) SetHarnessAuth(ctx context.Context, name string, mode AuthMode) (Harness, error)

SetHarnessAuth moves a harness to a shared or a separate login.

func (*Visor) SetHarnessEnv

func (v *Visor) SetHarnessEnv(ctx context.Context, name string, env map[string]string) error

SetHarnessEnv replaces the env of a harness. Each session of the harness gets it, under the session env. An empty env removes it.

func (*Visor) SetHarnessUpdates added in v0.2.0

func (v *Visor) SetHarnessUpdates(ctx context.Context, name string, mode UpdateMode, version string) (Harness, error)

SetHarnessUpdates sets the update mode of a harness. Keep mode holds a version: an empty version is the current one.

func (*Visor) ShareHarnessFile added in v0.2.0

func (v *Visor) ShareHarnessFile(ctx context.Context, name, key string) (HomeFile, error)

ShareHarnessFile makes the harness home use the user file. An own copy goes to a backup.

func (*Visor) Start

func (v *Visor) Start(ctx context.Context, spec StartSpec) (Session, error)

Start starts a session.

func (*Visor) Stop

func (v *Visor) Stop(ctx context.Context, id string) error

Stop ends a session. Its process stops, and it cannot resume.

func (*Visor) UpdateHarness

func (v *Visor) UpdateHarness(ctx context.Context, name, version string) (Harness, error)

UpdateHarness updates a harness. It returns ErrBusy when a live session uses the harness.

func (*Visor) Upgrade

func (v *Visor) Upgrade(ctx context.Context, spec UpgradeSpec) (Info, error)

Upgrade replaces the visor with spec.Binary when no session, attach client, login, or harness change needs it, or after Options.UpgradeWait. A session in a holder keeps running. A session in a turn that is not in a holder becomes lost at the deadline, and its restart policy applies in the next visor. Only a visor that ServeListener serves replaces itself; the upgrade waits for it.

func (*Visor) Workdirs

func (v *Visor) Workdirs(ctx context.Context, f Filter) ([]Workdir, error)

Workdirs lists the workdirs that match f.

func (*Visor) WriteHarnessFile added in v0.2.0

func (v *Visor) WriteHarnessFile(ctx context.Context, name, key, content, ifMatch string) (FileContent, error)

WriteHarnessFile replaces the own copy of a home file. An empty ifMatch skips the etag check. An old etag gives ErrStale.

type Workdir

type Workdir = workdir.Workdir

Workdir is one folder to work in, and for git one branch.

type WorkdirKind

type WorkdirKind = workdir.Kind

WorkdirKind is the kind of a workdir.

type WorkdirSpec

type WorkdirSpec = workdir.Spec

WorkdirSpec asks for a workdir.

type WorkdirState

type WorkdirState = workdir.State

WorkdirState is the state of a workdir.

Directories

Path Synopsis
backend
orca
Package orca is a visor backend for the terminals of Orca on this machine.
Package orca is a visor backend for the terminals of Orca on this machine.
Package cli is the command tree of the visor.
Package cli is the command tree of the visor.
cmd
agent-visor command
Command agent-visor is the generic visor CLI.
Command agent-visor is the generic visor CLI.
Package harness detects, installs, updates, and logs in to the vendor agent CLIs, and lists their models.
Package harness detects, installs, updates, and logs in to the vendor agent CLIs, and lists their models.
Package holder owns the PTY or the agent-wire session of one session, so that the session lives through a restart of the visor.
Package holder owns the PTY or the agent-wire session of one session, so that the session lives through a restart of the visor.
Package hooks reads the hook calls of vendor agent CLIs and edits their hook config files.
Package hooks reads the hook calls of vendor agent CLIs and edits their hook config files.
internal
store
Package store keeps the visor state in visor.db: documents (projects, workdirs, sessions, harness state, meta) and the event log.
Package store keeps the visor state in visor.db: documents (projects, workdirs, sessions, harness state, meta) and the event log.
Package service installs the visor as a user service and dials it.
Package service installs the visor as a user service and dials it.
Package workdir finds projects from paths and keeps workdirs: the main checkout of a repository, git worktrees, and plain folders.
Package workdir finds projects from paths and keeps workdirs: the main checkout of a repository, git worktrees, and plain folders.

Jump to

Keyboard shortcuts

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