Documentation
¶
Overview ¶
Package skills is the in-repo adapter for Agent Skills. The READ-ONLY core (discovery, source, and Skill tool) graduated into the importable engine module (engine/adapter/skillfs, issue #328) and is re-exported here via thin type/func/const aliases; the writable SkillDraft half stays in this package and reaches the core through those aliases. See alias.go and the skillfs package doc for the real contract.
Index ¶
- Constants
- func Discover(dir string) ([]Skill, []SkipError, error)
- func ImportLegacyDraft(ctx context.Context, repo learning.SkillRepository, ...) (learning.SkillVersion, error)
- func Jaccard2Gram(a, b string) float64
- func NewDraftTool(d Drafter) tool.Tool
- func NewFSSource(ctx context.Context, sources ...Source) (*FSSource, []SkipError, error)
- func NewSkillCommandSource(metas []tool.SkillMeta, source tool.SkillSource) prompt.CommandSource
- func Promote(quarantineDir, activeDir, name string) error
- func ReadCandidate(quarantineDir, name string) ([]byte, error)
- func Register(cat *tool.Catalog, dir string) ([]Skill, []SkipError, error)
- func RegisterSource(ctx context.Context, cat *tool.Catalog, src Source) ([]Skill, []SkipError, error)
- func ScanForInjection(s string) (marker string, found bool)
- func ValidSkillName(name string) bool
- type DirDrafter
- type DirSource
- type DraftOption
- type DraftRequest
- type DraftResult
- type DraftTool
- type Drafter
- type FSSource
- type LifecycleDrafter
- type MultiSource
- type ResolveOptions
- type Skill
- type SkipError
- type Source
- type Tool
Constants ¶
const ( MaxLicenseBytes = skillfs.MaxLicenseBytes MaxCompatibilityBytes = skillfs.MaxCompatibilityBytes MaxMetadataEntries = skillfs.MaxMetadataEntries MaxMetadataValueBytes = skillfs.MaxMetadataValueBytes MaxAllowedTools = skillfs.MaxAllowedTools MaxAllowedToolNameBytes = skillfs.MaxAllowedToolNameBytes )
MaxLicenseBytes, MaxCompatibilityBytes, MaxMetadataEntries, and MaxMetadataValueBytes are the advisory caps for the optional license/ compatibility/metadata frontmatter. See the skillfs constants. Exported so the remote-driver client (grpcdriver) re-clamps defensively to the SAME caps the parser uses.
MaxAllowedTools and MaxAllowedToolNameBytes are the advisory caps for the optional `allowed-tools` frontmatter (agentskills.io, Experimental). Same export rationale.
const DefaultDir = skillfs.DefaultDir
DefaultDir is the conventional project-level skills directory. See skillfs.DefaultDir.
const DefaultSimilarityThreshold = 0.5
DefaultSimilarityThreshold is the default 2-gram Jaccard similarity above which a candidate's description is flagged as a near-duplicate of an existing skill. It WARNS (returned in DraftResult.SimilarSkills); it never blocks — the model decides whether to refine or proceed.
const DraftToolName = "SkillDraft"
DraftToolName is the catalog name of the writable skill-authoring tool.
const MaxDescriptionBytes = skillfs.MaxDescriptionBytes
MaxDescriptionBytes caps a skill's one-line description. See skillfs.MaxDescriptionBytes.
const ProjectDirClaude = skillfs.ProjectDirClaude
ProjectDirClaude is the Claude-Code-compatible project-level skills dir. See skillfs.ProjectDirClaude.
const ProjectDirMecatl = skillfs.ProjectDirMecatl
ProjectDirMecatl is the project-level skills dir under the workspace. See skillfs.ProjectDirMecatl.
const QuarantineSubdir = "skills-quarantine"
QuarantineSubdir is the conventional name of the quarantine directory the DirDrafter writes candidate skills into when the composition root derives the quarantine location from a base directory. The quarantine dir is NEVER served to the live catalog (see the trust boundary in doc.go); it is only read by the novelty check and the promote CLI.
const SkillFileName = skillfs.SkillFileName
SkillFileName is the conventional file every skill directory contains. See skillfs.SkillFileName.
const ToolName = skillfs.ToolName
ToolName is the catalog name of the single skills tool. See skillfs.ToolName.
Variables ¶
This section is empty.
Functions ¶
func ImportLegacyDraft ¶
func ImportLegacyDraft(ctx context.Context, repo learning.SkillRepository, partition learning.SkillPartition, owner, quarantineDir, name string, inventory []learning.SkillInventoryItem) (learning.SkillVersion, error)
ImportLegacyDraft explicitly imports one origin:model quarantine candidate into the evaluated lifecycle as an unevidenced agent-owned Draft. It rejects assets, scripts, and inventory collisions; it never stages or activates the result.
func Jaccard2Gram ¶
Jaccard2Gram returns the 2-gram (character-bigram) Jaccard similarity between a and b, in [0,1]: |A∩B| / |A∪B| over the SET of adjacent character pairs of each (case-folded, whitespace-collapsed). It is an offline, dependency-free, near-oracle novelty signal — no embeddings, no network — used to flag a candidate skill's description as a near-duplicate of an existing one.
Identical strings score 1.0; strings with no shared bigram score 0.0. Two strings shorter than one bigram each (e.g. both empty) score 1.0 when equal, 0.0 otherwise.
func NewDraftTool ¶
NewDraftTool constructs the SkillDraft tool bound to d. d must be non-nil; the composition root registers this tool only when a quarantine dir is configured.
func NewFSSource ¶
NewFSSource resolves the given sources ONCE and returns the snapshot source plus the aggregated discovery diagnostics. See skillfs.NewFSSource.
func NewSkillCommandSource ¶
func NewSkillCommandSource(metas []tool.SkillMeta, source tool.SkillSource) prompt.CommandSource
NewSkillCommandSource builds a prompt.CommandSource over the resolved logical source so each discovered skill is invocable as /<skill-name>.
func Promote ¶
Promote moves a quarantined candidate skill <quarantineDir>/<name>/ into the operator's active <activeDir>/<name>/, re-running structural validation as defense in depth.
This is the legacy operator/manual filesystem workflow. It does not read or activate lifecycle repository records. New integrations should use ImportLegacyDraft and evaluate/stage/activate through SkillRepository.
It is the OPERATOR gate: the only path from model-authored quarantine to the live, trusted skill catalog. It requires filesystem access the model does not have, and is invoked by the `mecated skills promote` subcommand, never by a tool.
It fails (and moves nothing) when:
- name is not a valid activation name,
- the candidate is missing or unreadable,
- the candidate lacks `origin: model` provenance (only model-drafted candidates may be promoted),
- the candidate fails structural validation (parseSkill) or the injection scan (so an attacker who somehow planted a quarantine file cannot promote instruction-laden content),
- a skill with that name already exists under activeDir (no silent overwrite).
Promote performs no human review itself: the `mecated skills promote` CLI shows the operator the full candidate (ReadCandidate) and requires confirmation before calling this. The injection scan here is a backstop, not a substitute for a human reading the body. The move is a directory rename, so the provenance frontmatter (origin: model, drafted_at) is carried over for the audit trail.
func ReadCandidate ¶
ReadCandidate returns the raw SKILL.md bytes of a quarantined candidate, for the operator to review before promoting. It validates the name (so a traversal name cannot read outside the quarantine) and returns a clear error when the candidate is absent.
func Register ¶
Register discovers skills under a single directory and registers the Skill tool. See skillfs.Register.
func RegisterSource ¶
func RegisterSource(ctx context.Context, cat *tool.Catalog, src Source) ([]Skill, []SkipError, error)
RegisterSource discovers skills from src and, when at least one valid skill is found, registers a single Skill tool into cat. See skillfs.RegisterSource.
func ScanForInjection ¶
ScanForInjection scans s for any disallowed instruction-injection / role- override marker. See skillfs.ScanForInjection.
func ValidSkillName ¶
ValidSkillName reports whether name is a valid skill activation name under the shared grammar. It is exported so this package's writable half (the DirDrafter's validateName) routes through the SAME validator the read-only discovery core uses — a single source of truth, not two regexes to drift. See skillfs.ValidSkillName.
Types ¶
type DirDrafter ¶
type DirDrafter struct {
// contains filtered or unexported fields
}
DirDrafter is the local-filesystem Drafter. It writes candidates as <QuarantineDir>/<name>/SKILL.md with a provenance-stamped frontmatter, reusing parseSkill/validateName for validation and a snapshot of the active skill descriptions (taken at construction) for the offline novelty check.
func NewDirDrafter ¶
func NewDirDrafter(quarantineDir string, existing []Skill, opts ...DraftOption) *DirDrafter
NewDirDrafter builds a DirDrafter that writes quarantined candidates under quarantineDir and runs the novelty check against existing (a snapshot of the currently active skills). quarantineDir must be a directory the model has NO other write path into (the composition root enforces this with a governance deny rule on Write/Edit and asserts the dir is disjoint from every active skills dir).
func (*DirDrafter) Draft ¶
func (d *DirDrafter) Draft(ctx context.Context, req DraftRequest) (DraftResult, error)
Draft validates, sanitizes, novelty-checks, and atomically writes the candidate. On any validation/sanitization failure it returns ("", err) with NO file written. The novelty check never blocks: a near-duplicate is reported in DraftResult.SimilarSkills/Warnings and the candidate is still written.
type DirSource ¶
DirSource is the local-OS-filesystem implementation of Source. See skillfs.DirSource.
type DraftOption ¶
type DraftOption func(*DirDrafter)
DraftOption configures a DirDrafter.
func WithClock ¶
func WithClock(now func() time.Time) DraftOption
WithClock injects a deterministic time source for the `drafted_at` provenance stamp (tests pass a fixed clock). The default is time.Now.
func WithNeutralValidation ¶
func WithNeutralValidation(enabled bool) DraftOption
WithNeutralValidation controls the shared logical skill validator. Validation is enabled by default; false is the explicit compatibility escape hatch for a host that has not yet migrated its legacy quarantine policy.
func WithSimilarityThreshold ¶
func WithSimilarityThreshold(t float64) DraftOption
WithSimilarityThreshold overrides the 2-gram Jaccard threshold above which the novelty check flags a near-duplicate description. Values outside (0,1] are ignored (the default stands).
type DraftRequest ¶
type DraftRequest struct {
// Name is the proposed activation name (frontmatter `name`).
Name string
// Description is the one-line, always-in-context metadata (frontmatter
// `description`). It is scanned for injection markers because, if the skill
// were ever promoted, it would join the always-in-context layer.
Description string
// Body is the markdown instructions (loaded on activation).
Body string
}
DraftRequest is one candidate skill the model proposes. It is UNTRUSTED model output: every field is sanitized and validated by the Drafter before any byte touches disk.
type DraftResult ¶
type DraftResult struct {
// Path is where the candidate was written (under the quarantine dir), or ""
// when nothing was written (a validation/sanitization failure).
Path string
// SimilarSkills lists existing skill names whose description is a near-duplicate
// of the candidate's (at/above the similarity threshold). It is a warning, not
// a block.
SimilarSkills []string
// Warnings holds non-fatal notes (e.g. description truncation, similarity over
// the threshold) the tool surfaces to the model.
Warnings []string
}
DraftResult reports the outcome of a draft attempt for the model to read back.
type DraftTool ¶
type DraftTool struct {
// contains filtered or unexported fields
}
DraftTool is the writable skill-authoring tool. It is MUTATING (ReadOnly() == false): it writes a candidate SKILL.md to the quarantine via the injected Drafter. Because it is mutating, the dispatcher runs it alone/serially and the catalog filters it out of plan mode. The Drafter is constructor- injected, the write-side mirror of how the read-only Skill tool takes a Source.
func (DraftTool) Execute ¶
func (t DraftTool) Execute(ctx context.Context, in session.ToolCall, env tool.Environment) (session.ToolResult, error)
Execute validates and quarantines the candidate skill. A validation/ sanitization failure is returned as a model-addressable error result (never a harness-level Go error), so the model can revise and retry. On success the result names the quarantine path and any near-duplicate warnings.
type Drafter ¶
type Drafter interface {
// Draft validates req, runs the novelty check, and on success writes the
// candidate SKILL.md under the quarantine dir. A validation/sanitization
// failure returns a non-nil error whose message is model-addressable (the
// SkillDraft tool turns it into a NewToolError, never a harness fault) and
// DraftResult.Path is "" (no file written).
Draft(ctx context.Context, req DraftRequest) (DraftResult, error)
}
Drafter is the WRITE seam: it accepts an untrusted candidate skill, validates and sanitizes it, checks it for novelty against the existing skills, and on success persists it to a QUARANTINE location that is NOT part of any catalog- registered Source. It NEVER writes into a directory that DirSource serves to a live Skill tool. Construction binds it to (a) the quarantine dir and (b) a read-only snapshot of the currently active skills for the novelty check.
LAYERING: this is an adapter-package seam, the write-side mirror of Source (also an adapter-package seam, not a domain port). The domain never imports it; the SkillDraft tool depends on it by constructor injection, the same shape by which the read-only Skill tool depends on Source.
type FSSource ¶
FSSource is the FILESYSTEM implementation of the tool.SkillSource port. See skillfs.FSSource.
type LifecycleDrafter ¶
type LifecycleDrafter struct {
// contains filtered or unexported fields
}
LifecycleDrafter persists explicit model drafts as versioned, inactive agent-owned records. It never writes to or publishes the live catalog.
func NewLifecycleDrafter ¶
func NewLifecycleDrafter(repository learning.SkillRepository, partition learning.SkillPartition, owner string, inventory []learning.SkillInventoryItem) *LifecycleDrafter
NewLifecycleDrafter binds explicit model drafts to an inactive lifecycle partition.
func (*LifecycleDrafter) Draft ¶
func (d *LifecycleDrafter) Draft(ctx context.Context, request DraftRequest) (DraftResult, error)
Draft validates and persists one inactive versioned draft.
func (*LifecycleDrafter) DraftIn ¶
func (d *LifecycleDrafter) DraftIn(ctx context.Context, env tool.Environment, request DraftRequest) (DraftResult, error)
DraftIn derives model-facing draft ownership from the verified caller and exact live workspace. Missing identity or workspace disables drafting rather than writing to a process-global ownerless partition.
type MultiSource ¶
type MultiSource = skillfs.MultiSource
MultiSource composes an ORDERED list of Sources into one. See skillfs.MultiSource.
type ResolveOptions ¶
type ResolveOptions = skillfs.ResolveOptions
ResolveOptions configures the known-path resolver. See skillfs.ResolveOptions.
type Skill ¶
Skill is a pure value object: one discovered skill's metadata and body. See skillfs.Skill.
func ParseSkill ¶
ParseSkill splits raw into YAML frontmatter and a markdown body and validates the required header fields. It is exported so this package's writable half (promote.go) re-runs the promotion-gate structural validation through the SAME parser the read-only core uses. See skillfs.ParseSkill.
type Source ¶
Source is the pluggable EXTENSIBILITY POINT for where skills come from. See skillfs.Source.
func ResolveSources ¶
func ResolveSources(opts ResolveOptions) []Source
ResolveSources builds the ORDERED, highest-precedence-first Source list from the conventional locations plus any explicit paths. See skillfs.ResolveSources.