Documentation
¶
Overview ¶
Package spec reads Agentfiles into structured Agentfile values.
Parsing is a two-phase process: a line scanner handles comments, heredocs, and ARG expansion, then each instruction line is parsed by a participle v2 grammar. Semantic validation runs after parsing.
Agentfile (text)
|
v
+-------------+
| Line Scanner | comments, blank lines, # syntax=
+-------------+
|
v (per instruction line)
+-------------+
| Heredoc | extract <<MARKER content
| Extractor |
+-------------+
|
v
+-------------+
| ARG | ${VAR} substitution
| Expansion |
+-------------+
|
v
+-------------+
| Participle | grammar-based instruction parsing
| Parser | FROM, RUNTIME, MODEL, NAME, CONTEXT,
| | CONFIG, BIN, ADD, LABEL, ARG
+-------------+
|
v
+-------------+
| Validation | FROM first, reserved names, required
| | config constraints
+-------------+
|
v
*Agentfile
Index ¶
Constants ¶
const ( AgentConfigLayerMediatype = "application/vnd.openotters.agent.config.v1+json" ContextLayerMediaType = "application/vnd.openotters.context.v1" AgentArtifactType = "application/vnd.openotters.agent.v1" // AgentfileMediaType marks the layer carrying the raw, // user-authored Agentfile bytes — verbatim, not a // marshal/reconstruct of the parsed spec. Build pipelines push // this alongside the context / add layers; materialisation // extracts it to <agent-root>/etc/Agentfile so the image stays // self-describing in a form an operator can read or re-build // from without a registry round-trip. The Agentfile is the // source of truth for the agent; this mediatype represents that // source as it was written. No version suffix: spec version // belongs in the SYNTAX directive inside the file itself, not // in the wire mediatype. AgentfileMediaType = "application/vnd.openotters.agentfile" // BinArtifactType marks an OCI image as an openotters bin-tool // (vnd.openotters.bin.* annotations, single binary per platform). // Lets consumers distinguish tool images from agent images without // relying on annotation-sniffing. BinArtifactType = "application/vnd.openotters.bin.v1" OctetStream = "application/octet-stream" Markdown = "text/markdown" AnnotationBinName = "vnd.openotters.bin.name" AnnotationBinPath = "vnd.openotters.bin.path" AnnotationBinDescription = "vnd.openotters.bin.description" AnnotationBinUsage = "vnd.openotters.bin.usage" DefaultBinPath = "/" DefaultUsagePath = "/USAGE.md" )
const DefaultSyntax = "openotters/agentfile:1"
DefaultSyntax is the syntax value assumed when an Agentfile omits the `# syntax=` pragma. Parse stamps this onto Agentfile.Syntax.
const DefaultTag = "latest"
Variables ¶
var SupportedSyntaxes = []string{DefaultSyntax}
SupportedSyntaxes lists every `# syntax=` value the parser accepts.
Functions ¶
func GenerateAgentMD ¶
GenerateAgentMD generates markdown documentation from an Agentfile.
func IsQualified ¶
IsQualified reports whether name carries a registry-host component. Heuristic matches containerd / docker reference parsers: the first slash-separated segment is a host when it contains "." (a TLD) or ":" (a port), or equals "localhost". Bare names like "foo" or "agents/foo" are unqualified — a caller with a default registry fills the host in via QualifyWithDefault.
Accepts either a bare name ("agents/foo") or a full reference string ("agents/foo:v1") — the trailing tag, if any, is stripped before the host-detection runs so callers don't need to ParseReference first.
func Validate ¶
Validate checks structural invariants on a programmatically constructed Agentfile: FROM is required, context name AGENT is reserved, and required configs cannot carry a default value. Parse already runs Validate; callers who build an Agentfile in code should call Validate themselves.
Types ¶
type Agent ¶
type Agent struct {
From string `json:"from"`
Runtime string `json:"runtime,omitempty"`
Model string `json:"model,omitempty"`
Name string `json:"name,omitempty"`
Contexts []*Context `json:"contexts,omitempty"`
Configs []*Config `json:"configs,omitempty"`
Bins []*Bin `json:"bins,omitempty"`
Adds []*Add `json:"adds,omitempty"`
Exec []string `json:"exec,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
Args map[string]string `json:"args,omitempty"`
Envs []*Env `json:"envs,omitempty"`
// RuntimeMounts is a runtime-only side-channel populated by
// spec.WithMounts. Not serialised — Agentfiles do not have a
// MOUNT directive; mounts live with the launch invocation
// (`otters run -v ...`). Both executors read this slice at
// Create time to attach the user's bind mounts to the agent.
RuntimeMounts []*Mount `json:"-"`
}
type Env ¶
type Env struct {
Key string `json:"key"`
Value string `json:"value"`
Description string `json:"description,omitempty"`
}
Env declares an OS environment variable to be set on the spawned agent process. Unlike Config (a runtime-SDK knob the agent reads via the runtime API) and Arg (build-time substitution), Env values land directly on os/exec's Cmd.Env (system executor) and container.Config.Env (docker executor).
Reserved keys (PATH, HOME, XDG_*, TMPDIR, LANG, OTTERS_AGENT_ROOT, any *_API_KEY / *_API_BASE) are rejected by Validate to keep the locked-down env contract intact.
type Mount ¶
Mount is the runtime-only spec for a host-path → in-agent binding declared by `otters run -v HOST:TARGET[:DESC][:ro|:rw]`. Mirrors executor.Mount one-to-one; kept in spec/ so spec.Override (Agentfile mutator) can carry it without a circular import on executor.
type Override ¶
type Override func(*Agentfile)
Override mutates a parsed Agentfile. Overrides are applied via Apply and are intended for runtime field replacements (model, runtime image, etc.) coming from CLI flags or daemon config. Kept distinct from spec.Config, which is a data record declared in the Agentfile itself.
func WithExtraEnvs ¶
func WithMounts ¶
WithExtraEnvs appends additional ENV declarations to the parsed Agentfile. Used by the daemon to surface per-run env overrides (`otters run -e KEY=VAL`) through the same plumbing as the Agentfile-declared envs. Validate runs after Apply so reserved keys (PATH, *_API_KEY, etc.) are still rejected before the agent starts; the override is additive — duplicate keys win against the Agentfile-declared value. WithMounts attaches user mounts to the agent. The spec doesn't have a MOUNT directive (mounts live on the run invocation), but the override piggybacks through Agent.RuntimeMounts so the executor backends pick them up at Create time without a separate call-time channel.
type Reference ¶
Reference identifies an OCI image by name and tag. Name can be local ("meteo") or remote ("ghcr.io/openotters/agents/meteo"). Tag defaults to "latest" when not specified.
func ParseReference ¶
ParseReference parses a reference string in the form "name" or "name:tag". The tag is the part after the last colon that follows the last slash. This correctly handles host:port/name:tag references.
func QualifyWithDefault ¶
QualifyWithDefault returns ref with defaultRegistry prepended to its Name iff Name isn't already qualified. defaultRegistry should not include a scheme or trailing slash; an empty defaultRegistry is a no-op (callers without a default fall back to the unmodified ref).
type ReferenceWithDigest ¶
ReferenceWithDigest pairs a Reference with a content-addressed digest from the OCI store.
func (ReferenceWithDigest) String ¶
func (r ReferenceWithDigest) String() string
String returns "name:tag@digest".