Documentation
¶
Index ¶
- Constants
- Variables
- func AgentDir(registryDir, name string) string
- func AgentsRoot(registryDir string) string
- func BackupSkillFileInDir(skillDir, shortSHA string) (string, error)
- func BehavioralChanges(old, new *Fingerprint) []string
- func BuildAuther(cfg AuthConfig) (gitpkg.Auther, error)
- func CheckUpdatesBackground(registryDir string, logger *slog.Logger)
- func ContentHashFile(path string) (string, error)
- func DeleteAgent(registryDir, name string) error
- func DeleteOrigin(skillDir string) error
- func DetectAgentDrift(ctx context.Context, registryDir string) ([]string, error)
- func DetectDrift(ctx context.Context, store *registry.Store, lockPath, sourceName string) ([]string, error)
- func FetchAndCompare(repo, ref, currentSHA string, auth AuthConfig, logger *slog.Logger) (string, bool, error)
- func FormatFindings(findings []SecurityFinding) string
- func FormatUpdateNotice() string
- func HasOrigin(skillDir string) bool
- func IsPinnedRef(ref string) bool
- func IsSemVerConstraint(ref string) bool
- func ListRemoteTags(repoPath string) ([]string, error)
- func LockFilePath() string
- func MutateLockFile(ctx context.Context, path string, fn func(*LockFile) (bool, error)) error
- func RepoToName(repo string) string
- func ResolveSemVerConstraint(constraintStr string, tags []string) (string, error)
- func SafeRepoPath(path string) error
- func ShortSHA(sha string) string
- func ShouldCheckUpdates() bool
- func SkillsConfigPath() string
- func UpdateCachePath() string
- func ValidateAgentName(name string) error
- func WriteLockFile(path string, lf *LockFile) error
- func WriteOrigin(skillDir string, origin *Origin) error
- func WriteUpdateCache(status *UpdateStatus) error
- func WriteUpdateCacheAt(path string, status *UpdateStatus) error
- type AgentDefinition
- type AgentExtraField
- type AuthConfig
- type CloneResult
- type CredentialResolver
- type DiffResult
- type DiscoveredAgent
- type DiscoveredSkill
- type Fingerprint
- type ImportOptions
- type ImportResult
- type ImportedAgent
- type ImportedSkill
- type Importer
- func (imp *Importer) AdvanceTracking(ctx context.Context, skillName, newSHA string) error
- func (imp *Importer) AgentInfo(agentName string) (*SkillInfo, error)
- func (imp *Importer) BackupSkillFile(ctx context.Context, skillName, shortSHA string) (string, error)
- func (imp *Importer) Detach(ctx context.Context, skillName string) error
- func (imp *Importer) Diff(ctx context.Context, skillName string) (*DiffResult, error)
- func (imp *Importer) Import(opts ImportOptions) (*ImportResult, error)
- func (imp *Importer) Info(skillName string) (*SkillInfo, error)
- func (imp *Importer) Pin(skillName, ref string) error
- func (imp *Importer) Remove(skillName string) error
- func (imp *Importer) RemoveAgent(agentName string) error
- func (imp *Importer) SetCredentialResolver(r CredentialResolver)
- func (imp *Importer) Update(skillName string, dryRun, force, trust bool) (*ImportResult, error)
- type InstalledAgent
- type LockFile
- func (lf *LockFile) FindAgentSource(agentName string) (string, *LockedSource, bool)
- func (lf *LockFile) FindPackSource(packName string) (string, *LockedSource, bool)
- func (lf *LockFile) FindSkillSource(skillName string) (string, *LockedSource, bool)
- func (lf *LockFile) RemoveAgent(agentName string)
- func (lf *LockFile) RemoveSkill(skillName string)
- func (lf *LockFile) RemoveSource(name string)
- func (lf *LockFile) SetSource(name string, src LockedSource)
- type LockedAgent
- type LockedPack
- type LockedRule
- type LockedSkill
- type LockedSource
- type MalformedAgent
- type MalformedSkill
- type Origin
- type ScanResult
- type SecurityFinding
- type SkillDefaults
- type SkillInfo
- type SkillSource
- type SkillUpdate
- type SkillsConfig
- type SkippedAgent
- type SkippedSkill
- type SourceAuth
- type UpdateStatus
Constants ¶
const ImportLockVersion = 2
ImportLockVersion is the highest skills.lock.yaml schema version this gridctl reads. Version 1 added the version field itself and per-source agents; version 2 added per-source pack records. Files are written at the lowest version that can represent them (see WriteLockFile), so users without packs keep downgrade freedom.
Variables ¶
var ErrImportLockBusy = errors.New("timeout acquiring import lock")
ErrImportLockBusy signals contention on the cross-process import lock: the operation should be retried, nothing is corrupted.
var ErrNewerImportLockVersion = errors.New("import lockfile was written by a newer gridctl version")
ErrNewerImportLockVersion signals a skills.lock.yaml written by a newer gridctl. Callers must never paper over it: acting on state a newer version wrote risks silent data loss (the pkg/project lesson).
Functions ¶
func AgentDir ¶
AgentDir returns the canonical directory for one imported agent; the definition itself lives at AgentDir(...)/AGENT.md.
func AgentsRoot ¶
AgentsRoot returns the canonical agent store directory under a registry directory.
func BackupSkillFileInDir ¶
BackupSkillFileInDir is BackupSkillFile for callers that already hold the skill directory (skill projection adopt shares the convention, so there is exactly one hand-edit backup vocabulary).
func BehavioralChanges ¶
func BehavioralChanges(old, new *Fingerprint) []string
BehavioralChanges compares two fingerprints and returns human-readable changes.
func BuildAuther ¶
func BuildAuther(cfg AuthConfig) (gitpkg.Auther, error)
BuildAuther constructs a git.Auther matching the AuthConfig's Method. Returns an error for unknown methods. Individual Auther implementations also validate their own inputs (e.g. HTTPSTokenAuth rejects empty tokens).
func CheckUpdatesBackground ¶
CheckUpdatesBackground runs update checks in a background goroutine. Results are written to the cache file for display on next CLI command.
func ContentHashFile ¶
ContentHashFile computes a SHA-256 hash of a file.
func DeleteAgent ¶
DeleteAgent removes one agent from the canonical store.
func DeleteOrigin ¶
DeleteOrigin removes the .origin.json file from a skill directory.
func DetectAgentDrift ¶
DetectAgentDrift returns the names of imported agents whose on-disk AGENT.md has been edited since the last import. Same fail-open policy as DetectDrift: a missing origin or InstalledHash is not drift.
func DetectDrift ¶
func DetectDrift(ctx context.Context, store *registry.Store, lockPath, sourceName string) ([]string, error)
DetectDrift returns the names of imported skills in sourceName whose on-disk SKILL.md has been edited since the last import or sync. Drift is detected by comparing the current file hash against the InstalledHash snapshot written when the skill was last installed.
Skills imported before InstalledHash was tracked (empty value) are treated as not drifted — DetectDrift fails open rather than reporting noise. Skills with no Origin (purely local) are not considered.
Pass an empty sourceName to scan every imported skill in the registry.
func FetchAndCompare ¶
func FetchAndCompare(repo, ref, currentSHA string, auth AuthConfig, logger *slog.Logger) (string, bool, error)
FetchAndCompare fetches the latest from a remote and compares with current.
func FormatFindings ¶
func FormatFindings(findings []SecurityFinding) string
FormatFindings returns a human-readable summary of security findings.
func FormatUpdateNotice ¶
func FormatUpdateNotice() string
FormatUpdateNotice returns a user-friendly message about available updates.
func IsPinnedRef ¶
IsPinnedRef returns true when ref looks like an immutable pin (a specific version tag containing a ".", or a full 40-character commit SHA). Bare branch names and empty refs return false so they are treated as floating.
This is a heuristic, not a guarantee: a tag like "release-2026" with no dot will read as unpinned, and a branch named "feature.x" will read as pinned. Used by aggregate sync to skip pins by default so a bulk operation does not silently bump a user's intentionally-fixed version.
func IsSemVerConstraint ¶
IsSemVerConstraint returns true if the ref looks like a semver constraint.
func ListRemoteTags ¶
ListRemoteTags returns all tags from a cached repository.
func LockFilePath ¶
func LockFilePath() string
LockFilePath returns the default path to skills.lock.yaml.
func MutateLockFile ¶
MutateLockFile runs one read-modify-write cycle over skills.lock.yaml while holding the cross-process import lock, so concurrent operations serialize instead of losing each other's updates. fn returns whether its changes should be written; false skips the write and succeeds.
func RepoToName ¶
RepoToName extracts a short name from a repo URL (the last path segment with any ".git" suffix stripped). Exported so callers like the CLI can match the source names this package uses without duplicating the logic.
func ResolveSemVerConstraint ¶
ResolveSemVerConstraint finds the best matching tag for a constraint.
func SafeRepoPath ¶
SafeRepoPath validates a path component to prevent directory traversal.
func ShortSHA ¶
ShortSHA returns the first 8 characters of a commit SHA, or the whole string when it is shorter (including the empty string from an uncached fetch). It keeps SHA formatting panic-free for logs, backup names, and messages.
func ShouldCheckUpdates ¶
func ShouldCheckUpdates() bool
ShouldCheckUpdates returns false if update checks are disabled. GRIDCTL_NO_SKILL_UPDATE_CHECK accepts the shared boolean vocabulary (env.Bool); a malformed value is ignored and checks proceed.
func SkillsConfigPath ¶
func SkillsConfigPath() string
SkillsConfigPath returns the default path to skills.yaml.
func UpdateCachePath ¶
func UpdateCachePath() string
UpdateCachePath returns the path to the cached update status file.
func ValidateAgentName ¶
ValidateAgentName validates an agent name: non-empty, lowercase letters, digits, and hyphens only.
func WriteLockFile ¶
WriteLockFile writes skills.lock.yaml atomically. Keys are sorted for minimal merge conflicts.
func WriteOrigin ¶
WriteOrigin writes the .origin.json file to a skill directory.
func WriteUpdateCache ¶
func WriteUpdateCache(status *UpdateStatus) error
WriteUpdateCache writes the update status to the default cache path.
func WriteUpdateCacheAt ¶
func WriteUpdateCacheAt(path string, status *UpdateStatus) error
WriteUpdateCacheAt writes the update status to an explicit path.
Types ¶
type AgentDefinition ¶
type AgentDefinition struct {
Name string
Description string
// Extra holds every frontmatter key other than name and description,
// in document order, as raw YAML nodes.
Extra []AgentExtraField
// Body is the markdown after the frontmatter block.
Body string
// Raw is the file exactly as read; imports write it verbatim.
Raw []byte
}
AgentDefinition is a parsed Claude Code subagent definition (AGENT.md / agents/<name>.md). Name and Description are the only typed fields; every other frontmatter key (tools, model, hooks, mcpServers, permissionMode, vendor extensions) rides in Extra as raw YAML nodes in document order.
AgentDefinition deliberately does not reuse AgentSkill/ParseSkillMD: that parser types skill-specific keys and would silently strand tools and model in an untyped map, and its render path normalizes frontmatter. Agents are stored and projected verbatim (identity render), so Raw is the source of truth; the parsed form exists for validation, scanning, and listing.
func ParseAgentMD ¶
func ParseAgentMD(data []byte) (*AgentDefinition, error)
ParseAgentMD parses an agent definition file. Frontmatter with a non-empty description is required: a markdown file without it (a README dropped into an agents/ directory, say) is not an agent definition. The frontmatter mapping is walked by hand so unknown keys are preserved in order rather than silently dropped, and a duplicate key cannot discard the valid ones.
func SaveAgent ¶
func SaveAgent(registryDir, name string, raw []byte) (*AgentDefinition, error)
SaveAgent validates raw as an agent definition named name and writes it into the canonical store byte-for-byte. No normalization happens here on purpose: identity projections copy the canonical bytes verbatim, so any rewrite (key reordering, trailing-newline fixes) would surface as drift on every synced client after an edit. Returns the parsed definition so callers can inspect what was written.
func (*AgentDefinition) DeclaredModel ¶
func (d *AgentDefinition) DeclaredModel() (string, bool)
DeclaredModel reads the definition's top-level `model:` value. ok is false when the declaration exists but is not a scalar (a structured value cannot be honored or safely rewritten); an absent key reports ("", true). Every surface that answers "what model does this agent declare" (sync, CLI, REST) goes through this one helper so they can never disagree on non-scalar handling.
func (*AgentDefinition) ExtraByKey ¶
func (d *AgentDefinition) ExtraByKey(key string) (*yaml.Node, bool)
ExtraByKey returns the raw frontmatter node for one passthrough key. Renderers use it for key-level access without scanning Extra at every call site.
type AgentExtraField ¶
AgentExtraField is one passthrough frontmatter key.
type AuthConfig ¶
type AuthConfig struct {
Method string // "", "none", "token", "ssh-agent", "ssh-key"
Token string // resolved plaintext — transient, never persisted
CredentialRef string // e.g. "${vault:GIT_TOKEN}" — persisted
SSHUser string // defaults to "git" when empty
SSHKeyPath string // required for method "ssh-key"
SSHPassphrase string // transient
KnownHostsPath string // reserved for future host-key policy work
}
AuthConfig carries authentication configuration for a git operation. The Token and SSHPassphrase fields are transient — they must never be persisted to disk. CredentialRef is the opaque reference string (e.g. "${vault:GIT_TOKEN}") that gets stored in Origin/LockFile so that Update can re-resolve it later.
type CloneResult ¶
type CloneResult struct {
RepoPath string
CommitSHA string
Skills []DiscoveredSkill
Malformed []MalformedSkill
// Agents are agent definitions discovered under the agents/*.md
// convention; MalformedAgents records files in agents/ directories
// that are not parseable agent definitions.
Agents []DiscoveredAgent
MalformedAgents []MalformedAgent
}
CloneResult contains the result of a clone + discovery operation.
func CloneAndDiscover ¶
func CloneAndDiscover(repo, ref, subPath string, auth AuthConfig, logger *slog.Logger) (*CloneResult, error)
CloneAndDiscover clones a repo and discovers all SKILL.md files plus any agents/*.md definitions it ships.
type CredentialResolver ¶
CredentialResolver resolves an opaque reference like "${vault:GIT_TOKEN}" to its raw value. Callers (CLI, HTTP API) register one via Importer.SetCredentialResolver so that Update can re-resolve credentials recorded in Origin/LockFile without the importer needing to know where the values live.
type DiffResult ¶
type DiffResult struct {
Skill string `json:"skill"`
Local string `json:"local"` // current on-disk full SKILL.md text
Upstream string `json:"upstream"` // content an update would install
Drifted bool `json:"drifted"` // on-disk file diverges from InstalledHash
}
DiffResult holds a skill's current on-disk SKILL.md alongside the content an update would install, for on-demand comparison. Producing it changes no registry state, SHAs, or InstalledHashes.
type DiscoveredAgent ¶
type DiscoveredAgent struct {
Name string
Path string // Relative path from repo root to the .md file
Definition *AgentDefinition
ContentHash string
}
DiscoveredAgent represents an agent definition found in a cloned repo under an agents/ directory.
type DiscoveredSkill ¶
type DiscoveredSkill struct {
Name string
Path string // Relative path from repo root to SKILL.md directory
Skill *registry.AgentSkill
ContentHash string
}
DiscoveredSkill represents a SKILL.md found in a cloned repo.
type Fingerprint ¶
type Fingerprint struct {
ContentHash string `json:"contentHash" yaml:"content_hash"`
ToolsHash string `json:"toolsHash" yaml:"tools_hash"`
Tools []string `json:"tools,omitempty" yaml:"tools,omitempty"`
}
Fingerprint captures the behavioral identity of a skill.
func ComputeFingerprint ¶
func ComputeFingerprint(skill *registry.AgentSkill) *Fingerprint
ComputeFingerprint generates a behavioral fingerprint for a skill.
type ImportOptions ¶
type ImportOptions struct {
Repo string
Ref string
Path string
Trust bool // Skip security scan confirmation
NoActivate bool // Import as draft instead of active
Force bool // Overwrite existing skills
Rename string // Rename the skill on import
Selected []string // Only import skills with these names (empty = import all)
// SelectedAgents imports exactly these agent names. When empty, the
// legacy behavior holds: all agents when Selected is also empty, no
// agents when a skill selection is present (the web UI picker's
// contract). Pack imports always pass fully resolved lists.
SelectedAgents []string
// Discovered supplies a pre-cloned discovery result so callers that
// already ran CloneAndDiscover (pack add reads the manifest first)
// do not clone twice. Nil means Import clones itself.
Discovered *CloneResult
Auth AuthConfig
// PreserveState carries over the existing skill's State (draft/active/
// disabled) instead of resetting it. Used by Update so that re-syncing
// a source does not silently re-activate skills the user disabled.
PreserveState bool
}
ImportOptions controls the import behavior.
type ImportResult ¶
type ImportResult struct {
Imported []ImportedSkill `json:"imported"`
Skipped []SkippedSkill `json:"skipped"`
Warnings []string `json:"warnings"`
// ImportedAgents and SkippedAgents record agent definitions the same
// import discovered under the agents/*.md convention.
ImportedAgents []ImportedAgent `json:"importedAgents,omitempty"`
SkippedAgents []SkippedAgent `json:"skippedAgents,omitempty"`
}
ImportResult contains the results of an import operation.
type ImportedAgent ¶
type ImportedAgent struct {
Name string `json:"name"`
Path string `json:"path"`
Origin *Origin `json:"origin,omitempty"`
Findings []SecurityFinding `json:"findings,omitempty"`
}
ImportedAgent records a successfully imported agent definition.
type ImportedSkill ¶
type ImportedSkill struct {
Name string `json:"name"`
Path string `json:"path"`
Origin *Origin `json:"origin,omitempty"`
// FilesCopied counts supporting files installed alongside SKILL.md
// (scripts/, references/, assets/, and package metadata).
FilesCopied int `json:"filesCopied"`
Findings []SecurityFinding `json:"findings,omitempty"`
}
ImportedSkill records a successfully imported skill.
type Importer ¶
type Importer struct {
// contains filtered or unexported fields
}
Importer orchestrates the skill import process.
func NewImporter ¶
func NewImporter(store *registry.Store, registryDir, lockPath string, logger *slog.Logger) *Importer
NewImporter creates a new skill importer.
func (*Importer) AdvanceTracking ¶
AdvanceTracking records that a skill has been reconciled against upstream commit newSHA without changing its on-disk content. It advances only the version-tracking metadata — the skill's origin CommitSHA and the lock-file source's CommitSHA/ContentHash/FetchedAt — leaving the SKILL.md file and its InstalledHash untouched.
Used when a sync skips a locally-edited (drifted) skill: the reviewed upstream version is recorded so it no longer surfaces as an available update, while the user's local edits (and the drift signal that DetectDrift derives from InstalledHash) are preserved.
func (*Importer) BackupSkillFile ¶
func (imp *Importer) BackupSkillFile(ctx context.Context, skillName, shortSHA string) (string, error)
BackupSkillFile copies a skill's current SKILL.md to SKILL.md.pre-<shortSHA> next to it before an overwrite, so a forced update of a locally-edited skill stays recoverable. It returns the backup file name (relative to the skill directory). A missing SKILL.md is a no-op that returns an empty name.
func (*Importer) Detach ¶
Detach makes an imported skill local-only by removing its origin sidecar and its lock-file entry. The SKILL.md and the skill itself remain; it simply no longer tracks an upstream source and will not be touched by sync.
func (*Importer) Diff ¶
Diff fetches the latest upstream SKILL.md for an imported skill and returns both the current on-disk content and the content an update would install, without writing anything to the registry or changing any SHAs/InstalledHash. It is on-demand only — the caller pays for one git fetch.
func (*Importer) Import ¶
func (imp *Importer) Import(opts ImportOptions) (*ImportResult, error)
Import clones a repo, discovers skills and agents, validates, scans, and imports.
func (*Importer) RemoveAgent ¶
RemoveAgent removes an imported agent and cleans up origin and lock entries.
func (*Importer) SetCredentialResolver ¶
func (imp *Importer) SetCredentialResolver(r CredentialResolver)
SetCredentialResolver registers a resolver used to expand CredentialRef values stored in Origin/LockFile when Update fetches the latest state. Without a resolver, Update can still run for sources that have no stored reference (ambient GITHUB_TOKEN / public repos), but will fail fast for sources that do.
func (*Importer) Update ¶
func (imp *Importer) Update(skillName string, dryRun, force, trust bool) (*ImportResult, error)
Update fetches latest for a skill and applies changes.
trust forwards to ImportOptions.Trust. It defaults to false at every caller: a sync that surfaces new security findings is skipped with the finding text rather than applied silently. Previously this was hardcoded true, which meant every sync refreshed upstream content with the scan gate disabled, harmless while only the SKILL.md body was scanned, but not once supporting files are installed too.
type InstalledAgent ¶
type InstalledAgent struct {
Name string
Definition *AgentDefinition
// Dir is the agent's canonical directory (holds AGENT.md and its
// .origin.json sidecar).
Dir string
}
InstalledAgent is one agent present in the canonical store.
func GetAgent ¶
func GetAgent(registryDir, name string) (*InstalledAgent, error)
GetAgent returns one agent from the canonical store.
func ListAgents ¶
func ListAgents(registryDir string) ([]InstalledAgent, error)
ListAgents returns the agents in the canonical store, sorted by name. A missing store directory is the normal no-agents state. Entries whose AGENT.md is missing or unparseable are skipped: the store lists what it can serve.
type LockFile ¶
type LockFile struct {
Version int `yaml:"version"`
Sources map[string]LockedSource `yaml:"sources"`
}
LockFile represents skills.lock.yaml — pins exact versions of imported skills.
func ReadLockFile ¶
ReadLockFile reads and parses skills.lock.yaml. Version-less files (written before the schema carried a version) migrate to the current version on read; files from a newer gridctl are rejected with ErrNewerImportLockVersion.
func (*LockFile) FindAgentSource ¶
func (lf *LockFile) FindAgentSource(agentName string) (string, *LockedSource, bool)
FindAgentSource finds the source name for a given agent.
func (*LockFile) FindPackSource ¶
func (lf *LockFile) FindPackSource(packName string) (string, *LockedSource, bool)
FindPackSource finds the source carrying a pack by pack name.
func (*LockFile) FindSkillSource ¶
func (lf *LockFile) FindSkillSource(skillName string) (string, *LockedSource, bool)
FindSkillSource finds the source name for a given skill.
func (*LockFile) RemoveAgent ¶
RemoveAgent removes a single agent from the lock file, cleaning up the source when neither skills nor agents remain under it.
func (*LockFile) RemoveSkill ¶
RemoveSkill removes a single skill from the lock file, cleaning up the source when neither skills nor agents remain under it.
func (*LockFile) RemoveSource ¶
RemoveSource removes a source from the lock file.
func (*LockFile) SetSource ¶
func (lf *LockFile) SetSource(name string, src LockedSource)
SetSource updates or adds a source in the lock file.
type LockedAgent ¶
LockedAgent records per-agent metadata within a source.
type LockedPack ¶
type LockedPack struct {
Name string `yaml:"name"`
Version string `yaml:"version,omitempty"`
// Description and Author persist the manifest metadata a list view
// needs, so no consumer ever has to re-clone the repo to show it.
// Additive fields: files without them keep loading, and version 2
// (which every pack record already stamps) covers them.
Description string `yaml:"description,omitempty"`
Author string `yaml:"author,omitempty"`
Wiring bool `yaml:"wiring,omitempty"`
Clients []string `yaml:"clients,omitempty"`
Skills []string `yaml:"skills,omitempty"`
Agents []string `yaml:"agents,omitempty"`
// Rules lists context rule fragments imported from the pack repo.
// Superseded by RuleFiles, which adds per-rule provenance; retained so
// lockfiles written before that keep loading, and kept in sync on write
// so a downgrade still sees the selection.
Rules []string `yaml:"rules,omitempty"`
// RuleFiles records per-rule provenance keyed by fragment name. An entry
// with an empty ContentHash means provenance is unknown (migrated from a
// Rules-only lockfile), and callers must fall back to byte comparison
// rather than treating the empty hash as a match.
RuleFiles map[string]LockedRule `yaml:"rule_files,omitempty"`
// Unresolved lists manifest-selected names discovery could not find,
// so status can keep reporting them until the upstream repo (or the
// manifest) is fixed.
Unresolved []string `yaml:"unresolved,omitempty"`
}
LockedPack is the recorded state of an imported pack: the manifest identity plus the selection as resolved against discovery at import time (never the empty-means-all shorthand).
type LockedRule ¶
LockedRule records per-rule-fragment metadata within a pack source. The content hash is what lets a later install tell an upstream change apart from a local edit; without it the only available comparison is raw bytes against disk, which conflates the two.
type LockedSkill ¶
type LockedSkill struct {
Path string `yaml:"path"`
ContentHash string `yaml:"content_hash"`
Fingerprint *Fingerprint `yaml:"fingerprint,omitempty"`
}
LockedSkill records per-skill metadata within a source.
type LockedSource ¶
type LockedSource struct {
Repo string `yaml:"repo"`
Ref string `yaml:"ref"`
ResolvedRef string `yaml:"resolved_ref,omitempty"`
CommitSHA string `yaml:"commit_sha"`
FetchedAt time.Time `yaml:"fetched_at"`
ContentHash string `yaml:"content_hash"`
Skills map[string]LockedSkill `yaml:"skills"`
// Agents records agent definitions imported from this source.
Agents map[string]LockedAgent `yaml:"agents,omitempty"`
// CredentialRef is an opaque reference like "${vault:GIT_TOKEN}" used to
// re-resolve credentials on source update. Raw tokens are never stored.
CredentialRef string `yaml:"credential_ref,omitempty"`
// Pack records the pack manifest this source was imported through,
// with its resolved selection. Nil for plain skill/agent sources.
Pack *LockedPack `yaml:"pack,omitempty"`
}
LockedSource records the resolved state of a skill source.
type MalformedAgent ¶
type MalformedAgent = MalformedSkill
MalformedAgent aliases MalformedSkill so agent call sites read as what they are; the shape and JSON encoding are identical.
type MalformedSkill ¶
type MalformedSkill struct {
Path string `json:"path"` // Relative path from repo root
Err string `json:"error"`
}
MalformedSkill records a SKILL.md that could not be read or parsed (or a directory that could not be walked), so callers can surface the failure instead of silently dropping it.
type Origin ¶
type Origin struct {
Repo string `json:"repo"`
Ref string `json:"ref"`
Path string `json:"path,omitempty"`
CommitSHA string `json:"commitSha"`
ImportedAt time.Time `json:"importedAt"`
ContentHash string `json:"contentHash"`
// InstalledHash is the SHA-256 of the SKILL.md as written to disk
// immediately after the last import. DetectDrift compares the current
// on-disk hash against this to surface local user edits. Distinct from
// ContentHash, which records the upstream file as fetched (and which
// diverges from the installed file because of frontmatter render
// normalization and state injection).
InstalledHash string `json:"installedHash,omitempty"`
Fingerprint *Fingerprint `json:"fingerprint,omitempty"`
// CredentialRef is an opaque reference like "${vault:GIT_TOKEN}" used to
// re-resolve credentials on skill update. Raw token values are never
// persisted — only the reference string.
CredentialRef string `json:"credentialRef,omitempty"`
}
Origin tracks the remote source of an imported skill. Stored as .origin.json alongside the SKILL.md file.
func ReadOrigin ¶
ReadOrigin reads the .origin.json file from a skill directory.
type ScanResult ¶
type ScanResult struct {
SkillName string `json:"skillName"`
Findings []SecurityFinding `json:"findings"`
Safe bool `json:"safe"`
}
ScanResult contains the security scan results for a skill.
func ScanAgent ¶
func ScanAgent(def *AgentDefinition) *ScanResult
ScanAgent checks an agent definition for dangerous patterns in its body and frontmatter values. Like skill bodies (and unlike supporting files), any finding blocks: an agent definition is instructions the client executes with tool access.
func ScanFragment ¶
func ScanFragment(name string, content []byte) *ScanResult
ScanFragment checks a context rule fragment for dangerous patterns. Rule fragments are instructions clients inject into every session, so they get the same blocking scan agents do: the whole file (frontmatter and body) is scanned, and any finding blocks without --trust.
func ScanSkill ¶
func ScanSkill(sk *registry.AgentSkill) *ScanResult
ScanSkill checks a skill for dangerous patterns in its body.
type SecurityFinding ¶
type SecurityFinding struct {
StepID string `json:"stepId"`
Pattern string `json:"pattern"`
Description string `json:"description"`
Severity string `json:"severity"` // "warning" or "danger"
}
SecurityFinding represents a potentially dangerous pattern found in a skill.
func ScanSkillTree ¶
func ScanSkillTree(sk *registry.AgentSkill, srcDir string) (findings []SecurityFinding, blocking bool)
ScanSkillTree runs the same security gate an import applies to one discovered skill: the SKILL.md body (any finding blocks) plus the supporting-file tree (danger-severity findings block; lower severities surface without blocking). srcDir is the skill's directory in the clone. Callers that refuse before importing (the pack REST surface) use this so their refusal covers exactly what the importer would skip.
type SkillDefaults ¶
type SkillDefaults struct {
AutoUpdate bool `yaml:"auto_update" json:"autoUpdate"`
UpdateInterval string `yaml:"update_interval" json:"updateInterval"`
}
SkillDefaults defines global defaults for skill sources.
type SkillInfo ¶
type SkillInfo struct {
Name string `json:"name"`
Origin *Origin `json:"origin,omitempty"`
IsRemote bool `json:"isRemote"`
UpdateAvail bool `json:"updateAvailable"`
LatestSHA string `json:"latestSha,omitempty"`
LastChecked time.Time `json:"lastChecked,omitempty"`
}
SkillInfo returns details about an imported skill.
type SkillSource ¶
type SkillSource struct {
Name string `yaml:"name" json:"name"`
Repo string `yaml:"repo" json:"repo"`
Ref string `yaml:"ref,omitempty" json:"ref,omitempty"`
Path string `yaml:"path,omitempty" json:"path,omitempty"`
AutoUpdate *bool `yaml:"auto_update,omitempty" json:"autoUpdate,omitempty"`
UpdateInterval string `yaml:"update_interval,omitempty" json:"updateInterval,omitempty"`
Auth *SourceAuth `yaml:"auth,omitempty" json:"auth,omitempty"`
}
SkillSource defines a remote skill source in skills.yaml.
type SkillUpdate ¶
type SkillUpdate struct {
CurrentSHA string `yaml:"current_sha"`
LatestSHA string `yaml:"latest_sha"`
Repo string `yaml:"repo"`
Ref string `yaml:"ref"`
}
SkillUpdate describes an available update for a skill.
type SkillsConfig ¶
type SkillsConfig struct {
Defaults SkillDefaults `yaml:"defaults,omitempty" json:"defaults,omitempty"`
Sources []SkillSource `yaml:"sources" json:"sources"`
}
SkillsConfig represents the skills.yaml file.
func DefaultSkillsConfig ¶
func DefaultSkillsConfig() *SkillsConfig
DefaultSkillsConfig returns a config with sensible defaults.
func LoadSkillsConfig ¶
func LoadSkillsConfig(path string) (*SkillsConfig, error)
LoadSkillsConfig reads and parses a skills.yaml file.
func (*SkillsConfig) EffectiveAutoUpdate ¶
func (c *SkillsConfig) EffectiveAutoUpdate(src *SkillSource) bool
EffectiveAutoUpdate returns the auto_update setting for a source, falling back to the global default.
func (*SkillsConfig) EffectiveUpdateInterval ¶
func (c *SkillsConfig) EffectiveUpdateInterval(src *SkillSource) time.Duration
EffectiveUpdateInterval returns the update_interval for a source, falling back to the global default.
type SkippedAgent ¶
type SkippedAgent = SkippedSkill
SkippedAgent aliases SkippedSkill so agent call sites read as what they are; the shape and JSON encoding are identical.
type SkippedSkill ¶
SkippedSkill records a skill (or agent) that was skipped during import.
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"`
SSHKeyPath string `yaml:"ssh_key_path,omitempty" json:"sshKeyPath,omitempty"`
}
SourceAuth is the declarative auth block on a skills.yaml source. Raw tokens must NOT appear here — use CredentialRef (e.g. "${vault:GIT_TOKEN}") which is resolved against the live vault at clone/fetch time.
func (*SourceAuth) ToAuthConfig ¶
func (a *SourceAuth) ToAuthConfig() AuthConfig
ToAuthConfig converts the declarative block into a runtime AuthConfig. CredentialRef is copied through unchanged; callers are responsible for resolving it to a raw Token before invoking the importer.
type UpdateStatus ¶
type UpdateStatus struct {
CheckedAt time.Time `yaml:"checked_at"`
Updates map[string]SkillUpdate `yaml:"updates,omitempty"`
Errors []string `yaml:"errors,omitempty"`
}
UpdateStatus records the result of a background update check.
func ReadUpdateCache ¶
func ReadUpdateCache() (*UpdateStatus, error)
ReadUpdateCache reads the cached update status from the default path.
func ReadUpdateCacheAt ¶
func ReadUpdateCacheAt(path string) (*UpdateStatus, error)
ReadUpdateCacheAt reads the cached update status from an explicit path. Returns (nil, nil) when the file does not exist so callers can fail open.