Documentation
¶
Overview ¶
Package skillsync mirrors skill files across all agent skill directories (~/.claude/skills, ~/.codex/skills, ~/.gemini/skills, ~/.agents/skills) without symlinks. Any file in any dir is copied to all others. Newest mtime wins on conflict so no work is lost.
Index ¶
- func AppendBuiltinCatalog(preset string) string
- func BuiltinCatalog() string
- func BuiltinDir() string
- func BuiltinNames() map[string]bool
- func DeleteEntry(name string) (int, error)
- func DeleteEntryFromDir(dir, name string) error
- func DirLabel(dir string) string
- func DirLabelForProvider(providerType string) string
- func InProvider(s SkillInfo, providerType string) bool
- func IsBuiltinName(name string) bool
- func KnownDirs() []string
- func OwnLabel() string
- func ReadDirs() []string
- func ReadFile(filename string) ([]byte, string, error)
- func ZipEntry(entryName string) ([]byte, error)
- type ProviderLocation
- type Result
- type SkillEntry
- type SkillFile
- type SkillInfo
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AppendBuiltinCatalog ¶ added in v0.39.7
AppendBuiltinCatalog returns preset with the shipped-skill catalog appended, or preset unchanged when nothing ships.
Appended rather than prepended: the operator's preset opens with the session identity block, and a catalog above it would push that out of the position the CLIs and the operator both expect to find it in.
An empty preset still gets the catalog. A spawn with no preset is a bare agent, and a bare agent is exactly the one that most needs to be told the shipped skills exist.
func BuiltinCatalog ¶ added in v0.39.7
func BuiltinCatalog() string
BuiltinCatalog returns a markdown block naming every skill that ships with wick, or "" when none are installed on disk.
Sorted by name so the rendered prompt is byte-stable across spawns, which keeps the provider's prompt prefix cacheable.
func BuiltinDir ¶ added in v0.39.5
func BuiltinDir() string
BuiltinDir is where the shipped skills live: wick's own skills dir, shared with the user's own skills. Kept as a function rather than inlined so the several callers that reason about "where do shipped skills live" cannot drift apart, and so a future relocation is one edit.
func BuiltinNames ¶ added in v0.39.7
BuiltinNames returns the top-level entry names that ship inside the binary.
Sync consults this to keep shipped skills OUT of the provider rotation. They live in a dir wick rewrites, so a copy in ~/.claude/skills could never be cleaned up the same way: a skill dropped in a newer wick version would linger there forever, and a user edit to the copy would win on mtime and be silently reverted on the next boot. One copy, one owner.
func DeleteEntry ¶
DeleteEntry removes entryName (file or folder recursively) from all dirs.
func DeleteEntryFromDir ¶
DeleteEntryFromDir removes entryName only from one specific dir.
func DirLabelForProvider ¶ added in v0.39.5
DirLabelForProvider maps a PROVIDER TYPE ("claude", "codex", "gemini", "wick") to the DirLabel of that provider's skills dir.
They coincide for the CLI providers but NOT for wick: its provider type is always "wick" while its dir label follows the app name. Comparing the two directly meant a dev build listed zero wick skills — the folder was there, the label just never matched — which hid every skill from the `/` composer menu and from workflow skill listings.
func InProvider ¶ added in v0.39.5
InProvider reports whether a skill is present in the dir belonging to providerType. The "agents" dir is shared ground: skills placed there count for every provider.
A skill wick ships counts for EVERY provider even though it sits only in wick's own dir. It is deliberately never copied elsewhere, so a by-directory check would report it missing for claude and codex — and hide from the `/` composer a skill their agents can in fact invoke, since each provider trusts wick's dir on the argv and is handed the skill's path in its system prompt.
func IsBuiltinName ¶ added in v0.39.7
IsBuiltinName reports whether name is a skill that ships inside the binary.
func KnownDirs ¶
func KnownDirs() []string
KnownDirs returns existing skill dirs in a stable order, plus wick's own skills dir (~/.<appname>/skills) which is ENSURE-CREATED so the built-in wick provider is a first-class skill provider even before any skill is added — it appears in the UI chips, sync targets, and the wick session's `/` menu without the user having to create the folder first. The other provider dirs are only returned when they already exist on disk.
func OwnLabel ¶ added in v0.39.5
func OwnLabel() string
OwnLabel is the DirLabel of wick's own skills dir. It equals the resolved app name — "wick" for a release build, but "wick-lab" (or whatever wick.yml names) for a dev build, since the data dir is ~/.<appname>/.
func ReadDirs ¶ added in v0.39.5
func ReadDirs() []string
ReadDirs returns every directory a skill may be READ from.
The shipped skills now live inside wick's own dir, which KnownDirs already ensure-creates and returns, so this is KnownDirs plus a guarantee that the shipped copy has actually been extracted. It stays a distinct function because callers use it to mean "everything readable", and because extraction must not be triggered from the sync path.
Types ¶
type ProviderLocation ¶ added in v0.14.1
type ProviderLocation struct {
Label string `json:"label"`
Dir string `json:"dir"`
Path string `json:"path"` // full path to the skill entry (folder or file)
}
ProviderLocation is one provider that has a skill, with its full path.
type Result ¶
Result is returned by Sync and Upload.
Copied counts individual FILES written, so one folder skill with a SKILL.md plus two reference files reports 3 per destination dir. SkillsCopied counts top-level SKILL FOLDERS that gained at least one file — the number a user actually cares about, and the one the UI reports. The two are tracked separately because the skill dirs also hold loose bookkeeping files (CLAUDE.md, README.md, install_skills.sh) that sync but are not skills: counting only files made a run that copied zero skills look successful.
func PushFrom ¶ added in v0.39.5
PushFrom force-copies relPath (a file or folder, possibly nested inside a skill) from srcDir to every OTHER known dir, overwriting regardless of mtime.
Unlike Sync/SyncEntry this is deliberately one-directional: the user picked a specific provider's copy as the one to propagate, so mtime must not veto it.
func Sync ¶
Sync mirrors every skill to every known dir. Newest mtime wins.
A skill is a FOLDER holding a SKILL.md, so syncing walks each folder and resolves the winner PER FILE inside it: dir A can hold a newer SKILL.md while dir B holds a newer reference file, and both should survive. Loose files sitting in the skills dir (CLAUDE.md, README.md, …) are mirrored too, as plain top-level files. Dot entries are provider bookkeeping (.git, .DS_Store) and are always skipped.
func SyncBuiltin ¶ added in v0.39.5
SyncBuiltin writes the embedded skills into wick's skills dir.
Content-addressed rather than wipe-and-rewrite: the dir is shared with the user's own skills now, so deleting it would destroy their work. Each shipped file is compared by MD5 and only rewritten when it actually differs, which keeps mtimes stable — Sync resolves winners by mtime, and rewriting an unchanged file every boot would make shipped skills perpetually "newest".
Stale shipped skills are still removed, but only ones the embed itself no longer contains AND that carry the managed marker, so a user folder that happens to share a name is never deleted.
An empty embed is treated as "not built" rather than "no skills": nothing on disk is touched and no error is returned, mirroring how a missing embedded gate binary degrades instead of destroying state.
func SyncEntry ¶ added in v0.39.5
SyncEntry mirrors ONE top-level entry (folder skill or loose file) to every known dir, resolving the winner per file by mtime — the same rule Sync uses, scoped to a single skill.
Picking the source per FILE matters: a folder's own mtime does not change when a file inside it is edited, so choosing a source by folder mtime can copy a stale SKILL.md over a newer one.
type SkillEntry ¶
type SkillEntry struct {
Name string // entry name (folder or filename)
IsDir bool // true if it's a folder in at least one dir
Sources []string // dirs where this entry exists
Missing []string // dirs where this entry is absent
Newest time.Time // mtime of newest copy
}
SkillEntry represents one top-level entry (file or folder) found across skill dirs.
func ListDir ¶
func ListDir(entryName string) ([]SkillEntry, []string, error)
ListDir returns entries inside a specific subfolder across all skill dirs. entryName is a top-level folder name (e.g. "imagegen"). Returns entries found in any dir, deduped by name, isDir tracked. Second return is the list of dirs where entryName exists.
type SkillFile ¶
type SkillFile = SkillEntry
SkillFile is an alias kept for callers that only care about files.
type SkillInfo ¶ added in v0.14.1
type SkillInfo struct {
Name string `json:"name"`
IsDir bool `json:"is_dir"`
Builtin bool `json:"builtin"`
Meta map[string]string `json:"meta"`
InProviders []ProviderLocation `json:"in_providers"`
MissingProviders []ProviderLocation `json:"missing_providers"`
}
SkillInfo is an enriched skill entry — name, metadata, and per-provider locations.
Builtin marks a skill that ships inside the wick binary. Such a skill lives in a directory wick rewrites from scratch on every start, so it is effectively read-only: callers should not offer to edit or delete it, and should expect local changes to disappear. The flag is derived from which directory the skill was found in — no manifest or database row is involved.
func ListSkills ¶ added in v0.14.1
func ListSkills() []SkillInfo
ListSkills returns enriched SkillInfo for every top-level entry across all known skill dirs, including parsed metadata and per-provider paths.