feat(skillpack): SKILL.md-subscription battery #22

Merged
steve merged 3 commits from feat/skillpack-battery into main 2026-07-05 01:28:57 +00:00
2 changed files with 49 additions and 22 deletions
Showing only changes of commit 29598df814 - Show all commits
+32 -16
View File
2
@@ -66,17 +66,26 @@ type skillUseArgs struct {
Name string `json:"name" description:"the exact name of the skill to load, from the Available skills list"`
}
// BundleStager makes a pack's bundled files available to the current run and
// returns a short note the model can act on (e.g. where the files are and how to
// reference them). It is called LAZILY, inside the skill_use tool, so a pack's
// files are staged only when the model actually loads that pack — not for every
// subscribed pack on every run. A host implements it over its own file plumbing
// (mort saves the files to run-scoped storage and returns their file_ids). nil =
// no staging: skill_use just lists the bundled file names.
type BundleStager func(ctx context.Context, p *Pack) (string, error)
// Activate turns a set of resolved packs into a majordomo agent.Skill: its
// Instructions are the Catalog, and it contributes a single skill_use tool that
Review

🟠 Activate panics on nil pack element in slice

error-handling · flagged by 1 model

  • skillpack/activation.go:79Activate(packs []*Pack, stagedDir string) will panic if any pack in the input slice is nil. Same issue: byName[p.Manifest.Name] dereferences without checking p != nil. Fix: Skip nil packs in the loop or return an error.

🪰 Gadfly · advisory

🟠 **Activate panics on nil pack element in slice** _error-handling · flagged by 1 model_ - **`skillpack/activation.go:79`** — `Activate(packs []*Pack, stagedDir string)` will **panic** if any pack in the input slice is `nil`. Same issue: `byName[p.Manifest.Name]` dereferences without checking `p != nil`. **Fix:** Skip nil packs in the loop or return an error. <sub>🪰 Gadfly · advisory</sub>
// returns a named pack's full body (progressive disclosure). Attach the result
// to an agent with agent.WithSkill. Returns nil when there are no packs, which
// agent.WithSkill tolerates (a nil skill contributes nothing).
//
// stagedDir, if non-empty, is the directory a host has staged the packs' bundled
// files into (see Stage); skill_use appends the concrete path so the model knows
// where to read scripts/references with its file tools. Leave it empty when the
// host has no staging.
func Activate(packs []*Pack, stagedDir string) mdagent.Skill {
// stager, if non-nil, is invoked when skill_use loads a pack with bundled files;
// its returned note is appended to the body so the model knows how to reach the
// staged scripts/references. A stager error degrades gracefully (the
// instructions still return, with a note that the files are unavailable).
func Activate(packs []*Pack, stager BundleStager) mdagent.Skill {
byName := make(map[string]*Pack, len(packs))
for _, p := range packs {
if p != nil && p.Manifest != nil {
@@ -88,13 +97,23 @@ func Activate(packs []*Pack, stagedDir string) mdagent.Skill {
}
tool := llm.DefineTool("skill_use",
"Load the full instructions for a skill by name before doing a task it covers. Returns the skill's instructions and a list of any bundled files.",
func(_ context.Context, args skillUseArgs) (any, error) {
"Load the full instructions for a skill by name before doing a task it covers. Returns the skill's instructions and, if it has bundled files, how to access them.",
func(ctx context.Context, args skillUseArgs) (any, error) {
p, ok := byName[strings.TrimSpace(args.Name)]
if !ok {
Review

🟠 renderPackBody panics on nil Pack or nil Manifest

error-handling · flagged by 1 model

  • skillpack/activation.go:103-104renderPackBody(p *Pack, stagedDir string) will panic if p == nil or p.Manifest == nil. This is called from the skill_use tool handler; while Activate builds the map from valid packs, a future refactor or direct call could pass nil. Fix: Add if p == nil || p.Manifest == nil { return "Error: invalid pack" }.

🪰 Gadfly · advisory

🟠 **renderPackBody panics on nil Pack or nil Manifest** _error-handling · flagged by 1 model_ - **`skillpack/activation.go:103-104`** — `renderPackBody(p *Pack, stagedDir string)` will **panic** if `p == nil` or `p.Manifest == nil`. This is called from the `skill_use` tool handler; while `Activate` builds the map from valid packs, a future refactor or direct call could pass nil. **Fix:** Add `if p == nil || p.Manifest == nil { return "Error: invalid pack" }`. <sub>🪰 Gadfly · advisory</sub>
return fmt.Sprintf("No skill named %q. Use one of the names from the Available skills list.", args.Name), nil
}
return renderPackBody(p, stagedDir), nil
body := renderPackBody(p)
if stager != nil && len(p.Bundled) > 0 {
note, err := stager(ctx, p)
switch {
case err != nil:
body += "\n\n(bundled files could not be staged: " + err.Error() + ")"
case note != "":
body += "\n\n" + note
}
}
return body, nil
})
tb := llm.NewToolbox("skillpack", tool)
1
@@ -104,20 +123,17 @@ func Activate(packs []*Pack, stagedDir string) mdagent.Skill {
)
}
// renderPackBody is what skill_use returns: the pack's instructions plus a
// pointer to its bundled files (with the staged path when known).
func renderPackBody(p *Pack, stagedDir string) string {
// renderPackBody is the base skill_use payload: the pack's instructions plus, if
// it has any, a list of its bundled file names. A stager (see Activate) appends
// the concrete access note.
func renderPackBody(p *Pack) string {
if p == nil || p.Manifest == nil {
return "Error: invalid skill pack."
}
var b strings.Builder
fmt.Fprintf(&b, "# Skill: %s\n\n%s\n", p.Manifest.Name, p.Manifest.Body)
if len(p.Bundled) > 0 {
b.WriteString("\nBundled files")
if stagedDir != "" {
fmt.Fprintf(&b, " (under %s)", strings.TrimRight(stagedDir, "/")+"/"+p.Manifest.Name)
}
b.WriteString(":\n")
b.WriteString("\nBundled files:\n")
for _, f := range p.Bundled {
fmt.Fprintf(&b, "- %s\n", f)
}
+17 -6
View File
@@ -44,7 +44,12 @@ func TestActivate_SkillUseTool(t *testing.T) {
packs := []*Pack{
mustPack(t, "pdf", "Use pdfplumber.", map[string]string{"scripts/x.py": "print()"}),
}
sk := Activate(packs, "/stage")
staged := 0
stager := func(_ context.Context, p *Pack) (string, error) {
staged++
return "staged " + p.Manifest.Name + " (file_id=abc)", nil
}
sk := Activate(packs, stager)
if sk == nil {
t.Fatal("expected a non-nil skill")
}
@@ -56,6 +61,9 @@ func TestActivate_SkillUseTool(t *testing.T) {
if !ok {
t.Fatal("skill_use tool missing from toolbox")
}
if staged != 0 {
t.Error("stager must be lazy — not called until skill_use runs")
}
// load an existing pack
out, err := tool.Handler(ctx, json.RawMessage(`{"name":"pdf"}`))
@@ -66,8 +74,11 @@ func TestActivate_SkillUseTool(t *testing.T) {
if !strings.Contains(body, "Use pdfplumber.") {
t.Errorf("skill_use body missing instructions: %q", body)
}
if !strings.Contains(body, "scripts/x.py") || !strings.Contains(body, "/stage/pdf") {
t.Errorf("skill_use should list bundled files under the staged dir: %q", body)
if !strings.Contains(body, "scripts/x.py") {
t.Errorf("skill_use should list bundled files: %q", body)
}
if staged != 1 || !strings.Contains(body, "file_id=abc") {
t.Errorf("stager should run on load and its note append to the body: staged=%d body=%q", staged, body)
}
// unknown pack returns guidance, not an error
@@ -81,7 +92,7 @@ func TestActivate_SkillUseTool(t *testing.T) {
}
func TestActivate_Empty(t *testing.T) {
if Activate(nil, "") != nil {
if Activate(nil, nil) != nil {
t.Error("no packs should activate to a nil skill")
}
}
@@ -92,7 +103,7 @@ func TestNilPackElementsAreSafe(t *testing.T) {
if got := Catalog(packs); !strings.Contains(got, "real") {
t.Errorf("catalog should include the valid pack and skip nils: %q", got)
}
sk := Activate(packs, "")
sk := Activate(packs, nil)
if sk == nil {
t.Fatal("a valid pack among nils should still activate")
}
@@ -100,7 +111,7 @@ func TestNilPackElementsAreSafe(t *testing.T) {
t.Error("skill_use missing")
}
// All-nil activates to nothing rather than panicking.
if Activate([]*Pack{nil, {Manifest: nil}}, "") != nil {
if Activate([]*Pack{nil, {Manifest: nil}}, nil) != nil {
t.Error("only-nil packs should activate to nil")
}
}