Skip to documentation
Documentation navigation

Documentation navigation

Documentation / guides

Skill

Load embedded or workspace skills through an agent-scoped loader.

developer

Skill loads one named SKILL.md body on demand. The tool is constructed for one identity.AgentName and receives a narrow SkillLoader. The loader owns the closed allow-set and the body source, so the tool never holds a product catalog or guesses a path.

Embedded and Workspace Sources

NewSkill(loader, agent) is embedded-only. A name is authorized through SkillLoader.Allowed, then loaded from the curated embedded filesystem. An unknown name fails securely. Embedded names win even when workspace loading is enabled, so an attacker cannot shadow a curated skill with a same-named file.

WithWorkspaceRoot(root) enables a second, untrusted source for non-embedded names. Preparation validates the name, takes a TOCTOU-safe snapshot of .skills/<name>/SKILL.md, and emits a combined request: one context.load requirement scoped to workspace:<name> plus a filesystem read requirement for the canonical snapshot path. InvokableRun returns the approved snapshot body and never re-reads the file.

The embedded request uses context.load scoped to embedded:<name>. These requirements have no durable permission candidate because context loading is a product-owned capability, not an executor grant. AuditSummary includes only the skill name, never the body.

// The closed allow-set is checked before a path is constructed.
loader := skill.NewEmbeddedSkillLoader(catalogue, map[identity.AgentName]map[string]struct{}{
	"reviewer": {"check": {}},
})
skills := skill.NewSkill(loader, identity.AgentName("reviewer"))
request, artifact, err := skills.PrepareCall(ctx, executionID, `{"name":"check"}`)
if err != nil {
	panic(err)
}
prepared := loop.WithPreparedCall(ctx, tool.PreparedCall{
	ExecutionID: executionID,
	Request: request,
	Artifact: artifact,
})
result, err := skills.InvokableRun(prepared, `{}`)

The embedded skill fixture shows both a permitted load and an unknown-name error. For the general prepare-before-effect contract, see Tool Definitions, Preparation, and Results. For model tool content, see Inference’s tool-use blocks.

Source

Proof

← back to documentation