harness

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Jul 23, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package harness detects which AI agent runtime is invoking the host CLI. Detection uses the environment markers each runtime sets for its child processes — the same signals the vercel-labs skills installer keys on — so it needs no configuration and no filesystem probing.

Two detection surfaces serve two host needs. DetectAgent answers "is an agent driving this process, and which one" across every runtime with a known marker — the signal hosts use to resolve output modes (an agent gets machine-shaped output, a human terminal gets prose). Detect answers the narrower export question — "which runtime's skills-directory conventions apply" — and identifies only the harnesses with known conventions; the cobra adapter's "agent export --scope" resolution is built on it.

The environment variable AI_AGENT overrides both surfaces, letting a user or wrapper declare the invoking agent explicitly when no marker is set.

Index

Constants

View Source
const (
	// ScopeProject is the repo-local skills directory, resolved against the
	// current working directory.
	ScopeProject = "project"

	// ScopeUser is the per-user skills directory, resolved against the
	// user's home directory.
	ScopeUser = "user"
)

The two skill-installation scopes every supported harness distinguishes: skills committed with the project versus skills installed for the user account. Plain strings — they name a convention, carry no invariant, and flow straight into flag values.

Variables

View Source
var ErrUnsupportedScope = errors.New("docent: unsupported scope")

ErrUnsupportedScope is the sentinel ValidateScope and SkillsPath wrap when a scope names neither ScopeProject nor ScopeUser, so hosts can branch with errors.Is instead of matching message text.

Functions

func Agents

func Agents() []string

Agents lists the names DetectAgent can return from environment markers, in detection precedence order. AI_AGENT and AGENT=amp overrides can yield names beyond this list.

func DetectAgent

func DetectAgent(lookup func(string) (string, bool)) (string, bool)

DetectAgent identifies the AI agent runtime driving this process from the environment via lookup (typically os.LookupEnv; injected for testability).

The AI_AGENT variable, when set to a plain identifier, overrides all markers — the escape hatch for wrappers and runtimes without one; AGENT set to "amp" identifies Amp the same way. Otherwise the first entry in Agents order with a truthy marker wins. Marker values "0", "false", "no", and "off" (any case) count as unset, so an explicit CLAUDECODE=0 reads as "not this agent" rather than "agent present".

The returned name is the detected runtime's canonical identifier: a version/role qualifier some runtimes append to their override — Claude Code sets AI_AGENT to values like "claude-code_2-1-211_agent" — is stripped once here, so every consumer of the name sees the same spelling (see canonicalAgentName for the exact rule). ok is false when no agent is detected. Hosts branch on the boolean for output-mode resolution and may surface the name in diagnostics.

func EnvVars added in v0.2.0

func EnvVars() []string

EnvVars lists every environment variable detection consults: the AI_AGENT and AGENT overrides, then each agent's markers in Agents order. Hosts and tests use it to scrub or pin the whole detection surface — clearing only some variables lets a marker leaked by the invoking runtime satisfy detection. The returned slice is a fresh copy.

func ValidateScope added in v0.2.0

func ValidateScope(scope string) error

ValidateScope reports whether scope names a known skill-installation scope, returning an error wrapping ErrUnsupportedScope otherwise. It is the single spelling of scope validation: SkillsPath calls it before resolving, and adapters call it to pre-validate flag input before any harness detection.

Types

type Harness

type Harness struct {
	// Name is the runtime's identifier as reported to the user.
	Name string

	// DefaultFormat is the export format best suited to this runtime, used
	// when --scope is given without an explicit --format.
	DefaultFormat string

	// SkillsDir is the skills directory in forward-slash form, relative to
	// the scope's root: the working directory for ScopeProject, the user's
	// home directory for ScopeUser. The relative path is scope-independent
	// for every supported harness; only the root differs. SkillsPath
	// resolves it for a concrete scope.
	SkillsDir string
}

Harness identifies a detected agent runtime and its export conventions. All fields are plain data; Detect and Supported return copies, so mutating one affects nothing.

func Detect

func Detect(lookup func(string) (string, bool)) (Harness, bool)

Detect identifies the invoking agent runtime's export conventions from the environment via lookup (typically os.LookupEnv; injected for testability). It resolves the agent with DetectAgent — AI_AGENT override included — and returns the matching Supported harness, or false when no agent is detected or the detected agent has no known skills-directory conventions.

A detected name matches a harness exactly or as a separated prefix. DetectAgent already canonicalizes underscore-joined version qualifiers, so the prefix match is defense in depth for qualifier shapes that rule does not cover (e.g. hyphen-joined suffixes).

func Supported

func Supported() []Harness

Supported lists every harness Detect can identify — the runtimes with known skills-directory conventions — in detection precedence order. Callers use it to enumerate options in error messages and documentation. DetectAgent recognizes a wider set of runtimes; see Agents.

func (Harness) SkillsPath added in v0.2.0

func (h Harness) SkillsPath(scope string) (string, error)

SkillsPath resolves the harness's skills directory for a scope, in OS path form: ScopeProject returns SkillsDir relative to the working directory, ScopeUser joins it under the user's home directory. The scope-to-root mapping lives here — one authority for what a scope means — so adapters and hosts cannot disagree on where a harness's skills install. An unknown scope errors with ErrUnsupportedScope; a home directory that cannot be resolved is also an error.

Jump to

Keyboard shortcuts

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