Documentation
¶
Index ¶
- Variables
- func AgentsAttachingSkill(agentsDir, skillName string) ([]string, error)
- func AppendAlwaysAllowTool(agentsDir, agentName, tool string) error
- func AtomicWrite(path string, data []byte) error
- func AttachSkill(agentsDir, agentName, skillName string) error
- func DeleteAgentCommand(agentsDir, agentName, cmdName string) error
- func DeleteAgentDir(agentsDir, name string) error
- func DeleteAgentSkill(agentsDir, agentName, skillName string) error
- func DeleteAttachedSkills(agentsDir, agentName string) error
- func DetachSkill(agentsDir, agentName, skillName string) error
- func DetectTriggerConflicts(agentsDir, agentName string, schedules []ScheduleRef) []string
- func EnsureBuiltins(agentsDir, currentVersion string) error
- func HighRiskTools() []string
- func IsBuiltinAgent(name string) bool
- func IsToolAlwaysAllowable(toolName string) bool
- func LoadGlobalSkills(shannonDir string) ([]*skills.Skill, error)
- func MaterializeBuiltin(agentsDir, name string) error
- func ParseAgentMention(msg string) (string, string)
- func ReadAttachedSkills(agentsDir, agentName string) ([]string, error)
- func RemoveAlwaysAllowTool(agentsDir, agentName, tool string) error
- func SetAttachedSkills(agentsDir, agentName string, names []string) error
- func ValidateAgentName(name string) error
- func ValidateCommandName(name string) error
- func ValidateToolsFilter(f *AgentToolsFilter) error
- func WriteAgentCommand(agentsDir, agentName, cmdName, content string) error
- func WriteAgentConfig(agentsDir, name string, cfg *AgentConfigAPI) error
- func WriteAgentMemory(agentsDir, name, memory string) error
- func WriteAgentPrompt(agentsDir, name, prompt string) error
- func WriteAgentSkill(agentsDir, agentName string, skill *skills.Skill) error
- func WriteAttachedSkills(agentsDir, agentName string, names []string) error
- type Agent
- type AgentAPI
- type AgentConfig
- type AgentConfigAPI
- type AgentCreateRequest
- type AgentEntry
- type AgentMCPConfig
- type AgentMCPConfigAPI
- type AgentMCPServerRef
- type AgentModelConfig
- type AgentPermissionsConfig
- type AgentToolsFilter
- type AgentUpdateRequest
- type HeartbeatConfig
- type ScheduleRef
- type WatchEntry
Constants ¶
This section is empty.
Variables ¶
var BuiltinCommands = map[string]bool{ "quit": true, "exit": true, "help": true, "clear": true, "sessions": true, "session": true, "model": true, "config": true, "setup": true, "update": true, "copy": true, "research": true, "swarm": true, "search": true, }
BuiltinCommands is the set of slash command names reserved by the TUI. Agent commands and skills must not use these names.
var BuiltinNames = []string{"explorer", "reviewer"}
BuiltinNames lists the names of all bundled specialist agents.
var ErrToolNotPersistable = errors.New("tool cannot be persisted as always-allow")
ErrToolNotPersistable is returned when a tool cannot be persisted to a per-agent always-allow list. Currently this only fires for high-risk tools (see isHighRiskTool); the runtime check enforces the same gate even if a hand-edited config.yaml manages to bypass this function.
Functions ¶
func AgentsAttachingSkill ¶
AgentsAttachingSkill returns the names of agents whose _attached.yaml manifest references the given skill. The result is sorted alphabetically and is always a non-nil slice (empty slice when no agents attach the skill), so JSON responses render as "[]" rather than "null".
Errors from reading a single agent's manifest are skipped — a corrupt manifest for agent A should not hide attachments in agent B. Only a filesystem error opening agentsDir itself is returned.
func AppendAlwaysAllowTool ¶ added in v0.1.9
AppendAlwaysAllowTool adds a tool name to the agent's permissions.always_allow_tools list in <agentsDir>/<agentName>/config.yaml.
Concurrency: serialized via flock on <agentDir>/.config.lock. The lock file is persistent (never deleted) — see schedule.go for rationale.
First-write: creates the agent directory and an otherwise-empty config.yaml.
Idempotent: duplicate calls are no-ops (the list is deduplicated and sorted).
Defense-in-depth: high-risk tools (isHighRiskTool) are rejected with ErrToolNotPersistable. The runtime check at internal/agent/loop.go checkPermissionAndApproval also refuses to honor such entries.
func AtomicWrite ¶
AtomicWrite writes data to path via temp file + rename.
func AttachSkill ¶
AttachSkill adds a skill name to an agent's attached-skill manifest.
func DeleteAgentCommand ¶
DeleteAgentCommand removes a single command file.
func DeleteAgentDir ¶
DeleteAgentDir removes the entire agent directory.
func DeleteAgentSkill ¶
DeleteAgentSkill removes a single skill directory.
func DeleteAttachedSkills ¶
DeleteAttachedSkills removes the _attached.yaml manifest.
func DetachSkill ¶
DetachSkill removes a skill name from an agent's attached-skill manifest.
func DetectTriggerConflicts ¶ added in v0.0.98
func DetectTriggerConflicts(agentsDir, agentName string, schedules []ScheduleRef) []string
DetectTriggerConflicts returns human-readable warnings when an agent has BOTH a non-zero heartbeat.every AND at least one enabled schedule targeting it. The returned slice is nil when there is no conflict.
Contract:
- agentsDir + agentName are the usual LoadAgent inputs.
- schedules is the full list (e.g. schedule.Manager.List()) — entries with a non-matching Agent name or Enabled=false are ignored.
- Missing/malformed agent files produce no warnings (empty slice, nil err). Callers must not panic. Visibility only, never a hard error.
func EnsureBuiltins ¶
EnsureBuiltins syncs embedded agent definitions to agentsDir/_builtin/. Skips if the on-disk version matches currentVersion (idempotent). Uses write-to-temp-then-rename for atomicity: .version is written last.
func HighRiskTools ¶ added in v0.1.9
func HighRiskTools() []string
HighRiskTools returns a copy of the tools that cannot be persisted to a per-agent always-allow list. Exposed for cross-package consistency tests.
func IsBuiltinAgent ¶
IsBuiltinAgent returns true if the given name matches a bundled agent.
func IsToolAlwaysAllowable ¶ added in v0.1.9
IsToolAlwaysAllowable reports whether a tool may be persisted to an agent's permissions.always_allow_tools list. High-risk tools that require fresh human re-approval each call (publish_to_web, generate_image, edit_image) are not persistable. The runtime enforces the same gate independently — see internal/agent/loop.go checkPermissionAndApproval — so a hand-edited config.yaml cannot bypass the prompt.
func LoadGlobalSkills ¶
LoadGlobalSkills loads skills from the global skills directory (~/.shannon/skills/). Only installed (global) skills are returned — bundled skills must be explicitly installed first (except those auto-installed by EnsureBuiltinSkills).
func MaterializeBuiltin ¶
MaterializeBuiltin copies all definition files from _builtin/<name>/ to <name>/ in agentsDir. Used before CRUD writes to ensure the user-override directory is self-contained. MEMORY.md is NOT copied (it already lives at the top-level runtime dir). Returns nil if the builtin dir doesn't exist.
func ParseAgentMention ¶
func ReadAttachedSkills ¶
ReadAttachedSkills reads an agent's attached-skill manifest. Returns (nil, nil) when the manifest does not exist.
func RemoveAlwaysAllowTool ¶ added in v0.1.9
RemoveAlwaysAllowTool removes a tool name from the agent's permissions.always_allow_tools list. No-op if the tool is not present, the list is empty, or config.yaml does not exist.
If the resulting list is empty AND no other permissions sub-fields are set, the permissions: top-level key is dropped to keep YAML clean.
func SetAttachedSkills ¶
SetAttachedSkills replaces an agent's attached-skill manifest with a normalized set. Names are deduplicated and sorted; an empty set removes the manifest.
func ValidateAgentName ¶
func ValidateCommandName ¶
ValidateCommandName checks that a command/skill name is valid and doesn't collide with built-in slash commands.
func ValidateToolsFilter ¶
func ValidateToolsFilter(f *AgentToolsFilter) error
ValidateToolsFilter checks that allow and deny are not both set.
func WriteAgentCommand ¶
WriteAgentCommand writes a single command file.
func WriteAgentConfig ¶
func WriteAgentConfig(agentsDir, name string, cfg *AgentConfigAPI) error
WriteAgentConfig writes config.yaml from the API shape.
Serializes on <agentDir>/.config.lock to prevent lost-update races against AppendAlwaysAllowTool / RemoveAlwaysAllowTool (which read-modify-write the same file under the same lock).
func WriteAgentMemory ¶
WriteAgentMemory writes MEMORY.md atomically.
func WriteAgentPrompt ¶
WriteAgentPrompt writes AGENT.md atomically.
func WriteAgentSkill ¶
WriteAgentSkill writes a skill as a SKILL.md file with YAML frontmatter. Uses proper YAML marshalling to handle special characters in values.
Directory is keyed by Slug (URL-safe identifier). Falls back to Name for skills that predate the Name/Slug split where Slug is unset.
func WriteAttachedSkills ¶
WriteAttachedSkills writes the _attached.yaml manifest for an agent.
Types ¶
type Agent ¶
type Agent struct {
Name string
Prompt string
Memory string
Config *AgentConfig // nil = inherit everything (backwards-compatible)
Commands map[string]string // agent-scoped slash commands (name → content)
Skills []*skills.Skill // agent-scoped skills (prompt, tool_chain, sub_agent)
}
Agent represents a loaded agent definition.
type AgentAPI ¶
type AgentAPI struct {
Name string `json:"name"`
Prompt string `json:"prompt"`
Memory *string `json:"memory"` // null if no MEMORY.md
Config *AgentConfigAPI `json:"config"` // null if no config.yaml
Commands map[string]string `json:"commands"` // null if no commands
Skills []skills.SkillMeta `json:"skills"` // null if no skills
Builtin bool `json:"builtin"` // true if agent is a bundled builtin
Overridden bool `json:"overridden"` // true if builtin has user override
Warnings []string `json:"warnings,omitempty"` // non-fatal config advisories (e.g. heartbeat⊕schedule double-fire)
}
AgentAPI is the JSON representation of an agent for the HTTP API.
type AgentConfig ¶
type AgentConfig struct {
CWD string `yaml:"cwd"`
MCPServers *AgentMCPConfig `yaml:"-"` // parsed manually for _inherit
Tools *AgentToolsFilter `yaml:"tools"`
Agent *AgentModelConfig `yaml:"agent"`
AutoApprove *bool `yaml:"auto_approve"`
Permissions *AgentPermissionsConfig `yaml:"permissions,omitempty"`
Watch []WatchEntry `yaml:"watch,omitempty"`
Heartbeat *HeartbeatConfig `yaml:"heartbeat,omitempty"`
}
AgentConfig is the per-agent config overlay loaded from config.yaml.
type AgentConfigAPI ¶
type AgentConfigAPI struct {
CWD string `json:"cwd,omitempty"`
Tools *AgentToolsFilter `json:"tools,omitempty"`
MCPServers *AgentMCPConfigAPI `json:"mcp_servers,omitempty"`
Agent *AgentModelConfig `json:"agent,omitempty"`
Permissions *AgentPermissionsConfig `json:"permissions,omitempty"`
Watch []WatchEntry `json:"watch,omitempty"`
Heartbeat *HeartbeatConfig `json:"heartbeat,omitempty"`
}
AgentConfigAPI is the JSON representation of agent config.
type AgentCreateRequest ¶
type AgentCreateRequest struct {
Name string `json:"name"`
Prompt string `json:"prompt"`
Memory *string `json:"memory,omitempty"`
Config *AgentConfigAPI `json:"config,omitempty"`
Commands map[string]string `json:"commands,omitempty"`
Skills []*skills.Skill `json:"skills,omitempty"`
}
AgentCreateRequest parses a POST /agents request body.
func (*AgentCreateRequest) Validate ¶
func (r *AgentCreateRequest) Validate() error
Validate checks required fields and runs all validators.
type AgentEntry ¶
type AgentEntry struct {
Name string `json:"name"`
Builtin bool `json:"builtin"` // loaded from _builtin
Override bool `json:"override"` // user-defined agent overrides a builtin
}
AgentEntry represents an agent in the listing with source metadata.
func ListAgents ¶
func ListAgents(agentsDir string) ([]AgentEntry, error)
type AgentMCPConfig ¶
type AgentMCPConfig struct {
Inherit bool
Servers map[string]AgentMCPServerRef
}
AgentMCPConfig holds MCP server configs with an optional inherit flag. When Inherit is false (default), only the servers listed here are used. When Inherit is true, these servers are merged on top of the global set. This struct is populated programmatically by parseAgentConfig, not by direct YAML unmarshaling.
type AgentMCPConfigAPI ¶
type AgentMCPConfigAPI struct {
Inherit bool `json:"inherit"`
Servers map[string]AgentMCPServerRef `json:"servers,omitempty"`
}
AgentMCPConfigAPI is the JSON-friendly MCP config.
type AgentMCPServerRef ¶
type AgentMCPServerRef struct {
Command string `yaml:"command" json:"command,omitempty"`
Args []string `yaml:"args,omitempty" json:"args,omitempty"`
Env map[string]string `yaml:"env,omitempty" json:"env,omitempty"`
Type string `yaml:"type,omitempty" json:"type,omitempty"`
URL string `yaml:"url,omitempty" json:"url,omitempty"`
Disabled bool `yaml:"disabled,omitempty" json:"disabled,omitempty"`
Context string `yaml:"context,omitempty" json:"context,omitempty"`
KeepAlive bool `yaml:"keep_alive,omitempty" json:"keep_alive,omitempty"`
}
AgentMCPServerRef mirrors the fields needed for per-agent MCP server config. We keep it simple — the full MCPServerConfig is resolved at merge time.
type AgentModelConfig ¶
type AgentModelConfig struct {
Model *string `yaml:"model" json:"model,omitempty"`
MaxIterations *int `yaml:"max_iterations" json:"max_iterations,omitempty"`
Temperature *float64 `yaml:"temperature" json:"temperature,omitempty"`
MaxTokens *int `yaml:"max_tokens" json:"max_tokens,omitempty"`
ContextWindow *int `yaml:"context_window" json:"context_window,omitempty"`
IdleSoftTimeoutSecs *int `yaml:"idle_soft_timeout_secs" json:"idle_soft_timeout_secs,omitempty"`
IdleHardTimeoutSecs *int `yaml:"idle_hard_timeout_secs" json:"idle_hard_timeout_secs,omitempty"`
}
AgentModelConfig holds per-agent model/iteration overrides.
type AgentPermissionsConfig ¶ added in v0.1.9
type AgentPermissionsConfig struct {
// AlwaysAllowTools lists tool names whose approval prompts the user has
// chosen to skip permanently for this agent. High-risk tools (see
// agent.DisallowsAutoApproval) are never honored here even if present —
// the runtime check enforces defense-in-depth.
AlwaysAllowTools []string `yaml:"always_allow_tools,omitempty" json:"always_allow_tools,omitempty"`
}
AgentPermissionsConfig carries per-agent permission overrides. Distinct from tools.allow (which is a schema filter — controls what the LLM can see): these entries are approval bypasses applied at execution time.
func (*AgentPermissionsConfig) Clone ¶ added in v0.1.9
func (p *AgentPermissionsConfig) Clone() *AgentPermissionsConfig
Clone returns a deep copy. ToAPI uses this so the API response cannot share slice backing arrays with the in-memory Agent — an HTTP handler that mutates the returned slice would otherwise leak into the next call's response. Returns nil if p is nil.
func (*AgentPermissionsConfig) IsEmpty ¶ added in v0.1.9
func (p *AgentPermissionsConfig) IsEmpty() bool
IsEmpty reports whether the struct carries no effective configuration. WriteAgentConfig uses this to decide whether to emit the permissions: block at all, avoiding "permissions: {}" noise in YAML. Update this whenever a new field is added to AgentPermissionsConfig.
type AgentToolsFilter ¶
type AgentToolsFilter struct {
Allow []string `yaml:"allow,omitempty" json:"allow,omitempty"`
Deny []string `yaml:"deny,omitempty" json:"deny,omitempty"`
}
AgentToolsFilter controls which local tools an agent can access. If Allow is non-empty, only those tools are available. If Deny is non-empty, all tools except those are available. If both are empty, all tools are available (backwards-compatible).
type AgentUpdateRequest ¶
type AgentUpdateRequest struct {
Prompt *string `json:"prompt,omitempty"`
Memory json.RawMessage `json:"memory,omitempty"` // string or null
Config json.RawMessage `json:"config,omitempty"` // object or null
Commands map[string]string `json:"commands,omitempty"`
Skills []*skills.Skill `json:"skills,omitempty"`
}
AgentUpdateRequest is a partial update — only non-nil fields are applied.
type HeartbeatConfig ¶
type HeartbeatConfig struct {
Every string `yaml:"every" json:"every"`
ActiveHours string `yaml:"active_hours,omitempty" json:"active_hours,omitempty"`
Model string `yaml:"model,omitempty" json:"model,omitempty"`
IsolatedSession *bool `yaml:"isolated_session,omitempty" json:"isolated_session,omitempty"`
}
HeartbeatConfig configures periodic heartbeat checks for an agent. IsolatedSession defaults to true (nil = true). Use pointer for YAML omit-means-default.
func (*HeartbeatConfig) IsIsolatedSession ¶
func (h *HeartbeatConfig) IsIsolatedSession() bool
IsIsolatedSession returns the effective value (default true).
type ScheduleRef ¶ added in v0.0.98
ScheduleRef is the minimal view of a schedule needed by DetectTriggerConflicts. It intentionally mirrors the subset of internal/schedule.Schedule that the warning logic consumes, so this package does not import internal/schedule (and so tests can construct a slice without a real schedule store).
type WatchEntry ¶
type WatchEntry struct {
Path string `yaml:"path" json:"path"`
Glob string `yaml:"glob,omitempty" json:"glob,omitempty"`
}
WatchEntry defines a single file system watch path for an agent.