Install
$ agentstack add skill-genai-io-san-2-feature ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
skill
Loads markdown-defined skills from user / project / plugin scopes, tracks their enable state, and renders the active-skills directory that the harness attaches to user messages via the skills-directory reminder (see [concepts/harness-channels.md](../../concepts/harness-channels.md)).
Purpose
A skill is a markdown file (with YAML frontmatter) that the model can be made aware of (active), made invocable via slash command (enabled), or hidden (disabled). This package:
- Discovers skills across six scopes
(~/.claude/skills/, ~/.san/plugins/*/skills/, ~/.san/skills/, .claude/skills/, .san/plugins/*/skills/, .san/skills/) with project overriding user overriding Claude-compat.
- Persists per-skill state in user / project state stores.
- Renders the active-skills block consumed by the
skills-directory
reminder provider in internal/app.
For the broader extension model see [concepts/extension-model.md](../../concepts/extension-model.md). A how-to-author-a-skill guide is tracked in notes/tech-debt.md.
Contract
The package exposes *Registry directly. Skill consumers each use a different subset of the registry surface — the TUI selector goes wide (List / GetStatesAt / SetState), the slash-command flow uses narrow lookups (Get / FindByPartialName / GetSkillInvocationPrompt), the system-prompt builder uses one method (PromptSection), and the session recorder attaches an observer (SetStateChangeObserver). No shared narrow surface ⇒ no producer-side role interface earns its keep.
package skill
// Registry is an opaque handle to the loaded skill set plus per-scope
// enabled-state stores. The type is exported so callers can hold and
// pass *Registry values; all fields are unexported.
type Registry struct { /* internal fields */ }
// Query
func (r *Registry) Get(name string) (*Skill, bool)
func (r *Registry) FindByPartialName(name string) *Skill
func (r *Registry) List() []*Skill
func (r *Registry) GetEnabled() []*Skill
func (r *Registry) GetActive() []*Skill
func (r *Registry) Count() int
func (r *Registry) IsEnabled(name string) bool
// State (used by the TUI selector)
func (r *Registry) SetState(name string, state SkillState, userLevel bool) error
func (r *Registry) GetStatesAt(userLevel bool) map[string]SkillState
func (r *Registry) SetEnabled(name string, enabled bool, userLevel bool) error
func (r *Registry) GetDisabledAt(userLevel bool) map[string]bool
// Rendering (consumed by the skills-directory reminder provider)
func (r *Registry) PromptSection() string
func (r *Registry) GetSkillInvocationPrompt(name string) string
// Recorder observer (used by the session recorder)
func (r *Registry) SetStateChangeObserver(cb StateChangeObserver)
// Package-level access
func Initialize(opts Options)
func Default() *Registry
func DefaultIfInit() *Registry // nil if pre-Initialize
func SetDefaultRegistry(r *Registry) // test-only
func ResetDefaultRegistry() // test-only
// Skill, SkillState, SkillScope — see types.go for value types.
Internals
Registry(registry.go) is the only implementation, holding:skills []*Skill— loaded byloaderuserStore,projectStore— JSON-backed persistence of per-skill
SkillState
cwd— for project-scope resolutionloader.gowalks the six scopes in priority order, parsing
SKILL.md frontmatter and bundled resource directories (scripts/ / references/ / assets/).
- State (
disable→enable→active→disable) cycles via
SkillState.NextState(); the TUI's /skill flow uses this.
- Active skills render through
PromptSection()and are delivered to
the model via the skills-directory reminder attached to each user message; enable-only skills surface as slash commands but stay out of the model's awareness entirely.
Lifecycle
- Construction:
Initialize(Options{CWD})at app startup, before
internal/command builds its slash-command list. Singleton thereafter.
- Mutation:
SetEnabledwrites through to user or project store
immediately; in-memory skills slice is updated in place.
- Plugin sources are added post-init by
internal/pluginvia
AddPluginSkills.
- Concurrency: registry mutations are mutex-guarded; reads are
RWMutex-locked.
Tests
internal/skill/skill_test.go — loader, state cycling,
scope priority, prompt rendering.
internal/skill/lazy_loading_test.go — verifies content stays on disk
until GetInstructions().
See Also
- Code:
internal/skill/ - Concepts: [
concepts/extension-model.md](../../concepts/extension-model.md), [concepts/harness-channels.md](../../concepts/harness-channels.md) - Related: [
packages/command.md](command.md) (slash-command surface), [packages/plugin.md](plugin.md) (plugin-scoped skills), [packages/reminder.md](reminder.md) (the channel that deliversPromptSection) - Layer:
feature(see [reference/dependency-rules.md](../../reference/dependency-rules.md))
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: genai-io
- Source: genai-io/san
- License: Apache-2.0
- Homepage: https://genai-io.github.io/san/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.