Documentation
¶
Overview ¶
Package skills installs WB's Agent Skills (embedded from ai/skills, see package ai) into a harness's own skills directory -- Claude Code's ~/.claude/skills, Cursor's ~/.cursor/skills, Codex's ~/.codex/skills -- so they are discoverable in every project, not only inside a checkout of sneat-dev/wb.
The gap this closes: WB ships agent-facing skills under ai/skills/ in its own repository, and a checkout-local plugin manifest auto-discovers them there -- but only for a session working inside that repository. A session orchestrating a different repository, with wb installed globally (Homebrew, go install, self-update), has never had those skills at all. `wb skills sync` is the fix: it copies every shipped skill into the harness's own skills directory once, so it is available everywhere wb is.
Index ¶
Constants ¶
const MarkerFileName = ".wb-skills-sync.json"
MarkerFileName is the sync record Sync writes next to the skills it installs -- e.g. ~/.claude/skills/.wb-skills-sync.json. Leading-dot so it never reads as a skill directory itself. It is the single source both the drift banner (main.go) and `wb skills sync`'s own idempotency check read, so the two never disagree about what was last installed.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Action ¶
type Action string
Action classifies what Sync did (or, in a dry run, would do) with one skill.
const ( // Added means the skill was not installed and now is. Added Action = "added" // Updated means an installed skill's content hash changed and was // replaced. Updated Action = "updated" // Unchanged means the installed skill already matches the embedded one; // nothing was written. Unchanged Action = "unchanged" // Removed means a skill this wb build no longer ships was previously // installed by wb and has been deleted. Removed Action = "removed" // Conflict means a directory already occupies a shipped skill's name but // was never recorded as wb-installed. Sync never overwrites or deletes // it; the caller must report it and leave it alone. Conflict Action = "conflict" )
type Marker ¶
type Marker struct {
SchemaVersion int `json:"schema_version"`
WBVersion string `json:"wb_version"`
SyncedAt time.Time `json:"synced_at"`
Skills map[string]string `json:"skills"`
}
Marker records what `wb skills sync` last installed: which wb build ran it, when, and the exact content hash of every skill it wrote -- so a later run can tell added/updated/unchanged/removed apart without re-hashing installed files (which a user could have hand-edited) and so wb can print a drift warning by comparing WBVersion against the binary currently running, with no filesystem walk at all.
func ReadMarker ¶
ReadMarker reads the sync marker from skillsDir. A missing marker -- skills never synced on this machine -- is reported as os.ErrNotExist wrapped so callers can use errors.Is; every other read or parse failure is returned as-is.
type Options ¶
type Options struct {
// Source is the embedded skill tree, rooted so each skill's files sit at
// "<name>/...". Ordinarily fs.Sub(ai.SkillsFS, "skills").
Source fs.FS
// Dir is the harness skills directory to install into, e.g.
// ~/.claude/skills, ~/.cursor/skills, or ~/.codex/skills.
Dir string
// WBVersion is the running wb build's version, recorded in the marker.
WBVersion string
// DryRun computes and returns the Report without writing, removing, or
// touching the marker.
DryRun bool
}
Options configures one Sync call.
type Report ¶
type Report struct {
// Dir is the harness skills directory Sync targeted.
Dir string
// PriorWBVersion is the wb_version recorded in the marker before this
// run, or "" when there was no marker (a first sync).
PriorWBVersion string
// WBVersion is the wb build that performed this sync, now recorded in
// the marker (unless DryRun).
WBVersion string
// Changes covers every shipped skill plus every previously-installed
// skill this build no longer ships, sorted by name.
Changes []Change
// DryRun reports whether this Report describes a plan rather than an
// applied sync.
DryRun bool
}
Report is the full outcome of one Sync call, in the shape `wb skills sync` prints and tests assert against.
func Sync ¶
Sync installs every skill in opts.Source into opts.Dir, and removes any skill this build no longer ships that a previous Sync installed there.
It is idempotent and always safe to re-run: a directory that already matches the embedded content is left untouched (Unchanged), and a directory Sync did not itself install -- because it predates any sync, or because its name collides with a shipped skill it never recorded owning -- is never overwritten or deleted (Conflict). Only names this exact function previously wrote, per the marker, are ever candidates for Removed.
type Skill ¶
Skill is one shipped skill discovered in the embedded source: its name (the directory under ai/skills/, and the directory it is installed as under a harness skills directory) and a deterministic content hash of every file the skill directory contains.
func Discover ¶
Discover lists every skill in source: an fs.FS rooted so that a skill's files sit at "<name>/SKILL.md", "<name>/references/...", and so on -- ordinarily fs.Sub(ai.SkillsFS, "skills"). A top-level entry only counts as a skill when it is a directory containing SKILL.md; commands.json and any other loose file at the same level is ignored.
Results are sorted by name so callers, and the marker file Sync writes, never depend on directory iteration order.
type Status ¶
type Status struct {
// Installed reports whether a marker exists at all, i.e. `wb skills
// sync` has run on this machine before.
Installed bool
// SyncedWBVersion is the wb_version recorded in the marker. Empty when
// !Installed.
SyncedWBVersion string
}
Status is the cheap, marker-only read Drift and the SessionStart hook use: no embedded-skill discovery, no filesystem walk of the installed skills -- just the one small marker file, so it costs nothing to check on every wb invocation.
func ReadStatus ¶
ReadStatus reads skillsDir's marker and reports it as a Status. A missing marker is not an error here -- it is the ordinary "never synced" case -- but any other read or parse failure is returned.
func (Status) Drifted ¶
Drifted reports whether currentWBVersion disagrees with the marker enough to warn about it: either skills were never synced, or they were synced by a different wb version than the one running now. An "unknown"/"(devel)" currentWBVersion -- an undetermined dev build -- never counts as drifted, so a plain `go build` of wb does not nag a developer about a comparison that means nothing.