skillsync

package
v0.39.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 19, 2026 License: MIT Imports: 14 Imported by: 0

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

Constants

This section is empty.

Variables

This section is empty.

Functions

func AppendBuiltinCatalog added in v0.39.7

func AppendBuiltinCatalog(preset string) string

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

func BuiltinNames() map[string]bool

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

func DeleteEntry(name string) (int, error)

DeleteEntry removes entryName (file or folder recursively) from all dirs.

func DeleteEntryFromDir

func DeleteEntryFromDir(dir, name string) error

DeleteEntryFromDir removes entryName only from one specific dir.

func DirLabel

func DirLabel(dir string) string

DirLabel returns a short human label for a dir path (e.g. "claude", "codex").

func DirLabelForProvider added in v0.39.5

func DirLabelForProvider(providerType string) string

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

func InProvider(s SkillInfo, providerType string) bool

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

func IsBuiltinName(name string) bool

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.

func ReadFile

func ReadFile(filename string) ([]byte, string, error)

ReadFile returns the content of a skill file from the first dir that has it.

func ZipEntry

func ZipEntry(entryName string) ([]byte, error)

ZipEntry creates a zip archive of entryName (folder or file) from first dir that has it. Returns zip bytes.

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

type Result struct {
	Copied       int
	SkillsCopied int
	Skipped      int
	Errors       []string
	Dirs         []string
}

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

func PushFrom(srcDir, relPath string) (Result, error)

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

func Sync() (Result, error)

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

func SyncBuiltin() (Result, error)

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

func SyncEntry(name string) (Result, error)

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.

func UploadProcessed

func UploadProcessed(filename string, data []byte) (string, Result, error)

UploadProcessed handles upload logic:

  • .md / .txt → write to <skillDir>/<stem>/SKILL<ext>
  • .zip / .skills → extract zip with root-folder detection

Returns (folderName, Result, error).

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.

func Status

func Status() ([]SkillFile, []string, error)

Status returns current skill state without writing anything.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL