Documentation
¶
Overview ¶
Package agentx provides coding agent detection, hook management, and configuration.
agentx is a helper library for understanding how to extend the feature set of coding agents. It provides a unified interface for:
- Detecting which coding agent is currently running
- Understanding each agent's capabilities and configuration options
- Installing hooks and integrations for supported agents
- Managing agent-specific configuration paths (user and project level)
- Identifying context files each agent supports (CLAUDE.md, .cursorrules, etc.)
Supported agents: Claude Code, Cursor, Windsurf, GitHub Copilot, Aider, Cody, Continue, Code Puppy, Kiro, OpenCode, Goose, and Amp.
This package is designed to be standalone with no ox-specific dependencies, making it suitable for use by other tools that need coding agent integration.
Usage:
import (
"github.com/sageox/ox/pkg/agentx"
_ "github.com/sageox/ox/pkg/agentx/setup" // registers default agents
)
// Detect the current agent
if agentx.IsAgentContext() {
agent := agentx.CurrentAgent()
fmt.Printf("Running in %s\n", agent.Name())
fmt.Printf("Context files: %v\n", agent.ContextFiles())
}
Attribution ¶
This package is developed and maintained by SageOx (https://sageox.ai). If you use this package, please give credit to SageOx.
Index ¶
- Constants
- Variables
- func CompareVersions(a, b string) bool
- func ContentHash(content []byte) string
- func ExtractCommandHash(content []byte) string
- func ExtractStampVersion(content []byte) string
- func IsAgentContext() bool
- func IsCommandStale(existing []byte, cmd CommandFile) bool
- func RequireAgent(commandName string) string
- func ShouldWriteCommand(existing []byte, cmd CommandFile, overwrite bool) bool
- func StampedContent(content []byte, version string) []byte
- type Agent
- type AgentConfig
- type AgentDetector
- type AgentExtensions
- type AgentIdentity
- type AgentType
- type Capabilities
- type CommandFile
- type CommandManager
- type Detector
- type Environment
- type EventHooks
- type HookAction
- type HookConfig
- type HookEvent
- type HookManager
- type HookRule
- type MCPServerConfig
- type MockEnvironment
- func (e *MockEnvironment) CacheDir() (string, error)
- func (e *MockEnvironment) ConfigDir() (string, error)
- func (e *MockEnvironment) DataDir() (string, error)
- func (e *MockEnvironment) FileExists(path string) bool
- func (e *MockEnvironment) GOOS() string
- func (e *MockEnvironment) GetEnv(key string) string
- func (e *MockEnvironment) HomeDir() (string, error)
- func (e *MockEnvironment) IsDir(path string) bool
- func (e *MockEnvironment) LookPath(name string) (string, error)
- func (e *MockEnvironment) LookupEnv(key string) (string, bool)
- type Registry
- type SystemEnvironment
- func (e *SystemEnvironment) CacheDir() (string, error)
- func (e *SystemEnvironment) ConfigDir() (string, error)
- func (e *SystemEnvironment) DataDir() (string, error)
- func (e *SystemEnvironment) FileExists(path string) bool
- func (e *SystemEnvironment) GOOS() string
- func (e *SystemEnvironment) GetEnv(key string) string
- func (e *SystemEnvironment) HomeDir() (string, error)
- func (e *SystemEnvironment) IsDir(path string) bool
- func (e *SystemEnvironment) LookPath(name string) (string, error)
- func (e *SystemEnvironment) LookupEnv(key string) (string, bool)
Constants ¶
const CommandHashPrefix = "<!-- ox-hash: "
CommandHashPrefix is the marker used to stamp command files with a content hash and CLI version. Format: <!-- ox-hash: <hash> ver: <version> --> Files are only rewritten when content changes AND the writing version is >= installed.
Variables ¶
var DefaultRegistry = NewRegistry()
DefaultRegistry is the global registry with all supported agents.
var SupportedAgents = []AgentType{ AgentTypeClaudeCode, AgentTypeCursor, AgentTypeWindsurf, AgentTypeCopilot, AgentTypeAider, AgentTypeCody, AgentTypeContinue, AgentTypeCodePuppy, AgentTypeKiro, AgentTypeOpenCode, AgentTypeGoose, AgentTypeAmp, AgentTypeCline, AgentTypeDroid, }
SupportedAgents is the canonical list of coding agents that agentx supports. Use this when building agent-specific features or listing available agents.
Functions ¶
func CompareVersions ¶
CompareVersions returns true if version a is strictly older than version b. Uses simple semver comparison (major.minor.patch).
func ContentHash ¶
ContentHash returns the first 12 characters of the SHA-256 hex digest of content.
func ExtractCommandHash ¶
ExtractCommandHash extracts the content hash from a stamped command file. Returns empty string if no hash stamp is found.
func ExtractStampVersion ¶
ExtractStampVersion extracts the CLI version from a stamped command file. Returns empty string if no version is found in the stamp.
func IsAgentContext ¶
func IsAgentContext() bool
IsAgentContext returns true if running inside any coding agent. This is a convenience function using the default registry.
func IsCommandStale ¶
func IsCommandStale(existing []byte, cmd CommandFile) bool
IsCommandStale determines whether an installed command file is outdated compared to expected content. Returns false for user-managed files (no stamp) and files installed by a newer version (downgrade guard).
func RequireAgent ¶
RequireAgent returns an error message if not running in an agent context. Returns empty string if in agent context.
func ShouldWriteCommand ¶
func ShouldWriteCommand(existing []byte, cmd CommandFile, overwrite bool) bool
ShouldWriteCommand determines whether a command file should be written. existing is the current file content on disk (nil if the file doesn't exist). Returns true if the file should be written, false if it should be skipped.
Decision logic:
- File doesn't exist → write
- File exists + overwrite=false → skip
- File exists + no hash stamp → skip (user-managed)
- Hash matches → skip (content identical)
- Hash differs + installed version is newer → skip (downgrade guard)
- Otherwise → write
func StampedContent ¶
StampedContent returns the command content with a hash+version stamp prepended. Format: <!-- ox-hash: <12-char-hash> ver: <version> -->
Types ¶
type Agent ¶
type Agent interface {
AgentIdentity
AgentDetector
AgentConfig
AgentExtensions
}
Agent represents a coding agent with full detection and configuration capabilities. It embeds all focused interfaces for complete agent functionality.
When defining functions that work with agents, prefer using the narrowest interface that meets your needs:
- AgentIdentity: when you only need type, name, or URL
- AgentDetector: when you need to check if agent is running/installed
- AgentConfig: when you need configuration paths
- AgentExtensions: when you need hooks
- Agent: when you need full functionality or storage/registry
func CurrentAgent ¶
func CurrentAgent() Agent
CurrentAgent returns the currently detected agent, or nil if none.
type AgentConfig ¶
type AgentConfig interface {
// UserConfigPath returns the user-level configuration directory (e.g., ~/.claude)
UserConfigPath(env Environment) (string, error)
// ProjectConfigPath returns the project-level configuration directory (e.g., .claude/)
// Returns empty string if the agent doesn't support project-level config
ProjectConfigPath() string
// ContextFiles returns the list of context/instruction files this agent supports
// Examples: CLAUDE.md, AGENTS.md, .cursorrules, .windsurfrules
ContextFiles() []string
// SupportsXDGConfig returns true if the agent stores user config in XDG-compliant
// locations (~/.config/app/) rather than home directory dotfiles (~/.app/).
// XDG Base Directory Specification is the preferred standard for config locations.
// See: https://specifications.freedesktop.org/basedir-spec/latest/
SupportsXDGConfig() bool
}
AgentConfig provides configuration path information. Use this interface when you need to locate agent configuration files.
type AgentDetector ¶
type AgentDetector interface {
// Detect checks if this agent is currently running
Detect(ctx context.Context, env Environment) (bool, error)
// IsInstalled checks if this agent is installed on the system.
// Detection methods vary by agent: binary in PATH, config directory exists,
// application bundle present (macOS), etc.
IsInstalled(ctx context.Context, env Environment) (bool, error)
}
AgentDetector provides agent detection capabilities. Use this interface when you need to check if an agent is running or installed.
type AgentExtensions ¶
type AgentExtensions interface {
// Capabilities returns what features this agent supports
Capabilities() Capabilities
// HookManager returns the hook manager for this agent, or nil if hooks not supported
HookManager() HookManager
// CommandManager returns the command manager for this agent, or nil if custom commands not supported
CommandManager() CommandManager
}
AgentExtensions provides hook and command management capabilities. Use this interface when you need to work with agent extensions.
type AgentIdentity ¶
type AgentIdentity interface {
// Type returns the agent type slug
Type() AgentType
// Name returns the human-readable agent name
Name() string
// URL returns the official project URL (typically GitHub repo)
URL() string
}
AgentIdentity provides basic agent identification. Use this interface when you only need to identify an agent without needing detection or configuration capabilities.
type AgentType ¶
type AgentType string
AgentType identifies a coding agent
const ( AgentTypeUnknown AgentType = "" AgentTypeClaudeCode AgentType = "claude" AgentTypeCursor AgentType = "cursor" AgentTypeWindsurf AgentType = "windsurf" AgentTypeCopilot AgentType = "copilot" AgentTypeAider AgentType = "aider" AgentTypeCody AgentType = "cody" AgentTypeContinue AgentType = "continue" AgentTypeCodePuppy AgentType = "code-puppy" AgentTypeKiro AgentType = "kiro" AgentTypeOpenCode AgentType = "opencode" AgentTypeGoose AgentType = "goose" AgentTypeAmp AgentType = "amp" AgentTypeCline AgentType = "cline" AgentTypeDroid AgentType = "droid" AgentTypeCustom AgentType = "custom" )
type Capabilities ¶
type Capabilities struct {
// Hooks indicates the agent supports hook installation
Hooks bool
// MCPServers indicates the agent supports MCP server configuration
MCPServers bool
// SystemPrompt indicates the agent supports custom system instructions
SystemPrompt bool
// ProjectContext indicates the agent reads project context files (CLAUDE.md, etc.)
ProjectContext bool
// CustomCommands indicates the agent supports custom slash commands
CustomCommands bool
// MinVersion is the minimum agent version required for full feature support (future)
MinVersion string
}
Capabilities describes what features a coding agent supports. This allows tools to adapt their behavior based on agent capabilities.
type CommandFile ¶
type CommandFile struct {
// Name is the filename (e.g., "ox-status.md")
Name string
// Content is the file content (without stamp; stamp is added on write)
Content []byte
// Version is the ox version that ships this command.
// Used as a downgrade guard: an older binary won't overwrite commands
// installed by a newer binary.
Version string
}
CommandFile represents a custom slash command to install.
func ReadCommandFiles ¶
func ReadCommandFiles(fsys fs.FS, dir string) ([]CommandFile, error)
ReadCommandFiles reads .md files from an fs.FS directory into CommandFile slices. Useful for converting go:embed filesystems into CommandFile arrays for installation.
type CommandManager ¶
type CommandManager interface {
// Install writes command files to the agent's command directory.
// When overwrite is false, existing files are skipped entirely (safe for init).
// When overwrite is true, existing files are replaced only if content differs (safe for doctor).
// Returns the list of filenames that were written.
Install(ctx context.Context, projectRoot string, commands []CommandFile, overwrite bool) ([]string, error)
// Uninstall removes command files matching the prefix from the command directory.
// Returns the list of filenames that were removed.
Uninstall(ctx context.Context, projectRoot string, prefix string) ([]string, error)
// Validate checks which expected files are missing or stale in the command directory.
// Returns missing filenames and stale filenames (content differs from expected).
Validate(ctx context.Context, projectRoot string, commands []CommandFile) (missing []string, stale []string, err error)
// CommandDir returns the path to the command directory for a project.
CommandDir(projectRoot string) string
}
CommandManager handles custom slash command installation for agents.
type Detector ¶
type Detector interface {
// Detect identifies the active agent, returning nil if none detected
Detect(ctx context.Context) (Agent, error)
// DetectAll returns all detected agents (some may run simultaneously)
DetectAll(ctx context.Context) ([]Agent, error)
// DetectByType checks if a specific agent type is active
DetectByType(ctx context.Context, agentType AgentType) (bool, error)
}
Detector identifies which coding agent(s) are currently active.
func NewDetector ¶
func NewDetector() Detector
NewDetector creates a detector with the default registry.
func NewDetectorWithEnv ¶
func NewDetectorWithEnv(env Environment) Detector
NewDetectorWithEnv creates a detector with a custom environment.
type Environment ¶
type Environment interface {
// GetEnv retrieves an environment variable value
GetEnv(key string) string
// LookupEnv retrieves an environment variable and reports if it exists
LookupEnv(key string) (string, bool)
// HomeDir returns the user's home directory
HomeDir() (string, error)
// ConfigDir returns the XDG config directory
ConfigDir() (string, error)
// DataDir returns the XDG data directory
DataDir() (string, error)
// CacheDir returns the XDG cache directory
CacheDir() (string, error)
// GOOS returns the operating system name
GOOS() string
// LookPath searches for an executable in PATH
LookPath(name string) (string, error)
// FileExists checks if a file or directory exists
FileExists(path string) bool
// IsDir checks if a path is a directory
IsDir(path string) bool
}
Environment provides access to system environment for agent detection. This abstraction enables testing without real file system access.
func NewSystemEnvironment ¶
func NewSystemEnvironment() Environment
NewSystemEnvironment creates a new system environment.
type EventHooks ¶
EventHooks maps lifecycle events to their hook rules. This is the structure used in settings.json under the "hooks" key.
type HookAction ¶
type HookAction struct {
// Type is the action type. Currently only "command" is supported.
Type string `json:"type"`
// Command is the shell command to execute. Receives tool context via stdin as JSON.
// Exit code 2 from PreToolUse/PermissionRequest hooks denies the action.
Command string `json:"command"`
}
HookAction defines what happens when a hook triggers.
type HookConfig ¶
type HookConfig struct {
// SourcePath is the path to hook source files (templates, commands)
SourcePath string
// MCPServers are MCP server configurations to add
MCPServers map[string]MCPServerConfig
// SystemInstructions are custom instructions for the agent
SystemInstructions string
// EventHooks are lifecycle event hooks to install (PreToolUse, PostToolUse, etc.)
// See HookEvent constants for available events.
EventHooks EventHooks
// Merge indicates whether to merge with existing config (true) or replace (false)
Merge bool
}
HookConfig represents hook configuration for installation.
type HookEvent ¶
type HookEvent string
HookEvent represents a coding agent lifecycle event that can trigger hooks. These events allow tools to intercept and respond to agent actions.
Reference: https://code.claude.com/docs/en/hooks-guide
const ( // HookEventPreToolUse fires before a tool executes. Hooks can block or modify the call. HookEventPreToolUse HookEvent = "PreToolUse" // HookEventPostToolUse fires after a tool completes. Useful for validation or formatting. HookEventPostToolUse HookEvent = "PostToolUse" // HookEventUserPromptSubmit fires when a user submits a prompt. HookEventUserPromptSubmit HookEvent = "UserPromptSubmit" // HookEventPermissionRequest fires when the agent requests permission for an action. // Hooks can allow, deny, or prompt. Available in Claude Code v2.0.45+. HookEventPermissionRequest HookEvent = "PermissionRequest" // HookEventStop fires when the agent finishes responding. HookEventStop HookEvent = "Stop" // HookEventSubagentStop fires when a subagent completes. Available in Claude Code v1.0.41+. HookEventSubagentStop HookEvent = "SubagentStop" // HookEventSessionEnd fires when the agent session terminates. HookEventSessionEnd HookEvent = "SessionEnd" )
type HookManager ¶
type HookManager interface {
// Install installs hooks for the agent
Install(ctx context.Context, config HookConfig) error
// Uninstall removes installed hooks
Uninstall(ctx context.Context) error
// IsInstalled checks if hooks are installed
IsInstalled(ctx context.Context) (bool, error)
// Validate validates the current hook configuration
Validate(ctx context.Context) error
}
HookManager handles hook installation and management for an agent.
type HookRule ¶
type HookRule struct {
// Matcher is a tool name pattern (e.g., "Bash", "Edit|Write", "*" for all).
// Only applies to PreToolUse, PostToolUse, and PermissionRequest events.
Matcher string `json:"matcher,omitempty"`
// Hooks are the actions to execute when this rule matches.
Hooks []HookAction `json:"hooks"`
}
HookRule defines when and how a hook triggers. Rules use matchers to filter which tools activate the hook.
type MCPServerConfig ¶
type MCPServerConfig struct {
Command string `json:"command"`
Args []string `json:"args,omitempty"`
Env map[string]string `json:"env,omitempty"`
}
MCPServerConfig represents an MCP server configuration.
type MockEnvironment ¶
type MockEnvironment struct {
EnvVars map[string]string
Home string
Config string
Data string
Cache string
OS string
HomeError error
}
MockEnvironment is a test implementation of Environment.
func NewMockEnvironment ¶
func NewMockEnvironment(envVars map[string]string) *MockEnvironment
NewMockEnvironment creates a mock environment for testing.
func (*MockEnvironment) CacheDir ¶
func (e *MockEnvironment) CacheDir() (string, error)
func (*MockEnvironment) ConfigDir ¶
func (e *MockEnvironment) ConfigDir() (string, error)
func (*MockEnvironment) DataDir ¶
func (e *MockEnvironment) DataDir() (string, error)
func (*MockEnvironment) FileExists ¶
func (e *MockEnvironment) FileExists(path string) bool
func (*MockEnvironment) GOOS ¶
func (e *MockEnvironment) GOOS() string
func (*MockEnvironment) GetEnv ¶
func (e *MockEnvironment) GetEnv(key string) string
func (*MockEnvironment) HomeDir ¶
func (e *MockEnvironment) HomeDir() (string, error)
func (*MockEnvironment) IsDir ¶
func (e *MockEnvironment) IsDir(path string) bool
type Registry ¶
type Registry interface {
// Register adds an agent to the registry
Register(agent Agent) error
// Get retrieves an agent by type
Get(agentType AgentType) (Agent, bool)
// List returns all registered agents
List() []Agent
// Detector returns a detector for registered agents
Detector() Detector
}
Registry manages available agents and provides detection.
type SystemEnvironment ¶
type SystemEnvironment struct{}
SystemEnvironment implements Environment using the real system.
func (*SystemEnvironment) CacheDir ¶
func (e *SystemEnvironment) CacheDir() (string, error)
func (*SystemEnvironment) ConfigDir ¶
func (e *SystemEnvironment) ConfigDir() (string, error)
func (*SystemEnvironment) DataDir ¶
func (e *SystemEnvironment) DataDir() (string, error)
func (*SystemEnvironment) FileExists ¶
func (e *SystemEnvironment) FileExists(path string) bool
func (*SystemEnvironment) GOOS ¶
func (e *SystemEnvironment) GOOS() string
func (*SystemEnvironment) GetEnv ¶
func (e *SystemEnvironment) GetEnv(key string) string
func (*SystemEnvironment) HomeDir ¶
func (e *SystemEnvironment) HomeDir() (string, error)
func (*SystemEnvironment) IsDir ¶
func (e *SystemEnvironment) IsDir(path string) bool
Directories
¶
| Path | Synopsis |
|---|---|
|
Package config provides configuration path resolution for agentx.
|
Package config provides configuration path resolution for agentx. |
|
Package hooks provides hook management for coding agents.
|
Package hooks provides hook management for coding agents. |
|
Package setup provides initialization for the agentx package.
|
Package setup provides initialization for the agentx package. |