skillslock

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Jul 17, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package skillslock owns the shared project-level skills-lock.json v1 format that gskill co-owns with compatible external tooling (e.g. `npx skills`).

The package provides a lossless model: fields it does not understand — unknown top-level keys, unknown skill-entry keys, and other tools' extension blocks — survive every rewrite with their values intact and their key order stable, so the file remains fully usable by the other tool. gskill's own metadata lives under the namespaced per-entry "gskill" field and never repurposes the shared core fields (source, sourceType, skillPath, computedHash).

It also hosts the in-memory working model (State/Record) commands operate on, and the bridge between records and shared-format entries.

Index

Constants

View Source
const FileName = "skills-lock.json"

FileName is the shared project-level lock file gskill co-owns with compatible external tooling.

View Source
const SchemaVersion = 1

SchemaVersion is the skills-lock.json schema this build understands.

Variables

View Source
var (
	// ErrInvalid is returned for a structurally or semantically invalid lock.
	ErrInvalid = errors.New("invalid skills-lock.json")
	// ErrUnsupportedSchema is returned for a version other than SchemaVersion;
	// gskill refuses to guess at (or rewrite) a schema it does not understand.
	ErrUnsupportedSchema = errors.New("unsupported skills-lock.json schema version")
)

Sentinel errors.

Functions

func Marshal

func Marshal(l *Lock) ([]byte, error)

Marshal serializes the lock deterministically: original key order, unknown values re-emitted verbatim, 2-space indent, trailing newline, no HTML escaping. New keys appear in sorted order after the original ones.

func Save

func Save(path string, l *Lock) error

Save writes the lock to path atomically. The file is committed and shared with other tools, so it is world-readable.

Types

type Entry

type Entry struct {
	Source       string
	Ref          string // optional branch/tag used for installation (npx "ref")
	SourceType   string
	SkillPath    string
	ComputedHash string
	Ext          *Ext
}

Entry is the typed view of one skill entry's core fields plus gskill's namespaced extension block (nil when the entry was never installed by gskill). Unknown entry fields stay in the Lock and survive rewrites.

func FromRecord

func FromRecord(ls Record) Entry

FromRecord maps an in-memory record into a shared-format entry: core fields stay npx-skills-compatible, everything gskill-specific goes under the namespaced extension.

type Ext

type Ext struct {
	SourceURL     string   `json:"sourceUrl,omitempty"`
	Ref           string   `json:"ref,omitempty"`
	Commit        string   `json:"commit,omitempty"`
	Version       string   `json:"version,omitempty"`
	Agents        []string `json:"agents,omitempty"`
	InstallMode   string   `json:"installMode,omitempty"`
	Scope         string   `json:"scope,omitempty"`
	StoreHash     string   `json:"storeHash,omitempty"`
	SkillFileHash string   `json:"skillFileHash,omitempty"`
	InstalledAt   string   `json:"installedAt,omitempty"`
	UpdatedAt     string   `json:"updatedAt,omitempty"`
	// State nests the residual machine state existing commands still consume;
	// see ExtState (bridge.go).
	State *ExtState `json:"state,omitempty"`
}

Ext is the namespaced per-entry "gskill" extension block (FR-004): every gskill-owned fact lives here, never in the shared core fields, so the file stays fully usable by other tools. Timestamps are confined to this block and excluded from reproducible determinism, mirroring the legacy Provenance carve-out.

type ExtState

type ExtState struct {
	// SourceKind is gskill's resolved source type (e.g. a "local" entry whose
	// path is a git repo resolves as "git"); the entry's core sourceType stays
	// whatever the external tool wrote.
	SourceKind     string `json:"sourceKind,omitempty"`
	SourceOriginal string `json:"sourceOriginal,omitempty"`
	SourceOwner    string `json:"sourceOwner,omitempty"`
	SourceRepo     string `json:"sourceRepo,omitempty"`
	SourcePath     string `json:"sourcePath,omitempty"`

	RequestedVersion string `json:"requestedVersion,omitempty"`
	RequestedRef     string `json:"requestedRef,omitempty"`
	RequestedCommit  string `json:"requestedCommit,omitempty"`

	RefKind       string `json:"refKind,omitempty"`
	Tag           string `json:"tag,omitempty"`
	Branch        string `json:"branch,omitempty"`
	TreeHash      string `json:"treeHash,omitempty"`
	MutableRef    bool   `json:"mutableRef,omitempty"`
	LocalPathHash string `json:"localPathHash,omitempty"`

	MetaName        string `json:"metaName,omitempty"`
	MetaDescription string `json:"metaDescription,omitempty"`
	MetaVersion     string `json:"metaVersion,omitempty"`
	MetaLicense     string `json:"metaLicense,omitempty"`

	RequiresSkills      []string `json:"requiresSkills,omitempty"`
	RequiresCommands    []string `json:"requiresCommands,omitempty"`
	RequiresEnvironment []string `json:"requiresEnvironment,omitempty"`
	RequiresMCP         []string `json:"requiresMcp,omitempty"`

	ActivePath string            `json:"activePath,omitempty"`
	Targets    map[string]string `json:"targets,omitempty"`
	Modes      map[string]string `json:"modes,omitempty"`

	Trust string `json:"trust,omitempty"`
}

ExtState carries the residual gskill install state that has no place in the interop-visible Ext fields but is still consumed by existing commands (update skip logic, target removal, drift checks, display metadata). It lives nested under gskill.state so the top of the extension block stays the small, documented interop surface.

type Installation

type Installation struct {
	Scope      string
	Mode       string
	Agents     []string
	ActivePath string
	Targets    map[string]string
	Modes      map[string]string
}

Installation is the placement record (FR-019, FR-020, FR-027, FR-028). Mode is the representative install mode; Modes records the actual mode per agent for the case where they differ (e.g. a symlink falls back to a copy). ActivePath is the project-relative active-layer entry (.agents/skills/<name>) that every agent target derives from.

type Lock

type Lock struct {
	// contains filtered or unexported fields
}

Lock is the lossless in-memory form of skills-lock.json: typed access to the fields gskill understands, raw preservation for everything else.

func Load

func Load(path string) (*Lock, error)

Load reads and parses the lock file at path.

func New

func New() *Lock

New returns an empty lock at the current schema version.

func Unmarshal

func Unmarshal(data []byte) (*Lock, error)

Unmarshal parses lock bytes, enforcing the structural schema: valid JSON, version == SchemaVersion, and a skills object whose values are objects. Entry-level field validation is Validate's job.

func (*Lock) CheckExts

func (l *Lock) CheckExts() error

CheckExts fails when any entry carries a gskill block that does not parse. A corrupted block must fail closed, not silently degrade the entry to external-only (which would drop it from restore/remove/sync).

func (*Lock) Entry

func (l *Lock) Entry(name string) (Entry, bool)

Entry returns the typed view of one entry.

func (*Lock) Has

func (l *Lock) Has(name string) bool

Has reports whether an entry exists.

func (*Lock) Names

func (l *Lock) Names() []string

Names returns the entry names in file order.

func (*Lock) Remove

func (l *Lock) Remove(name string) bool

Remove deletes an entry, leaving every other byte of the document untouched.

func (*Lock) ReplaceEntryCore

func (l *Lock) ReplaceEntryCore(name string, e Entry)

ReplaceEntryCore rewrites an entry's core identity fields. This is the one sanctioned core rewrite: manifest-wins reconciliation (spec 012 FR-023), where the user explicitly chose the manifest's declaration over the lock. Stale verification facts — computedHash and the gskill block — are dropped so the next install re-resolves and re-records them; fields gskill does not understand still survive.

func (*Lock) SetEntry

func (l *Lock) SetEntry(name string, e Entry)

SetEntry creates or updates an entry, preserving any fields it does not understand. Core identity fields (source, ref, sourceType, skillPath) are owned by whichever tool wrote them first: gskill fills them only when absent and never rewrites them. computedHash is the shared verification fact and is updated in place; the gskill extension block is always gskill's to replace. New entries are inserted in sorted order after the original ones.

func (*Lock) SetExt

func (l *Lock) SetExt(name string, ext *Ext) error

SetExt creates or replaces the namespaced gskill block on an existing entry.

func (*Lock) Validate

func (l *Lock) Validate() error

Validate checks every entry's required core fields and rejects skillPath values that are absolute or escape the project (path traversal, FR-027).

func (*Lock) Version

func (l *Lock) Version() int

Version returns the parsed schema version.

type Metadata

type Metadata struct {
	Name        string
	Description string
	Version     string
	License     string
}

Metadata is the captured SKILL.md frontmatter.

type Provenance

type Provenance struct {
	FetchedAt string
	UpdatedAt string
	Trust     string
}

Provenance is best-effort trust info. Timestamps are excluded from reproducible determinism (FR-004).

type Record

type Record struct {
	Source       Source
	Requested    Requested
	Resolved     Resolved
	Metadata     Metadata
	Requires     Requires
	Installation Installation
	Provenance   Provenance
}

Record is the full reproduction record for one managed skill.

func ToRecord

func ToRecord(name string, e Entry) Record

ToRecord reconstructs the in-memory record from a shared-format entry. name is the map key, used as the display-name fallback for entries that never carried gskill state (external-only entries).

type Requested

type Requested struct {
	Version string
	Ref     string
	Commit  string
}

Requested echoes the human's intent (FR-010).

type Requires

type Requires struct {
	Skills      []string
	Commands    []string
	Environment []string
	MCP         []string
}

Requires records declared needs, surfaced but never resolved (FR-032).

type Resolved

type Resolved struct {
	Version       string
	RefKind       string
	Tag           string
	Branch        string
	Commit        string
	TreeHash      string
	ContentHash   string
	SkillFileHash string
	MutableRef    bool
	LocalPathHash string
	// CompatHash is the npx-skills-compatible computedHash (spec 012). The
	// shared skills-lock.json persists it as the core computedHash field.
	CompatHash string
}

Resolved is the immutable identity gskill pinned to (FR-009, FR-010).

type Source

type Source struct {
	Type     string
	Original string
	URL      string
	Owner    string
	Repo     string
	Path     string
}

Source is the normalized origin of a skill.

type State

type State struct {
	Skills map[string]Record
}

State is the in-memory working model of the project's managed skills: the typed view commands operate on, hydrated from skills-lock.json entries carrying a gskill block and written back through the lossless Lock. It is never serialized directly.

func NewState

func NewState() *State

NewState returns an empty in-memory state.

Jump to

Keyboard shortcuts

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