Documentation
¶
Overview ¶
Package skilltree owns the one canonical definition of an Agent Skill's content: which filesystem nodes belong to a skill, how they are hashed, how they are materialized, and how two divergent versions are merged.
Every skill content operation — import, local change detection, pull merge, push delta, and ordinary projection — reads trees through this package so a permissive copier can never drift from the strict import policy.
Index ¶
- Constants
- func HasManifest(tree Tree) bool
- func IsIgnoredName(name string) bool
- func Materialize(tree Tree, dir string) error
- func Merge(base, local, remote Tree, mergeText TextMerger) (Tree, []Conflict, error)
- func NormalizeName(value string) string
- func ValidateRelativePath(value string) error
- type Conflict
- type ConflictKind
- type FS
- type File
- type OSFS
- type SkillInfo
- type TextMerger
- type Tree
Constants ¶
const SkillManifestName = "SKILL.md"
SkillManifestName is the canonical skill manifest filename. Every source tier requires it exactly; no lowercase fallback is accepted.
Variables ¶
This section is empty.
Functions ¶
func HasManifest ¶
HasManifest reports whether a tree carries a root-level canonical SKILL.md. Wildcard selectors use it to ignore ordinary directories.
func IsIgnoredName ¶
IsIgnoredName reports whether a filesystem entry is one of the three source artifacts excluded from every canonical skill-tree read.
func Materialize ¶
Materialize writes the tree into dir, which must already exist and is expected to be an empty staging directory owned by the caller. It never writes outside dir.
func Merge ¶
func Merge(base, local, remote Tree, mergeText TextMerger) (Tree, []Conflict, error)
Merge reconciles local and remote against their common base.
A path changed on only one side applies cleanly, identical changes on both sides coalesce, compatible text changes are merged by mergeText, and every remaining divergence is reported as a conflict rather than resolved by preference. As in Git, a file's content and executable bit merge independently, so a content change on one side combines with a mode change on the other. Renames are handled as the deletion plus addition they are recorded as, because a skill tree carries no rename metadata.
Merge never partially applies: when any conflict is reported the returned tree must be discarded by the caller.
func NormalizeName ¶
NormalizeName applies the same Unicode normalization used when comparing skill names across configuration, imports, and user-managed sources.
func ValidateRelativePath ¶
ValidateRelativePath rejects any tree path that could escape its skill root.
Types ¶
type Conflict ¶
type Conflict struct {
Path string
Kind ConflictKind
}
Conflict reports one unmergeable path.
type ConflictKind ¶
type ConflictKind string
ConflictKind names why a path could not be reconciled automatically.
const ( // ConflictContent means both sides changed the same text file // incompatibly. ConflictContent ConflictKind = "content" // ConflictDeleteModify means one side deleted a path the other changed. ConflictDeleteModify ConflictKind = "delete/modify" // ConflictBinary means both sides changed the content of a non-text file // differently. ConflictBinary ConflictKind = "binary" // ConflictMode means both sides added the same path with different // executable bits. With a base, a one-sided change to the bit applies and a // two-sided change agrees, so the bit alone never conflicts. ConflictMode ConflictKind = "mode" // ConflictFileDirectory means one side has a file where the other side // has files beneath a same-named directory. ConflictFileDirectory ConflictKind = "file/directory" )
type FS ¶
type FS interface {
Lstat(name string) (os.FileInfo, error)
ReadDir(name string) ([]os.DirEntry, error)
ReadFile(name string) ([]byte, error)
}
FS is the filesystem surface a tree read needs. It is deliberately small so the sync package's injectable System and a plain OS implementation both satisfy it.
type File ¶
type File struct {
// Path is the slash-normalized path relative to the skill root.
Path string
// Data is the file's exact bytes.
Data []byte
// Executable records whether the owner execute bit is set. Git uses that
// bit to choose between blob modes 100644 and 100755.
Executable bool
}
File is one regular file in a skill tree.
type OSFS ¶
type OSFS struct{}
OSFS reads through the real filesystem.
type SkillInfo ¶
type SkillInfo struct {
// Name is the frontmatter name, which must equal the selected directory
// name and becomes the local imported directory name.
Name string
// Description is the required nonempty frontmatter description.
Description string
}
SkillInfo is the identity a validated skill tree carries.
func ValidateManifest ¶
ValidateManifest applies the same strict rules to one manifest's bytes.
Callers that already hold the manifest use it to apply the same identity and metadata rules without constructing a second tree. sourcePath names the skill root.
func ValidateNode ¶ added in v1.0.0
ValidateNode keeps skill directory validation unchanged for directory imports.
func ValidateSkill ¶
ValidateSkill enforces Agent Layer's strict skill rules on a tree that was selected at sourcePath.
It requires a canonical SKILL.md at the tree root, valid required metadata, a safe skill name, a name matching the selected directory, and frontmatter Agent Layer can project faithfully. sourcePath is used for error context and to derive the expected name.
type TextMerger ¶
TextMerger performs a three-way merge of text content. It returns the merged bytes and whether the merge produced conflicts. An error means the merge could not be attempted at all.
type Tree ¶
type Tree struct {
// contains filtered or unexported fields
}
Tree is a skill's complete regular-file content, sorted by path.
Directories are intentionally absent: an empty directory carries no skill content and is not representable in Git, so including it would make local and upstream hashes disagree for identical skills.
func Read ¶
Read enumerates the skill tree rooted at dir.
It walks with Lstat so a link is classified without being followed, includes every regular file (hidden files included), ignores only `.git`, `.DS_Store`, and `Thumbs.db`, and rejects every other node type. A missing root directory yields an empty tree so callers can distinguish "no content" from a read failure by checking the directory themselves.
func ReadFileNode ¶ added in v1.0.0
ReadFileNode represents one exact regular file as a canonical one-file tree. name is the destination filename, including during trusted legacy adoption.
func ReadStrict ¶ added in v1.0.0
ReadStrict requires a real root and rejects metadata that Read normally excludes. Adoption and frozen snapshots use it so hashing cannot hide content that would be discarded when the source is retired or copied.