feat(skillpack): SKILL.md-subscription battery
New additive, nil-safe battery for subscribing to skill packages in the Anthropic agent-skills format (SKILL.md manifest + bundled files): - Manifest/ParseManifest: SKILL.md frontmatter+body parse & validation (name/description required, allowed-tools passthrough, kebab/length limits) - Tree/Pack/LoadPack: self-contained file set, order-independent content digest (the pin identity + change signal), bundled-file listing, traversal- safe staging - Source (DirSource, GitSource): Fetch returns tree + resolved ref; git clones to temp, reads subpath into memory, cleans up (self-contained tree) - Subscription + Store + content-addressed PackCache, with Memory defaults - Syncer: Subscribe pins; Check records a PENDING update but never moves the pin; Apply is the only re-pin (supply-chain guard — upstream can't silently change what an agent runs) - Activate: resolved packs -> majordomo agent.Skill (catalog instructions + one skill_use tool) for progressive disclosure; Stage materializes files Third distinct 'skill' concept, deliberately separate from executus/skill (saved-agent noun) and majordomo/skill (eager capability bundle). Mort-side wiring (convars, .skillpack commands, Agent.SkillPacks, allowed-tools shim) is a later, separate step. Full unit + hermetic local-git tests; gofmt/vet clean; race-tested. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
package skillpack
|
||||
|
||||
import "context"
|
||||
|
||||
// Store is the persistence seam for subscriptions (metadata + the current pin).
|
||||
// It is deliberately small; a host backs it with its DB, Memory is the zero-dep
|
||||
// default, and contrib/store can add durable SQLite alongside the other
|
||||
// executus store impls.
|
||||
type Store interface {
|
||||
Initialize(ctx context.Context) error
|
||||
Save(ctx context.Context, s *Subscription) error
|
||||
Get(ctx context.Context, id string) (*Subscription, error)
|
||||
GetByName(ctx context.Context, name string) (*Subscription, error)
|
||||
List(ctx context.Context) ([]Subscription, error)
|
||||
Delete(ctx context.Context, id string) error
|
||||
}
|
||||
|
||||
// PackCache is the content-addressed store of pinned pack trees, keyed by
|
||||
// content digest. It exists so activating an agent never re-fetches from the
|
||||
// Source (no clone per run) and so a pinned digest's exact bytes survive even if
|
||||
// upstream later force-pushes or disappears. A host may back it with disk;
|
||||
// Memory is the default. Because the key IS the content digest, entries are
|
||||
// immutable and safe to share across subscriptions that pin the same bytes.
|
||||
type PackCache interface {
|
||||
Put(ctx context.Context, digest string, t Tree) error
|
||||
Get(ctx context.Context, digest string) (Tree, error)
|
||||
}
|
||||
Reference in New Issue
Block a user