pack

package
v1.0.0-rc.4 Latest Latest
Warning

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

Go to latest
Published: Nov 3, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package pack defines the gridctl pack manifest: a versioned selector over a repo's skills, agents, context rule fragments, and gateway wiring, so one git import configures a whole team setup. This package is deliberately thin — types, parsing, and validation only. There is no pack engine: the CLI expands a manifest into calls against the existing kind managers (skillsync, agentsync, contexts, wiring), which own every write.

Field names align with the Claude Code plugin.json family where the semantics match (name, version, description, author, skills, agents), so a pack maps onto that ecosystem instead of fighting it. The word "bundle" is avoided: the MCP ecosystem uses it for .mcpb, a single-server archive format.

Index

Constants

View Source
const APIVersion = "gridctl.dev/v1"

APIVersion is the current manifest schema, emitted by everything gridctl writes and documented as the value authors should use.

View Source
const Kind = "Pack"

Kind is the manifest's required kind value.

View Source
const LegacyAPIVersion = "gridctl.dev/v1alpha1"

LegacyAPIVersion is the pre-1.0 alpha schema. It is structurally identical to APIVersion and stays accepted indefinitely so packs authored before the graduation keep importing (Article IX).

View Source
const LockFileName = "gridctl-pack.lock.yaml"

LockFileName is the committed pack lock, written next to gridctl-pack.yaml only by `gridctl pack lock`.

View Source
const LockVersion = 1

LockVersion is the gridctl-pack.lock.yaml schema this gridctl writes.

View Source
const ManifestFileName = "gridctl-pack.yaml"

ManifestFileName is the fixed manifest location at a repo root.

Variables

View Source
var ErrNewerPackLockVersion = errors.New("pack lock was written by a newer gridctl version")

ErrNewerPackLockVersion signals a pack lock written by a newer gridctl. Callers must not honor or rewrite it.

Functions

func ManifestDigest

func ManifestDigest(m *Manifest) string

ManifestDigest returns sha256:<hex> over the canonical JSON encoding of sources and stack.extends, with auth blocks stripped. Comments, formatting, and every non-source manifest field do not stale the lock. encoding/json sorts map keys, so source order does not matter.

func WriteLockFile

func WriteLockFile(path string, lf *LockFile) error

WriteLockFile marshals lf with sorted map keys, a trailing newline, and mode 0644, via a temp file in the same directory. It refuses a lock that would not parse.

Types

type Author

type Author struct {
	Name string `yaml:"name,omitempty" json:"name,omitempty"`
	URL  string `yaml:"url,omitempty" json:"url,omitempty"`
}

Author identifies a pack's maintainer (plugin.json-aligned subset).

type LockFile

type LockFile struct {
	Version        int                      `yaml:"version"`
	Pack           string                   `yaml:"pack"`
	ManifestDigest string                   `yaml:"manifestDigest"`
	Sources        map[string]LockedSource  `yaml:"sources,omitempty"`
	Extends        map[string]LockedExtends `yaml:"extends,omitempty"`
}

LockFile is gridctl-pack.lock.yaml. The digest covers sources and stack.extends only. Comments, formatting, auth blocks, and every other manifest field do not stale the lock and never appear in it.

func ParseLockFile

func ParseLockFile(data []byte) (*LockFile, error)

ParseLockFile decodes a pack lock. version greater than LockVersion is refused with ErrNewerPackLockVersion. A missing or non-positive version, a commit that is not a 40-hex SHA, and a repo carrying URL userinfo are refused. An ssh:// URL may carry a username with no password; that is a login name, not a credential. An https userinfo component and any SSH password are refused. The newer-version message names LockFileName, which is the path authors and the CLI print.

type LockedExtends

type LockedExtends struct {
	Repo   string `yaml:"repo"`
	Commit string `yaml:"commit"`
}

LockedExtends is the base pack a booster extends, pinned by repo and commit.

type LockedSource

type LockedSource struct {
	Repo   string `yaml:"repo"`
	Ref    string `yaml:"ref,omitempty"`
	Commit string `yaml:"commit"`
	Path   string `yaml:"path,omitempty"`
}

LockedSource is one resolved sources: entry. Repo carries no credential userinfo. An ssh:// username with no password is a login name and is kept.

type Manifest

type Manifest struct {
	APIVersion  string `yaml:"apiVersion" json:"apiVersion"`
	Kind        string `yaml:"kind" json:"kind"`
	Name        string `yaml:"name" json:"name"`
	Version     string `yaml:"version,omitempty" json:"version,omitempty"`
	Description string `yaml:"description,omitempty" json:"description,omitempty"`
	Author      Author `yaml:"author,omitempty" json:"author,omitempty"`
	// Sources names external git repositories this pack selects from.
	// Empty means every selection comes from this repository.
	Sources map[string]Source `yaml:"sources,omitempty" json:"sources,omitempty"`
	// Skills and Agents select resources by name. A string entry (Source
	// empty) comes from this repository. A mapping names a declared source.
	// Empty means every resource of that kind discovered in this repository
	// only; external sources are never import-all.
	Skills []Selection `yaml:"skills,omitempty" json:"skills,omitempty"`
	Agents []Selection `yaml:"agents,omitempty" json:"agents,omitempty"`
	// Wiring asks apply to ensure the gateway entry is present in the
	// selected clients (empty Clients = all detected).
	Wiring  bool     `yaml:"wiring,omitempty" json:"wiring,omitempty"`
	Clients []string `yaml:"clients,omitempty" json:"clients,omitempty"`
	// Rules selects context rule fragments from the pack repo's
	// rules/*.md (or fragments/*.md) discovery. Empty means none
	// (rules are opt-in, never import-all).
	Rules []string `yaml:"rules,omitempty" json:"rules,omitempty"`
	// Variables documents value-free prerequisites. Installing a pack never
	// writes these declarations to a stack or variable store.
	Variables map[string]VariableDeclaration `yaml:"variables,omitempty" json:"variables,omitempty"`
	// Stack names a stack file inside this repository. Empty means the
	// pack carries no stack and apply does not start a gateway. A scalar
	// is today's path. A mapping with extends names a fragment that
	// composes onto another pack's stack.
	Stack StackSpec `yaml:"stack,omitempty" json:"stack,omitempty"`
	// Requires is an optional semver floor for the running gridctl.
	// Older readers ignore the key (Parse is not strict). Enforcement is
	// pack add, pack apply, and preview, not Parse or pack lock.
	// Defined locally so this package does not import pkg/config.
	Requires *RequiresConfig `yaml:"requires,omitempty" json:"requires,omitempty"`
}

Manifest is a parsed gridctl-pack.yaml.

func Parse

func Parse(data []byte) (*Manifest, error)

Parse decodes and validates a manifest.

func ParseFile

func ParseFile(path string) (*Manifest, error)

ParseFile reads and parses a manifest from path. A missing file reports os.IsNotExist-compatible errors so callers can distinguish "no manifest" from "broken manifest".

func (*Manifest) AgentNames

func (m *Manifest) AgentNames() []string

AgentNames returns agent selections that come from the pack repository.

func (*Manifest) IsBooster

func (m *Manifest) IsBooster() bool

IsBooster reports whether this pack extends another pack's stack. A booster's File is a fragment, not a standalone stack.

func (*Manifest) SkillNames

func (m *Manifest) SkillNames() []string

SkillNames returns skill selections that come from the pack repository.

func (*Manifest) Validate

func (m *Manifest) Validate() error

Validate checks the manifest's schema envelope and name.

func (*Manifest) Warnings

func (m *Manifest) Warnings() []string

Warnings reports advisory conditions a valid manifest still carries. Currently none; the reserved-rules warning was removed when the rules fragment library activated.

type RequiresConfig

type RequiresConfig struct {
	Gridctl string `yaml:"gridctl,omitempty" json:"gridctl,omitempty"`
}

RequiresConfig is the optional tool-version floor. The shape matches config.RequiresConfig. Omitted means no constraint (Article IX).

type Selection

type Selection struct {
	Name   string `yaml:"name" json:"name"`
	Source string `yaml:"source,omitempty" json:"source,omitempty"`
}

Selection is one skill or agent name. A scalar is a name from the pack repository. A mapping names a resource in a declared source. JSON encoding is always the object form.

func (*Selection) UnmarshalYAML

func (s *Selection) UnmarshalYAML(value *yaml.Node) error

UnmarshalYAML accepts a scalar name or a mapping with name and source. A mapping that omits either key is an error that names the line.

type Source

type Source struct {
	Repo string      `yaml:"repo" json:"repo"`
	Ref  string      `yaml:"ref,omitempty" json:"ref,omitempty"`
	Path string      `yaml:"path,omitempty" json:"path,omitempty"`
	Auth *SourceAuth `yaml:"auth,omitempty" json:"auth,omitempty"`
}

Source is one external git repository a pack selects skills and agents from. Field names and YAML tags mirror skills.SkillSource. A source is a repository the pack author chose, pinned by commit at import, not an index entry.

type SourceAuth

type SourceAuth struct {
	Method        string `yaml:"method,omitempty" json:"method,omitempty"`
	CredentialRef string `yaml:"credential_ref,omitempty" json:"credentialRef,omitempty"`
	SSHUser       string `yaml:"ssh_user,omitempty" json:"sshUser,omitempty"`
	// contains filtered or unexported fields
}

SourceAuth is the declarative auth block on a pack source. It mirrors skills.SourceAuth except ssh_key_path, which a manifest must not carry: a key path is a caller secret, not pack content. UnmarshalYAML captures that key so validation can refuse it by name instead of dropping it.

func (*SourceAuth) HasSSHKeyPath

func (a *SourceAuth) HasSSHKeyPath() bool

HasSSHKeyPath reports whether the manifest named ssh_key_path.

func (*SourceAuth) UnmarshalYAML

func (a *SourceAuth) UnmarshalYAML(value *yaml.Node) error

UnmarshalYAML decodes the auth block and remembers ssh_key_path so Validate can reject it explicitly.

type StackSpec

type StackSpec struct {
	File    string `yaml:"file,omitempty" json:"file,omitempty"`
	Extends string `yaml:"extends,omitempty" json:"extends,omitempty"`
}

StackSpec is a carried stack path, or a fragment that extends another pack. Extends empty means a plain carried stack. JSON and YAML emit the scalar path in that case so existing readers see today's shape.

func (StackSpec) IsZero

func (s StackSpec) IsZero() bool

IsZero reports an empty stack so omitempty drops the field.

func (StackSpec) MarshalJSON

func (s StackSpec) MarshalJSON() ([]byte, error)

MarshalJSON emits a JSON string when Extends is empty.

func (StackSpec) MarshalYAML

func (s StackSpec) MarshalYAML() (any, error)

MarshalYAML emits a scalar when Extends is empty so a round trip of today's manifests stays a string.

func (*StackSpec) UnmarshalJSON

func (s *StackSpec) UnmarshalJSON(data []byte) error

UnmarshalJSON accepts a string or the object form.

func (*StackSpec) UnmarshalYAML

func (s *StackSpec) UnmarshalYAML(value *yaml.Node) error

UnmarshalYAML accepts a scalar path or a mapping with file and optional extends. A mapping without file is an error that names the line. An unknown mapping key is an error that names the key.

type VariableDeclaration

type VariableDeclaration struct {
	Required    *bool  `yaml:"required,omitempty" json:"required,omitempty"`
	Secret      *bool  `yaml:"secret,omitempty" json:"secret,omitempty"`
	Type        string `yaml:"type,omitempty" json:"type,omitempty"`
	Description string `yaml:"description,omitempty" json:"description,omitempty"`
	Docs        string `yaml:"docs,omitempty" json:"docs,omitempty"`
}

VariableDeclaration documents a pack prerequisite.

Jump to

Keyboard shortcuts

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