Documentation
¶
Index ¶
- Variables
- func AgentSearchPaths() []string
- func AgentSearchPathsFor(scope Scope) []string
- func EnvKeyFor(path string) string
- type Config
- type FileOutputConfig
- type LoggingConfig
- type LokiOutputConfig
- type MetricsConfig
- type PathType
- type Scope
- type SecurityConfig
- type ShutdownConfig
- type SupervisorConfig
- type TimeoutConfig
- type TransportConfig
- type WatchdogConfig
Constants ¶
This section is empty.
Variables ¶
var ( // QUICStreamTimeout is the max time for a single QUIC stream operation. // Rationale: Covers network latency + agent marshaling/unmarshaling (< 10s typical). QUICStreamTimeout = 10 * time.Second // QUICIdleTimeout is the connection idle timeout before automatic closure. // Rationale: Balances connection reuse vs resource cleanup (1 minute idle acceptable). QUICIdleTimeout = 60 * time.Second )
QUIC Transport Timeouts
var ( // ClientPendingTimeout is the max wait for an agent to enter PENDING state. // Rationale: Fast-fail if supervisor doesn't acknowledge command quickly. ClientPendingTimeout = 2 * time.Second // ClientTerminalTimeout is the max wait for an agent to reach terminal state (RUNNING/STOPPED/FAILED). // Rationale: Covers Python startup, health checks, socket binding (< 20s for well-behaved agents). ClientTerminalTimeout = 20 * time.Second )
Client Lifecycle Timeouts
var ( // SupervisorStartDeadline is the max time for an agent to report ready after start command. // Rationale: Aligns with ClientTerminalTimeout to prevent supervisor-client mismatch. SupervisorStartDeadline = 20 * time.Second // SupervisorShutdownTimeout is the graceful shutdown timeout before force-kill. // Rationale: Allows agents to flush logs, close connections (5s is reasonable grace period). SupervisorShutdownTimeout = 5 * time.Second )
Supervisor Timeouts
var ( // TestAgentStartTimeout is the max time to wait for agent start in tests. // Rationale: CI environments may be slow; 2-minute buffer covers edge cases. TestAgentStartTimeout = 120 * time.Second // TestAgentStopTimeout is the max time to wait for agent stop in tests. // Rationale: Covers graceful shutdown + Python interpreter cleanup. TestAgentStopTimeout = 60 * time.Second )
Test Timeouts (more generous for CI environments)
Functions ¶
func AgentSearchPaths ¶
func AgentSearchPaths() []string
AgentSearchPaths returns the system-scope search path.
It is the compatibility spelling for AgentSearchPathsFor(ScopeSystem); every existing caller is a system manager.
func AgentSearchPathsFor ¶
AgentSearchPathsFor returns the ordered directories to search, highest precedence first. Discovery is first-ID-wins, so an agent found in an earlier directory MASKS one of the same ID found later - which is what makes these tiers an override mechanism rather than a concatenation.
Every directory is namespaced by the PRODUCT rather than by the kernel (GAPI-DIV-061): gapid searches /usr/lib/gapi/agents, goblind searches /usr/lib/goblin/agents. This function is reached inside goblind through agentmgr's discovery, so it is one of the kernel surfaces an operator who has never heard of gapi would otherwise meet.
THE ORDERING RULE, taken from systemd and XDG and applied to both scopes: configuration beats runtime beats data beats vendor. An operator's edit outranks a package's file, and a transient unit outranks the installed one it shadows.
System scope, highest to lowest, with <p> the product name:
- <PREFIX>_DEV_AGENTS explicit development override
- /etc/<p>/agents operator-authored
- /run/<p>/agents transient, generated at runtime
- /usr/local/lib/<p>/agents locally installed
- /usr/lib/<p>/agents package-owned
User scope, highest to lowest:
- <PREFIX>_DEV_AGENTS explicit development override
- $XDG_CONFIG_HOME/<p>/agents the user's own
- /etc/<p>/user/agents operator-provided, for all users
- $XDG_RUNTIME_DIR/<p>/agents transient
- $XDG_DATA_HOME/<p>/agents user-installed
- ~/.<p>/agents LEGACY, see below
- /usr/lib/<p>/user/agents package-owned user agents
SYSTEM SCOPE CONTAINS NO HOME-DIRECTORY PATH, and that is a security boundary rather than tidiness. agentmgr's safeToExecute already refuses world-writable or foreign-owned binaries at EXECUTION time; keeping user-writable directories out of the system list is the same defence at DISCOVERY time, and the two are not substitutes.
There is deliberately no implicit ./agents tier. It made discovery depend on the working directory a daemon happened to be started from - a daemon launched from the wrong directory silently discovered nothing, and 'agent new' run outside a checkout silently wrote a tree into whatever directory the operator was standing in. Development now names its directory explicitly through <PREFIX>_DEV_AGENTS, which is also what every test and script in this repo already did.
Environment overrides:
- <PREFIX>_AGENT_PATH: colon-separated directories PREPENDED to the tiers below. It adds precedence; it does not replace the path.
- <PREFIX>_AGENT_PATH_EXCLUSIVE: search ONLY what AGENT_PATH names.
- <PREFIX>_DEV_AGENTS: highest-priority directory in either scope.
- <PREFIX>_SKIP_SYSTEM_AGENTS: drop the package-owned tiers.
AGENT_PATH used to REPLACE the whole search path, and the replacement was load-bearing in two places rather than one, which is why the exclusive switch exists rather than the additive behaviour simply landing on its own (GAPI-DIV-063). A packaged install set AGENT_PATH to one directory, so the tiers above were dead code in the only configuration that ships; and test/adk's harness set it to fence discovery to a fixture directory, without which the checkout's own agents starve the fixtures' state transitions (GAPI-DIV-021). Additive fixes the first. The switch preserves the second, and a fence is a thing you ask for rather than a side effect of naming a directory.
func EnvKeyFor ¶
EnvKeyFor renders a dotted config path as the environment variable that overrides it: under gapid, "supervisor.pid1Mode" becomes GAPI_SUPERVISOR_PID1MODE; under goblind, GOBLIN_SUPERVISOR_PID1MODE.
The prefix was the literal "RUNTIME" until GAPI-DIV-059 and the literal "GAPI" until GAPI-DIV-061. Neither could be chosen by the process embedding the kernel, so an operator of goblind - which links this package as a library - had to configure it under a name belonging to a component they are not meant to know exists. It now comes from core/product, set once by the binary.
Both renames are HARD - no fallback reads an old spelling, decided by the operator. A deployed RUNTIME_CONFIG or, on goblind, a deployed GAPI_CONFIG therefore yields default config rather than an error, which is why each carries a release note.
Types ¶
type Config ¶
type Config struct {
Transport TransportConfig `mapstructure:"transport"`
Security SecurityConfig `mapstructure:"security"`
Metrics MetricsConfig `mapstructure:"metrics"`
Logging LoggingConfig `mapstructure:"logging"`
Timeouts TimeoutConfig `mapstructure:"timeouts"`
Supervisor SupervisorConfig `mapstructure:"supervisor"`
}
type FileOutputConfig ¶
type FileOutputConfig struct {
Enabled bool `mapstructure:"enabled"`
Path string `mapstructure:"path"`
MaxSize int `mapstructure:"maxSize"` // MB
MaxBackups int `mapstructure:"maxBackups"` // Number of old files to keep
MaxAge int `mapstructure:"maxAge"` // Days
Compress bool `mapstructure:"compress"`
}
type LoggingConfig ¶
type LoggingConfig struct {
Level string `mapstructure:"level"` // trace, debug, info, warn, error
Format string `mapstructure:"format"` // json, console
File FileOutputConfig `mapstructure:"file"`
Loki LokiOutputConfig `mapstructure:"loki"`
}
type LokiOutputConfig ¶
type MetricsConfig ¶
type PathType ¶
type PathType int
PathType represents the type of agent path
func ClassifyPath ¶
ClassifyPath reports which tier a path belongs to.
It classifies against the SAME lists that are searched, so the label a log line carries cannot drift from the precedence that produced it - they were two literal lists that disagreed about /etc before GAPI-DIV-061, and /etc's position has now changed.
type Scope ¶
type Scope int
Scope selects which tier list is searched.
It is an explicit parameter and MUST NOT be inferred from the effective uid. A system daemon commonly runs as an unprivileged service user - nix/module.nix creates exactly such a user - and deriving scope from privilege would silently flip that daemon into user scope, where it would discover a different agent set than the operator installed. systemd has the same property: 'systemctl --user' run by root manages root's USER instance, because the scope was asked for rather than deduced.
const ( // ScopeSystem is the machine-wide manager: the daemon an operator // installs and an init system starts. ScopeSystem Scope = iota // ScopeUser is the per-user manager, selected by --user. The tier // list is defined so that implementing --user is wiring rather than // a redesign of the search path. ScopeUser )
type SecurityConfig ¶
type SecurityConfig struct {
VerifyKey string `mapstructure:"verifyKey"` // Path to public key
}
type ShutdownConfig ¶
type ShutdownConfig struct {
GracePeriod string `mapstructure:"gracePeriod"`
}
type SupervisorConfig ¶
type SupervisorConfig struct {
ProductionMode bool `mapstructure:"productionMode"`
// Pid1Mode activates the Phase-0 pre-userspace boot sequence
// (subreaper, PID-1 signals, kmsg, early mounts). Off by default:
// gapid runs as an ordinary supervisor unless it IS init.
Pid1Mode bool `mapstructure:"pid1Mode"`
// NoEarlyMounts skips the mount phase (the OCI runtime owns mounts
// in a container).
NoEarlyMounts bool `mapstructure:"noEarlyMounts"`
Watchdog WatchdogConfig `mapstructure:"watchdog"`
Shutdown ShutdownConfig `mapstructure:"shutdown"`
}
type TimeoutConfig ¶
type TimeoutConfig struct {
QUICStream string `mapstructure:"quicStream"`
QUICIdle string `mapstructure:"quicIdle"`
ClientPending string `mapstructure:"clientPending"`
ClientTerminal string `mapstructure:"clientTerminal"`
SupervisorStart string `mapstructure:"supervisorStart"`
SupervisorShutdown string `mapstructure:"supervisorShutdown"`
}