Documentation
¶
Overview ¶
Package discovery provides unified resource discovery from tool-native configurations. This allows agentctl to detect and load resources (rules, skills, hooks, etc.) from tool-specific directories like .claude/, .gemini/, .cursor/ even without agentctl.json.
Index ¶
- Constants
- Variables
- func DiscoverAgents(dir string) []*agent.Agent
- func DiscoverGlobalAgents() []*agent.Agent
- func DiscoverHooks(dir string) []*hook.Hook
- func DiscoverRules(dir string) []*rule.Rule
- func DiscoverSkills(dir string) []*skill.Skill
- func HasToolConfig(dir string) bool
- func Register(s Scanner)
- func SafeReadFile(path string) ([]byte, error)
- func ToolConfigPaths(dir string) map[string]string
- type AgentScanner
- type ClaudeScanner
- func (s *ClaudeScanner) Detect(dir string) bool
- func (s *ClaudeScanner) Name() string
- func (s *ClaudeScanner) ScanAgents(dir string) ([]*agent.Agent, error)
- func (s *ClaudeScanner) ScanCommands(dir string) ([]*command.Command, error)
- func (s *ClaudeScanner) ScanGlobalAgents() ([]*agent.Agent, error)
- func (s *ClaudeScanner) ScanGlobalCommands() ([]*command.Command, error)
- func (s *ClaudeScanner) ScanGlobalHooks() ([]*hook.Hook, error)
- func (s *ClaudeScanner) ScanGlobalPlugins() ([]*Plugin, error)
- func (s *ClaudeScanner) ScanGlobalRules() ([]*rule.Rule, error)
- func (s *ClaudeScanner) ScanGlobalSkills() ([]*skill.Skill, error)
- func (s *ClaudeScanner) ScanHooks(dir string) ([]*hook.Hook, error)
- func (s *ClaudeScanner) ScanPlugins(dir string) ([]*Plugin, error)
- func (s *ClaudeScanner) ScanRules(dir string) ([]*rule.Rule, error)
- func (s *ClaudeScanner) ScanServers(dir string) ([]*mcp.Server, error)
- func (s *ClaudeScanner) ScanSkills(dir string) ([]*skill.Skill, error)
- type DirectoryScanner
- func (s *DirectoryScanner) Detect(dir string) bool
- func (s *DirectoryScanner) Name() string
- func (s *DirectoryScanner) ScanAgents(dir string) ([]*agent.Agent, error)
- func (s *DirectoryScanner) ScanCommands(dir string) ([]*command.Command, error)
- func (s *DirectoryScanner) ScanGlobalAgents() ([]*agent.Agent, error)
- func (s *DirectoryScanner) ScanHooks(dir string) ([]*hook.Hook, error)
- func (s *DirectoryScanner) ScanRules(dir string) ([]*rule.Rule, error)
- func (s *DirectoryScanner) ScanServers(dir string) ([]*mcp.Server, error)
- func (s *DirectoryScanner) ScanSkills(dir string) ([]*skill.Skill, error)
- type GeminiScanner
- func (s *GeminiScanner) Detect(dir string) bool
- func (s *GeminiScanner) Name() string
- func (s *GeminiScanner) ScanCommands(dir string) ([]*command.Command, error)
- func (s *GeminiScanner) ScanGlobalCommands() ([]*command.Command, error)
- func (s *GeminiScanner) ScanGlobalHooks() ([]*hook.Hook, error)
- func (s *GeminiScanner) ScanGlobalRules() ([]*rule.Rule, error)
- func (s *GeminiScanner) ScanGlobalSkills() ([]*skill.Skill, error)
- func (s *GeminiScanner) ScanHooks(dir string) ([]*hook.Hook, error)
- func (s *GeminiScanner) ScanRules(dir string) ([]*rule.Rule, error)
- func (s *GeminiScanner) ScanServers(dir string) ([]*mcp.Server, error)
- func (s *GeminiScanner) ScanSkills(dir string) ([]*skill.Skill, error)
- type GlobalScanner
- type NativeResource
- type Plugin
- type PluginScanner
- type SafeReader
- type Scanner
- type ScannerConfig
Constants ¶
const MaxFileSize = 1 << 20 // 1MB
MaxFileSize is the default maximum file size to read (1MB)
Variables ¶
var DefaultReader = NewSafeReader()
DefaultReader is a package-level SafeReader for convenience
Functions ¶
func DiscoverAgents ¶
DiscoverAgents scans all detected tools for agents in the given directory
func DiscoverGlobalAgents ¶
DiscoverGlobalAgents scans all tools for global agents
func DiscoverHooks ¶
DiscoverHooks scans all detected tools for hooks
func DiscoverRules ¶
DiscoverRules scans all detected tools for rules
func DiscoverSkills ¶
DiscoverSkills scans all detected tools for skills
func HasToolConfig ¶
HasToolConfig checks if any tool has a config in the given directory
func SafeReadFile ¶
SafeReadFile reads a file using the default SafeReader
func ToolConfigPaths ¶
ToolConfigPaths returns paths to all detected tool configs
Types ¶
type AgentScanner ¶
type AgentScanner interface {
Scanner
// ScanAgents discovers agents from the tool's local config directory
ScanAgents(dir string) ([]*agent.Agent, error)
// ScanGlobalAgents discovers agents from the tool's global config directory
ScanGlobalAgents() ([]*agent.Agent, error)
}
AgentScanner defines the interface for discovering agents/subagents
type ClaudeScanner ¶
type ClaudeScanner struct{}
ClaudeScanner discovers resources from Claude Code's .claude/ directory
func (*ClaudeScanner) Detect ¶
func (s *ClaudeScanner) Detect(dir string) bool
func (*ClaudeScanner) Name ¶
func (s *ClaudeScanner) Name() string
func (*ClaudeScanner) ScanAgents ¶
func (s *ClaudeScanner) ScanAgents(dir string) ([]*agent.Agent, error)
ScanAgents discovers agents from the project's local .claude/agents/ directory
func (*ClaudeScanner) ScanCommands ¶
func (s *ClaudeScanner) ScanCommands(dir string) ([]*command.Command, error)
func (*ClaudeScanner) ScanGlobalAgents ¶
func (s *ClaudeScanner) ScanGlobalAgents() ([]*agent.Agent, error)
ScanGlobalAgents discovers agents from Claude's global ~/.claude/agents/ directory
func (*ClaudeScanner) ScanGlobalCommands ¶
func (s *ClaudeScanner) ScanGlobalCommands() ([]*command.Command, error)
ScanGlobalCommands discovers commands from Claude's global config directory
func (*ClaudeScanner) ScanGlobalHooks ¶
func (s *ClaudeScanner) ScanGlobalHooks() ([]*hook.Hook, error)
ScanGlobalHooks discovers hooks from Claude's global settings
func (*ClaudeScanner) ScanGlobalPlugins ¶
func (s *ClaudeScanner) ScanGlobalPlugins() ([]*Plugin, error)
ScanGlobalPlugins discovers plugins from Claude's global plugin config
func (*ClaudeScanner) ScanGlobalRules ¶
func (s *ClaudeScanner) ScanGlobalRules() ([]*rule.Rule, error)
ScanGlobalRules discovers rules from Claude's global config directory
func (*ClaudeScanner) ScanGlobalSkills ¶
func (s *ClaudeScanner) ScanGlobalSkills() ([]*skill.Skill, error)
ScanGlobalSkills discovers skills from Claude's global config directory
func (*ClaudeScanner) ScanHooks ¶
func (s *ClaudeScanner) ScanHooks(dir string) ([]*hook.Hook, error)
func (*ClaudeScanner) ScanPlugins ¶
func (s *ClaudeScanner) ScanPlugins(dir string) ([]*Plugin, error)
ScanPlugins discovers plugins from the project's local plugin config
func (*ClaudeScanner) ScanRules ¶
func (s *ClaudeScanner) ScanRules(dir string) ([]*rule.Rule, error)
func (*ClaudeScanner) ScanServers ¶
func (s *ClaudeScanner) ScanServers(dir string) ([]*mcp.Server, error)
func (*ClaudeScanner) ScanSkills ¶
func (s *ClaudeScanner) ScanSkills(dir string) ([]*skill.Skill, error)
type DirectoryScanner ¶
type DirectoryScanner struct {
// contains filtered or unexported fields
}
DirectoryScanner is a config-driven scanner for discovering resources from tool-native directories.
func NewDirectoryScanner ¶
func NewDirectoryScanner(cfg ScannerConfig) *DirectoryScanner
NewDirectoryScanner creates a new DirectoryScanner with the given config.
func (*DirectoryScanner) Detect ¶
func (s *DirectoryScanner) Detect(dir string) bool
func (*DirectoryScanner) Name ¶
func (s *DirectoryScanner) Name() string
func (*DirectoryScanner) ScanAgents ¶
func (s *DirectoryScanner) ScanAgents(dir string) ([]*agent.Agent, error)
ScanAgents discovers agents from the tool's local agents directory
func (*DirectoryScanner) ScanCommands ¶
func (s *DirectoryScanner) ScanCommands(dir string) ([]*command.Command, error)
func (*DirectoryScanner) ScanGlobalAgents ¶
func (s *DirectoryScanner) ScanGlobalAgents() ([]*agent.Agent, error)
ScanGlobalAgents discovers agents from the tool's global agents directory
func (*DirectoryScanner) ScanHooks ¶
func (s *DirectoryScanner) ScanHooks(dir string) ([]*hook.Hook, error)
func (*DirectoryScanner) ScanRules ¶
func (s *DirectoryScanner) ScanRules(dir string) ([]*rule.Rule, error)
func (*DirectoryScanner) ScanServers ¶
func (s *DirectoryScanner) ScanServers(dir string) ([]*mcp.Server, error)
func (*DirectoryScanner) ScanSkills ¶
func (s *DirectoryScanner) ScanSkills(dir string) ([]*skill.Skill, error)
type GeminiScanner ¶
type GeminiScanner struct{}
GeminiScanner discovers resources from Gemini CLI's .gemini/ directory
func (*GeminiScanner) Detect ¶
func (s *GeminiScanner) Detect(dir string) bool
func (*GeminiScanner) Name ¶
func (s *GeminiScanner) Name() string
func (*GeminiScanner) ScanCommands ¶
func (s *GeminiScanner) ScanCommands(dir string) ([]*command.Command, error)
func (*GeminiScanner) ScanGlobalCommands ¶
func (s *GeminiScanner) ScanGlobalCommands() ([]*command.Command, error)
ScanGlobalCommands discovers commands from Gemini's global config directory
func (*GeminiScanner) ScanGlobalHooks ¶
func (s *GeminiScanner) ScanGlobalHooks() ([]*hook.Hook, error)
ScanGlobalHooks discovers hooks from Gemini's global settings
func (*GeminiScanner) ScanGlobalRules ¶
func (s *GeminiScanner) ScanGlobalRules() ([]*rule.Rule, error)
ScanGlobalRules discovers rules from Gemini's global config directory
func (*GeminiScanner) ScanGlobalSkills ¶
func (s *GeminiScanner) ScanGlobalSkills() ([]*skill.Skill, error)
ScanGlobalSkills discovers skills from Gemini's global config directory
func (*GeminiScanner) ScanHooks ¶
func (s *GeminiScanner) ScanHooks(dir string) ([]*hook.Hook, error)
func (*GeminiScanner) ScanRules ¶
func (s *GeminiScanner) ScanRules(dir string) ([]*rule.Rule, error)
func (*GeminiScanner) ScanServers ¶
func (s *GeminiScanner) ScanServers(dir string) ([]*mcp.Server, error)
func (*GeminiScanner) ScanSkills ¶
func (s *GeminiScanner) ScanSkills(dir string) ([]*skill.Skill, error)
type GlobalScanner ¶
type GlobalScanner interface {
Scanner
// ScanGlobalRules discovers rules from the tool's global config directory
ScanGlobalRules() ([]*rule.Rule, error)
// ScanGlobalSkills discovers skills from the tool's global config directory
ScanGlobalSkills() ([]*skill.Skill, error)
// ScanGlobalCommands discovers commands from the tool's global config directory
ScanGlobalCommands() ([]*command.Command, error)
// ScanGlobalHooks discovers hooks from the tool's global settings
ScanGlobalHooks() ([]*hook.Hook, error)
}
GlobalScanner defines the interface for discovering global resources
type NativeResource ¶
type NativeResource struct {
Type string // "rule", "skill", "command", "hook", "server", "plugin", "agent"
Name string
Path string // Path to the file or directory
Tool string // Which tool owns this (e.g., "claude", "gemini")
Scope string // "local" or "global"
Resource any // The actual resource (*rule.Rule, *skill.Skill, *agent.Agent, etc.)
}
NativeResource represents a resource discovered from a tool's native config
func DiscoverAll ¶
func DiscoverAll(dir string) []*NativeResource
DiscoverAll runs all scanners against the given directory and returns discovered resources
func DiscoverBoth ¶
func DiscoverBoth(dir string) []*NativeResource
DiscoverBoth discovers resources from both local and global configurations
func DiscoverGlobal ¶
func DiscoverGlobal() []*NativeResource
DiscoverGlobal discovers resources from global tool configurations
func DiscoverWorkingDir ¶
func DiscoverWorkingDir() []*NativeResource
DiscoverWorkingDir discovers resources from the current working directory
type Plugin ¶
type Plugin struct {
Name string `json:"name"`
Path string `json:"path"`
Version string `json:"version"`
Enabled bool `json:"enabled"`
Scope string `json:"-"` // "local" or "global"
Tool string `json:"-"` // Always "claude" for now
InstalledAt string `json:"installed_at,omitempty"`
LastUpdated string `json:"last_updated,omitempty"`
GitCommitSha string `json:"git_commit_sha,omitempty"`
}
Plugin represents a Claude Code plugin
func LoadClaudePlugins ¶
LoadClaudePlugins loads plugins from Claude's installed_plugins.json
func LoadClaudeProjectPlugins ¶
LoadClaudeProjectPlugins loads plugins from a project's local plugin config
func (*Plugin) InspectContent ¶
InspectContent returns the formatted content for the inspector viewport
func (*Plugin) InspectTitle ¶
InspectTitle returns the display name for the inspector modal header
type PluginScanner ¶
type PluginScanner interface {
Scanner
// ScanPlugins discovers plugins from the tool's local config
ScanPlugins(dir string) ([]*Plugin, error)
// ScanGlobalPlugins discovers plugins from the tool's global config
ScanGlobalPlugins() ([]*Plugin, error)
}
PluginScanner defines the interface for discovering plugins
type SafeReader ¶
type SafeReader struct {
MaxSize int64
}
SafeReader provides safe file reading with size limits to prevent memory exhaustion
func NewSafeReader ¶
func NewSafeReader() *SafeReader
NewSafeReader creates a new SafeReader with the default max size
type Scanner ¶
type Scanner interface {
// Name returns the scanner/tool name (e.g., "claude", "gemini")
Name() string
// Detect checks if the tool's configuration exists in the given directory
Detect(dir string) bool
// ScanRules discovers rules from the tool's config directory
ScanRules(dir string) ([]*rule.Rule, error)
// ScanSkills discovers skills from the tool's config directory
ScanSkills(dir string) ([]*skill.Skill, error)
// ScanHooks discovers hooks from the tool's settings
ScanHooks(dir string) ([]*hook.Hook, error)
// ScanCommands discovers commands (slash commands) from the tool's config
ScanCommands(dir string) ([]*command.Command, error)
// ScanServers discovers MCP servers from the tool's config
ScanServers(dir string) ([]*mcp.Server, error)
}
Scanner defines the interface for discovering resources from tool configurations
type ScannerConfig ¶
type ScannerConfig struct {
Name string // Scanner/tool name (e.g., "cursor")
LocalDirs []string // Tool directories relative to project (e.g., [".cursor"])
GlobalDirs []string // Global config directories (e.g., ["~/.cursor"])
DetectFiles []string // Files that indicate tool presence (e.g., [".cursorrules"])
RulesDirs []string // Subdirs containing rules (e.g., ["rules"])
SkillsDirs []string // Subdirs containing skills
CommandsDirs []string // Subdirs containing commands
AgentsDirs []string // Subdirs containing agents (e.g., ["agents"])
FileExts []string // Allowed file extensions (default: [".md", ".mdc"])
}
ScannerConfig defines the configuration for a DirectoryScanner. WARNING: Keep this struct frozen. The moment you add ValidationFunc, CustomDetectors, or IgnorePatterns, consider whether 5 simple files would be clearer. Config-driven is good; a DSL is not.