Documentation
¶
Overview ¶
Package skill discovers ari's skills and slash commands and renders the lazy, budgeted listing block two carries. A skill is a directory with a SKILL.md; a slash command is a markdown template under commands/. Both share one frontmatter parser, one discovery walk, and one precedence rule, because the moment they drift into two config formats they drift into two sets of bugs (doc 13 section 2.6, D20).
This package reads frontmatter at discovery and bodies only on demand: the whole point of lazy loading is that a repo with fifty skills costs fifty small header reads at session start and nothing in the prompt beyond a name and one line each. Invocation, the step that injects a body into the context, is the next slice; this package stops at Body().
Index ¶
- func Budget(contextWindow int) int
- func Discover(o Options) ([]Skill, []Warning)
- func NamedArgs(s *Skill, args string) map[string]string
- func NearMatches(names []string, target string) []string
- func RenderList(skills []Skill, budget int, est Estimator) (block string, cut []string)
- func Substitute(body, args string, named map[string]string) string
- type ArgSpec
- type Estimator
- type InlineRunner
- type Invocation
- type Kind
- type Matcher
- type Options
- type Request
- type Scope
- type Skill
- type Warning
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Budget ¶
Budget is the token allowance for the skills listing: one percent of the context window, never above budgetCap. A tiny window still gets a floor of one line's worth so a single skill can always announce itself.
func Discover ¶
Discover scans the builtin, user, and project layers and returns every loadable skill and command, higher-priority scopes shadowing lower ones by name. Frontmatter is read; bodies are not. A malformed entry becomes a warning, never a failure: one broken skill must not take the session down (doc 13 section 2.3).
func NamedArgs ¶
NamedArgs maps a skill's declared arguments onto the whitespace-split argument string, so a slash command like /deploy staging fills $target when the frontmatter declares target as the first argument. Positions past the declared list are left to $ARGUMENTS and the positional $1/$2 forms.
func NearMatches ¶
NearMatches returns the discovered names closest to an unknown one, so an invalid invocation returns a helpful validation error rather than a bare miss. It is a cheap prefix-and-substring match, enough to catch a typo.
func RenderList ¶
RenderList builds the block two skills listing: one line per skill, name then description, ranked so the closest scope wins a tie and the whole thing fits the budget. The caller owns the "## Skills" heading, so this returns only the entry lines. Skills that do not fit are dropped and returned in cut, so the caller can note the elision rather than pretend everything listed (doc 13 section 2.5). ModelHidden skills never appear here: they are user-invocable only and must not tempt the model.
est measures the running block so the cut lands on the same token scale as the budget. A nil est falls back to the standard (len+3)/4 estimate.
func Substitute ¶
Substitute expands the argument placeholders in a command or skill body. It supports $ARGUMENTS (the whole argument string), $1 $2 ... (positional, whitespace-split), and $name (a declared named argument). A placeholder with no matching argument expands to empty. When the body carries no placeholder at all and arguments were passed, they are appended as a trailing "ARGUMENTS:" line, so a template that forgot to reference them still receives them rather than dropping them silently (doc 13 section 4).
Types ¶
type Estimator ¶
Estimator turns a string into a token estimate. The caller passes the same (len+3)/4 estimator the prompt builder uses, so the listing is measured in the same unit as the budget it must fit (doc 07).
type InlineRunner ¶
InlineRunner runs one command through the host's permission-gated sh path and returns its output. It is the second inline-shell gate: every command it receives has already matched the skill's allowed-tools, and it submits the command as a normal sh call so the full doc 05 pipeline, safety floor included, still decides (doc 13 section 2.7). A nil runner disables inline execution.
type Invocation ¶
Invocation is the result of invoking a skill: the processed body ready to inject as a synthetic user message, the allowed-tools rules to add to the session for the duration of the invocation, and any notes worth logging.
type Kind ¶
type Kind string
Kind separates a directory skill from a command template. They share everything else, so the distinction is one field, not two types.
type Matcher ¶
Matcher reports whether a command is permitted by the skill's declared allowed-tools rules, the first inline-shell gate. It carries the doc 05 normalization so a skill cannot smuggle a second command past a narrow allowance. The skill package holds no permission logic of its own, so the host builds this from the parsed rules and passes it in; a nil matcher denies every command, which is the safe default.
type Options ¶
type Options struct {
// Root is the project root; project skills live under Root/.ari/skills
// and commands under Root/.ari/commands, walked from Root down to Cwd
// the way project memory is (D21).
Root string
// Cwd is where the project walk ends, so a nested package's skills
// outrank the root's.
Cwd string
// GlobalDir is the user nest; user skills and commands live under it.
GlobalDir string
// Builtins is the bundled skill tree, may be nil. A test injects a
// fstest.MapFS; the binary injects its embedded FS.
Builtins fs.FS
// contains filtered or unexported fields
}
Options configures discovery across the three layers.
type Request ¶
type Request struct {
Args string // the whole argument string, for $ARGUMENTS
Named map[string]string // resolved named arguments, for $name
Match Matcher // gate one: allowed-tools membership
Inline InlineRunner // gate two: the permission-gated sh path
Trusted bool // gates three and four: a human-authored skill in a trusted session
}
Request carries everything an invocation needs from the host: the raw and resolved arguments, the two inline-shell gates, and the session trust flag.
type Scope ¶
type Scope string
Scope is where a skill was discovered, which sets its precedence and, in a later slice, whether inline shell execution is allowed.
type Skill ¶
type Skill struct {
Name string
Description string
Kind Kind
Scope Scope
Path string // the SKILL.md or command .md file
AllowedTools []string // doc 05 rule strings, active only during invocation
ArgumentHint string
Arguments []ArgSpec
ModelHidden bool // disable-model-invocation: user-invocable only
Model string // tier hint, empty for the session default
Context string // inline or fresh, empty for the default
// contains filtered or unexported fields
}
Skill is one discovered skill or command. Everything here is read from the frontmatter at discovery; the body is read only when Body is called, which is what keeps discovery cheap (doc 13 section 2.2).
func (*Skill) Body ¶
Body reads and returns the instruction body on demand, the lazy half of lazy loading. It is not read at discovery, so a listed-but-never-invoked skill costs only its frontmatter.
func (*Skill) Invoke ¶
Invoke loads the skill's body, substitutes its arguments, runs the gated inline-shell pass, and wraps the result in the invocation marker. The allowed-tools rules ride back as Grants so the host can add them to the session; they narrow what the skill's own commands may ask for, never widen what the session allows (doc 13 sections 2.5 and 2.7).