agent

package
v1.17.0 Latest Latest
Warning

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

Go to latest
Published: Aug 21, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package agent detects, without any user configuration, whether a process running inside a session is an AI coding agent CLI (claude, codex, opencode, ...) and what it is currently doing: idle, working, or waiting on the user. It never talks to the agent — only to the session's terminal emulator (pkg/screen) — so a detector that gets it wrong degrades a gutter marker, never the session itself.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Detector

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

Detector holds every loaded manifest, keyed by process name, and turns a session's foreground process plus its screen snapshot into a State. It does no I/O of its own — LoadManifests builds it once at startup, and pkg/session calls Evaluate from its drain goroutine, throttled.

func LoadManifests

func LoadManifests(overrideDir string) (*Detector, []error)

LoadManifests builds a Detector from the manifests shipped in the binary, overridden or extended by whatever is in overrideDir (typically config.AgentsDir()). A file in overrideDir whose base name matches a built-in manifest (e.g. "claude.yml") replaces it outright — manifests are ordered rule lists, so merging them field by field would be ambiguous about which side's ordering wins; a different base name adds a manifest for another agent. A missing overrideDir is not an error: the built-ins alone are what makes this phase work with zero configuration.

A manifest that fails to parse is skipped, not fatal — one broken file degrades detection for that one agent, never the whole feature. Every skip is returned as a warning for the caller to print to stderr, the same contract pkg/config's Load/Validate use.

func NewDetector

func NewDetector(manifests map[string]Manifest) *Detector

NewDetector builds a Detector from an already-loaded set of manifests, one per process name. Exported mainly for tests; LoadManifests is what pkg/session actually calls.

func (*Detector) Evaluate

func (d *Detector) Evaluate(processName, screenTail, title string) State

Evaluate returns the agent state for a session whose foreground process is processName, given the plain-text tail of its visible screen and its terminal title. StateNone means processName matches no known manifest — this is not an agent session, and the caller must not render a marker for it. A manifest match with no rule firing is StateIdle.

func (*Detector) Name added in v1.12.0

func (d *Detector) Name(processName string) (string, bool)

Name reports the manifest's declared name for processName (e.g. "claude", "codex", "opencode") — false if no manifest matches. The same lookup Evaluate does internally, split out so a caller only interested in which agent this is (pkg/gui's dashboard) does not need a screen tail or title to ask for it.

type Manifest

type Manifest struct {
	// Process is the foreground process name (as reported by the OS, e.g.
	// Linux's /proc/<pid>/comm) that selects this manifest. Matched
	// case-insensitively.
	Process string
	Rules   []Rule
}

Manifest declares how to recognize one agent CLI (by its foreground process name) and how to read its state off the screen it draws — no Go code, so a UI change in the agent is a manifest edit, not a lazyshell release.

type Rule

type Rule struct {
	State State
	// ScreenPattern, if set, must match the plain-text tail of the visible
	// screen. TitlePattern, if set, must match the terminal title (OSC 0/2).
	// At least one of the two is set; when both are, the rule only matches
	// when both do.
	ScreenPattern *regexp.Regexp
	TitlePattern  *regexp.Regexp
}

Rule is one line of a manifest: if its pattern(s) match, the session is in State. Rules are evaluated in file order and the first match wins, which is what lets a manifest author put its "blocked" rules first — see ValidateBlockedFirst.

type State

type State int

State is the four-value classification herdr popularized, and that this package's design report (RAPPORT_ANALYSE_INTEGRATION_AGENTS_IA.md) settled on: it is the split tmux does not make, between "produced output" and "is waiting for you".

const (
	// StateNone means the session's foreground process does not match any
	// known agent manifest — it is not an agent session at all, and the
	// gutter must not show a marker for it. Distinct from StateIdle, which
	// means "this is an agent, and it is not doing anything right now".
	StateNone State = iota
	StateIdle
	StateWorking
	StateBlocked
	StateDone
)

func ParseState

func ParseState(s string) (State, bool)

ParseState is String's inverse: manifest.go uses it to decode a rule's "state:" key, and pkg/hook uses it to validate a line received over an agent's hook socket — the exact same four names in both places, since a hook event and a manifest rule express the same four-value state. StateNone has no valid spelling: neither a manifest rule nor a hook event can declare "this is not an agent session" — that is the zero value for "nothing said otherwise", never something to say out loud.

func (State) String

func (s State) String() string

String is used by manifest validation errors and tests; it is not meant for the gutter, which renders a configurable glyph instead.

Jump to

Keyboard shortcuts

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