mirror of
https://github.com/patriceckhart/zot.git
synced 2026-06-26 21:36:31 +02:00
The model now ships with a `write-zot-extension` skill compiled
into the binary. When the user asks for help authoring a zot
extension (slash command, LLM tool, audit hook, permission gate)
the model sees the skill in its system-prompt manifest, calls
the `skill` tool to load the body on demand, and walks the user
through the right answer with the wire format, manifest shape,
SDK examples (Go + TS + Python), and dev workflow already in
context. No need for the user to be in the zot repo or to ask
the model to read docs/extensions.md first.
Built-in skills:
- shipped via //go:embed at internal/skills/builtin/
- merged into Discover()'s output AFTER user skills, so a
user-installed skill with the same name shadows the built-in
(drop your own SKILL.md at $ZOT_HOME/skills/write-zot-extension/
to customise)
- marked Builtin: true on the Skill struct
- hidden from user-facing surfaces: VisibleSkills() filters them
so /skills only shows skills the user actually installed or
shipped in their project
The model side stays unchanged: system-prompt manifest still lists
built-ins (so the model knows they exist), the `skill` tool still
loads them on demand. Only the picker is filtered.
Verified live:
prompt: "List the names of the skills you have available"
-> code-review, test-fix, write-zot-extension
prompt: "I want to write a zot extension that adds a slash
command /pwd which inserts the current directory path
into the editor. What language should I use, and what
files do I need to create?"
-> [tool_call] skill({"name":"write-zot-extension"})
-> body returned
-> the model produces a complete extension with the right
manifest, the right hello/register/ready frames, action:
insert correctly chosen, and a remark about cwd capture.
The picker filter has its own unit test
(TestVisibleSkillsHidesBuiltins) and the existing Discover test
was updated to expect the built-in count without hardcoding it.
51 lines
1.3 KiB
Go
51 lines
1.3 KiB
Go
package skills
|
|
|
|
import (
|
|
"embed"
|
|
"io/fs"
|
|
"path"
|
|
"strings"
|
|
)
|
|
|
|
// builtinFS holds the SKILL.md files zot ships with the binary.
|
|
// They appear in the catalogue as ordinary skills — same on-demand
|
|
// load via the `skill` tool, same /skills picker — but never need
|
|
// to be installed by the user. A user-installed skill with the same
|
|
// name shadows the built-in one (Discover's first-match-wins).
|
|
//
|
|
//go:embed all:builtin
|
|
var builtinFS embed.FS
|
|
|
|
// loadBuiltins returns every SKILL.md compiled into the binary.
|
|
// Errors per file are silently dropped: built-ins are part of the
|
|
// release; if one is malformed it's a release bug we want to surface
|
|
// in tests, not panic in front of the user.
|
|
func loadBuiltins() []*Skill {
|
|
entries, err := fs.ReadDir(builtinFS, "builtin")
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
var out []*Skill
|
|
for _, e := range entries {
|
|
if !e.IsDir() {
|
|
continue
|
|
}
|
|
raw, err := fs.ReadFile(builtinFS, path.Join("builtin", e.Name(), "SKILL.md"))
|
|
if err != nil {
|
|
continue
|
|
}
|
|
front, body := splitFrontmatter(string(raw))
|
|
s := &Skill{
|
|
Path: "builtin:" + e.Name(),
|
|
Source: "built-in",
|
|
Body: strings.TrimSpace(body),
|
|
Builtin: true,
|
|
}
|
|
parseFrontmatter(front, s)
|
|
if s.Name == "" {
|
|
s.Name = e.Name()
|
|
}
|
|
out = append(out, s)
|
|
}
|
|
return out
|
|
}
|