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

harness

package
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: 23 Imported by: 0

Documentation

Overview

Package harness detects, installs, updates, and logs in to the vendor agent CLIs, and lists their models. The vendor facts come from agent-wire.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrStale is a write with an old etag.
	ErrStale = errors.New("harness: the file changed since the read")
	// ErrNoBackup means that no backup of the own copy exists.
	ErrNoBackup = errors.New("harness: no backup")
)

Home file errors.

View Source
var (
	ErrNotFound    = errors.New("harness: not found")
	ErrInvalid     = errors.New("harness: invalid request")
	ErrState       = errors.New("harness: wrong state")
	ErrBusy        = errors.New("harness: busy")
	ErrUnsupported = errors.New("harness: not supported")
)

Errors.

Functions

This section is empty.

Types

type AuthMode

type AuthMode string

AuthMode tells which login a harness uses.

const (
	// AuthShared uses the login of the user. The harness home links it.
	AuthShared AuthMode = "shared"
	// AuthSeparate uses a login of the visor only, in <home>/harness/<name>.
	AuthSeparate AuthMode = "separate"
)

Auth modes.

type AuthState

type AuthState string

AuthState is the login state of a harness.

const (
	AuthUnknown AuthState = "unknown"
	AuthOK      AuthState = "ok"
	AuthMissing AuthState = "missing"
	AuthExpired AuthState = "expired"
)

Auth states.

type Facts

type Facts struct {
	Recipe          func(h agentwire.Harness) (agentwire.InstallRecipe, bool)
	LoginCommand    func(h agentwire.Harness, o agentwire.LoginOptions) ([]string, error)
	LogoutCommand   func(h agentwire.Harness) []string
	LoginEnv        func(h agentwire.Harness, home string) map[string]string
	CredentialFiles func(h agentwire.Harness) []string
	AuthStatus      func(ctx context.Context, h agentwire.Harness, home string) (agentwire.AuthState, error)
	// Binary finds the program of a harness that agent-wire does not find,
	// such as a test harness of the product. Nil finds none.
	Binary func(h agentwire.Harness) string
}

Facts are the vendor facts with no runtime. A nil field uses agent-wire. Tests replace them.

type FileContent added in v0.2.0

type FileContent struct {
	Key     string `json:"key"`
	Side    string `json:"side"`
	Content string `json:"content"`
	ETag    string `json:"etag"`
}

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

type Harness

type Harness struct {
	Name      string `json:"name"`
	Installed bool   `json:"installed"`
	Version   string `json:"version,omitempty"`
	// Latest is the newest vendor release, when known.
	Latest string `json:"latest,omitempty"`
	Path   string `json:"path,omitempty"`
	Source Source `json:"source,omitempty"`
	// Installs are the versions that the visor installed, oldest first.
	Installs []string `json:"installs,omitempty"`
	// Installable means that the visor can install its own copy.
	Installable bool `json:"installable"`
	// Supported means that the installed version meets the agent-wire floor.
	Supported bool `json:"supported"`
	// Detail tells why the harness is not usable.
	Detail   string    `json:"detail,omitempty"`
	AuthMode AuthMode  `json:"auth_mode"`
	Auth     AuthState `json:"auth"`
	// EnvKeys lists the harness env keys. The values never leave the visor.
	EnvKeys []string `json:"env_keys,omitempty"`
	Limits  *Limits  `json:"limits,omitempty"`
	// Updates is the update mode. KeptAt is when keep mode started.
	Updates UpdateMode `json:"updates"`
	KeptAt  *time.Time `json:"kept_at,omitempty"`
	// Pending means that an update waits for the end of the live sessions.
	Pending  bool `json:"pending,omitempty"`
	Updating bool `json:"updating,omitempty"`
	// History holds the last version changes, oldest first.
	History []Update `json:"history,omitempty"`
	// Models is the fixed model list. Manager.Models gives the live list.
	Models []Model `json:"models,omitempty"`
	// Login is the login that runs now, or nil.
	Login *Login `json:"login,omitempty"`
}

Harness is one vendor agent CLI on this machine.

type HomeFile added in v0.2.0

type HomeFile struct {
	Key    string                 `json:"key"`
	Kind   agentwire.HomeFileKind `json:"kind"`
	Format string                 `json:"format,omitempty"`
	// Shared means that the home uses the user file. Else the home keeps
	// its own copy.
	Shared bool `json:"shared"`
	// Login marks a login file. The auth mode decides its share.
	Login bool `json:"login,omitempty"`
	// Hooks marks a file that holds user hooks.
	Hooks bool `json:"hooks,omitempty"`
	// Locked means that the policy or the auth mode decides the share.
	Locked bool `json:"locked,omitempty"`
	// Blocked means that the home holds a real file where a shared file
	// links to the user file. The home uses its own copy until the user
	// removes it.
	Blocked    bool       `json:"blocked,omitempty"`
	UserPath   string     `json:"user_path"`
	HomePath   string     `json:"home_path"`
	UserExists bool       `json:"user_exists"`
	UserModAt  *time.Time `json:"user_modified_at,omitempty"`
	// OwnSince is when the home made its own copy.
	OwnSince *time.Time `json:"own_since,omitempty"`
	// UserChanged means that the user file changed after OwnSince.
	UserChanged bool `json:"user_changed_since_own,omitempty"`
	// BackupUntil is when the newest backup of an own copy expires.
	BackupUntil *time.Time `json:"backup_until,omitempty"`
}

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

type Launch

type Launch struct {
	// Binary is the visor copy. Empty searches PATH.
	Binary string
	// Home is the harness home that the visor builds. Empty uses the user
	// home of the harness.
	Home string
	// Env is the harness env layer.
	Env map[string]string
	// Args are launch args that the harness needs, before the session args.
	Args []string
}

Launch is what a session start needs from the harness.

type LimitWindow

type LimitWindow struct {
	Key         string    `json:"key"`
	Scope       string    `json:"scope,omitempty"`
	Minutes     int       `json:"minutes,omitempty"`
	UsedPercent float64   `json:"used_percent"`
	ResetsAt    time.Time `json:"resets_at,omitzero"`
}

LimitWindow is the use of one plan limit window.

type Limits

type Limits struct {
	Plan     string        `json:"plan,omitempty"`
	Rejected bool          `json:"rejected,omitempty"`
	Windows  []LimitWindow `json:"windows,omitempty"`
}

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

type Login

type Login struct {
	Harness string     `json:"harness"`
	Phase   LoginPhase `json:"phase"`
	// URL is the address that the user opens.
	URL string `json:"url,omitempty"`
	// Code is the device code that the user types on that page.
	Code string `json:"code,omitempty"`
	// AwaitCode means that the vendor asks for a pasted code. A terminal
	// login takes it with LoginCode; a pipe login cannot.
	AwaitCode bool `json:"await_code,omitempty"`
	// InApp means that the harness logs in only inside its own terminal
	// view. No login process runs.
	InApp bool   `json:"in_app,omitempty"`
	Error string `json:"error,omitempty"`
	Hint  string `json:"hint,omitempty"`
	// Session is the terminal session of the login, when the visor runs
	// it in a terminal. A client can attach to it.
	Session string `json:"session,omitempty"`
	// Screen is the end of the login screen.
	Screen string `json:"screen,omitempty"`
	// Done means that the login process ended.
	Done      bool      `json:"done,omitempty"`
	StartedAt time.Time `json:"started_at,omitzero"`
	EndedAt   time.Time `json:"ended_at,omitzero"`
}

Login is the state of a vendor login. A token that the vendor prints never goes in it.

type LoginPhase added in v0.2.0

type LoginPhase string

LoginPhase is the step of a login.

const (
	LoginStarting  LoginPhase = "starting"
	LoginBrowser   LoginPhase = "awaiting_browser"
	LoginCode      LoginPhase = "awaiting_code"
	LoginVerifying LoginPhase = "verifying"
	LoginDone      LoginPhase = "done"
	LoginFailed    LoginPhase = "failed"
)

Login phases.

type LoginSpec added in v0.2.0

type LoginSpec struct {
	// Provider is the model provider of a harness with many providers.
	Provider string `json:"provider,omitempty"`
}

LoginSpec asks for a login.

type Manager

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

Manager keeps the harness inventory of one visor.

func New

func New(home string, st *store.Store, wire Wire, o Options) *Manager

New makes the manager of the harnesses under home.

func (*Manager) Busy

func (m *Manager) Busy() bool

Busy reports that a login, an install, or an update runs.

func (*Manager) CancelLogin added in v0.2.0

func (m *Manager) CancelLogin(ctx context.Context, name string)

CancelLogin stops a running login.

func (*Manager) Check added in v0.2.0

func (m *Manager) Check(ctx context.Context)

Check does one pass of Run.

func (*Manager) Close

func (m *Manager) Close(ctx context.Context) error

Close stops the logins and the release lookups.

func (*Manager) Files added in v0.2.0

func (m *Manager) Files(ctx context.Context, name string) ([]HomeFile, error)

Files lists the home files of a harness.

func (*Manager) Harness

func (m *Manager) Harness(ctx context.Context, name string) (Harness, error)

Harness gives one harness.

func (*Manager) Install

func (m *Manager) Install(ctx context.Context, name, version string) (Harness, error)

Install installs a visor copy of the harness in bin/<name>/<version>/ and moves the current link to it. An empty version is the latest release. A harness with no npm recipe runs the vendor install instead, and gets the latest release. A failed install leaves the current link as it was. It returns ErrBusy when a live session uses the harness, because the switch must not change the binary under a running session.

func (*Manager) Launch

func (m *Manager) Launch(ctx context.Context, name string) (Launch, error)

Launch gives what a session of the harness needs. An unknown harness gives the zero Launch, so a session with no inventory entry still starts.

func (*Manager) List

func (m *Manager) List(ctx context.Context) ([]Harness, error)

List gives each known harness.

func (*Manager) Login

func (m *Manager) Login(ctx context.Context, name string, spec LoginSpec) (Login, error)

Login starts the vendor login of the harness, in the login home of its auth mode. It returns when the vendor shows a URL or a code, when the process ends, or after Options.LoginWait. The process runs on until the user ends the login, or until Options.LoginTimeout. A second call while a login runs gives the same login. At the end, the visor checks the login.

func (*Manager) LoginCode added in v0.2.0

func (m *Manager) LoginCode(ctx context.Context, name, code string) (Login, error)

LoginCode types a pasted code into a terminal login.

func (*Manager) LoginState added in v0.2.0

func (m *Manager) LoginState(name string) (Login, bool)

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

func (*Manager) LoginToken added in v0.2.0

func (m *Manager) LoginToken(ctx context.Context, name, token string) (Harness, error)

LoginToken keeps a token or an API key as the login of the harness. It goes into the harness env.

func (*Manager) Logout

func (m *Manager) Logout(ctx context.Context, name string) error

Logout runs the vendor logout in the login home of the auth mode. With no vendor logout, a separate login removes its credential files. A token in the harness env goes too.

func (*Manager) Models

func (m *Manager) Models(ctx context.Context, name string) ([]Model, error)

Models lists the models of a harness: the live list when the harness gives one, else the fixed list.

func (*Manager) OwnFile added in v0.2.0

func (m *Manager) OwnFile(ctx context.Context, name, key string, start OwnStart) (HomeFile, error)

OwnFile makes an own copy of a home file. The copy starts from the user file, from nothing, or from the newest backup.

func (*Manager) ReadFile added in v0.2.0

func (m *Manager) ReadFile(ctx context.Context, name, key, side string) (FileContent, error)

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

func (*Manager) Run added in v0.2.0

func (m *Manager) Run(ctx context.Context)

Run checks the harnesses each minute until ctx ends: it looks for a new release each Options.CheckEvery, records an update outside the visor, and runs the auto and the waiting updates.

func (*Manager) SetAuthMode

func (m *Manager) SetAuthMode(ctx context.Context, name string, mode AuthMode) (Harness, error)

SetAuthMode moves the harness to a shared or a separate login. A live session keeps its login; the next session gets the new one.

func (*Manager) SetEnv

func (m *Manager) SetEnv(_ context.Context, name string, env map[string]string) error

SetEnv replaces the env of a harness. An empty env removes it. The file has mode 0600.

func (*Manager) SetLimits

func (m *Manager) SetLimits(ctx context.Context, name string, l Limits)

SetLimits keeps the last plan limits that a session of the harness saw.

func (*Manager) SetUpdates added in v0.2.0

func (m *Manager) SetUpdates(ctx context.Context, name string, mode UpdateMode, version string) (Harness, error)

SetUpdates sets the update mode. Keep with a version moves to that version first; an empty version keeps the version that runs now.

func (*Manager) ShareFile added in v0.2.0

func (m *Manager) ShareFile(ctx context.Context, name, key string) (HomeFile, error)

ShareFile makes the home use the user file again. An own copy moves to the backups for 30 days.

func (*Manager) TrustDir added in v0.4.2

func (m *Manager) TrustDir(name, dir string) error

TrustDir marks dir as a trusted folder in the separate home of a harness, so that the vendor CLI shows no folder trust dialog there. The start of a session in dir is the approval. A harness with no trust file changes nothing.

func (*Manager) Update

func (m *Manager) Update(ctx context.Context, name, version string) (Harness, error)

Update updates the harness. A visor copy gets a new visor copy. A system install runs the vendor update, after a copy of the old program. A check after the update needs a version and, when the login worked before, a working login. A failed check goes back to the old program. When a live session uses the harness, the update waits for its end and Update returns ErrBusy.

func (*Manager) WriteFile added in v0.2.0

func (m *Manager) WriteFile(ctx context.Context, name, key, content, ifMatch string) (FileContent, error)

WriteFile replaces the own copy of a home file. An empty ifMatch skips the etag check. A stale write gives ErrStale and the current content.

type Model

type Model struct {
	ID          string `json:"id"`
	Name        string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
	Default     bool   `json:"default,omitempty"`
	// Efforts are the effort levels, from low to high.
	Efforts []string `json:"efforts,omitempty"`
}

Model is one model that a harness offers.

type Options

type Options struct {
	// Names are the harnesses that the manager knows. Empty means each
	// agent-wire harness with an install recipe.
	Names []string
	// Path is the search path for the install tools, such as npm. Empty
	// uses PATH.
	Path  string
	Facts Facts
	// LoginWait is how long Login waits for a URL or a code. Zero is 20 s.
	LoginWait time.Duration
	// LoginTimeout stops a login that does not end. Zero is 10 min.
	LoginTimeout time.Duration
	// InUse reports that a live session uses the harness. The visor sets it.
	InUse func(name string) bool
	// Enabled reports that the visor checks and updates a harness, also a
	// binary that the visor did not install. Nil checks only the visor
	// copies.
	Enabled func(name string) bool
	// CheckEvery is the time between two looks for a new release. Zero is
	// 6 h.
	CheckEvery time.Duration
	// Terminal runs the logins in terminal sessions. Nil runs them with a
	// pipe, which cannot take a pasted code.
	Terminal Terminal
	// OnChange gets the name of a harness that changed. The visor sets it.
	OnChange func(name string)
	// Policy is the product policy for the harness homes.
	Policy Policy
	// UserHome is the home folder of the user. Empty uses the home of the
	// process user.
	UserHome string
	Logger   *slog.Logger
}

Options configures a Manager.

type OwnStart added in v0.2.0

type OwnStart string

OwnStart is the first content of an own copy.

const (
	SideUser = "user"
	SideHome = "home"

	OwnFromUser   OwnStart = "user"
	OwnFromEmpty  OwnStart = "empty"
	OwnFromBackup OwnStart = "backup"
)

File sides and own starts.

type Policy added in v0.2.0

type Policy struct {
	// MCPServers go into the MCP file of each harness home.
	MCPServers []agentwire.MCPServer
	// NoUserHooks keeps the user hooks out of the harness homes.
	NoUserHooks bool
	// Share changes the default share of a home file, by harness and key.
	Share map[string]map[string]bool
	// Keys are values that the home files must hold, by harness.
	Keys map[string][]agentwire.HomeKey
	// Files gives the product files of a harness home, by path relative to
	// the home. The visor writes a file when its content changes. The
	// function can read the home. It runs on each launch.
	Files func(name, home string) map[string][]byte
}

Policy is the product policy for the harness homes.

type Source

type Source string

Source tells where the harness binary comes from.

const (
	SourceVisor  Source = "visor"
	SourceSystem Source = "system"
)

Sources.

type Terminal added in v0.2.0

type Terminal interface {
	Start(ctx context.Context, name string, argv []string, dir string, env map[string]string) (string, error)
	// Screen gives the screen text and whether the session still runs.
	Screen(ctx context.Context, id string) (string, bool, error)
	Send(ctx context.Context, id, text string) error
	Stop(ctx context.Context, id string) error
}

Terminal runs a login in a terminal session. The visor sets it.

type Update added in v0.2.0

type Update struct {
	At    time.Time `json:"at"`
	From  string    `json:"from,omitempty"`
	To    string    `json:"to,omitempty"`
	OK    bool      `json:"ok"`
	Error string    `json:"error,omitempty"`
	// Outside means that the harness changed outside the visor.
	Outside bool `json:"outside,omitempty"`
}

Update is one version change of a harness.

type UpdateMode added in v0.2.0

type UpdateMode string

UpdateMode tells how the visor updates a harness.

const (
	// UpdatesAuto updates to each new release when no session uses the
	// harness.
	UpdatesAuto UpdateMode = "auto"
	// UpdatesKeep keeps the version. A system install runs from a kept
	// copy, so the vendor update cannot change it.
	UpdatesKeep UpdateMode = "keep"
)

Update modes.

type Wire

type Wire interface {
	Detect(ctx context.Context, h agentwire.Harness) (agentwire.Detection, error)
	Version(ctx context.Context, bin string) string
	Models(ctx context.Context, h agentwire.Harness, q agentwire.ModelQuery) ([]agentwire.ModelInfo, error)
	LatestVersion(ctx context.Context, h agentwire.Harness) (string, error)
	InvalidateModels(h agentwire.Harness)
}

Wire is what the manager needs from the agent-wire runtime.

Jump to

Keyboard shortcuts

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