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 OrchestratorType() string
- 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 AgentRole
- 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) Exec(ctx context.Context, name string, args ...string) ([]byte, 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)
- func (e *MockEnvironment) ReadFile(path string) ([]byte, error)
- 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) Exec(ctx context.Context, name string, args ...string) ([]byte, 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)
- func (e *SystemEnvironment) ReadFile(path string) ([]byte, error)
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, AgentTypeOpenClaw, AgentTypeConductor, }
SupportedAgents is the canonical list of coding agents and orchestrators that agentx supports.
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 OrchestratorType ¶ added in v0.2.0
func OrchestratorType() string
OrchestratorType returns the type string of the detected orchestrator, or empty string if none detected.
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 coding agent, or nil if none.
func CurrentOrchestrator ¶ added in v0.2.0
func CurrentOrchestrator() Agent
CurrentOrchestrator returns the currently detected orchestrator, 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)
// DetectVersion attempts to determine the installed version of this agent.
// Returns empty string if version cannot be determined (best-effort).
// Strategies vary by agent: CLI --version, reading package.json, etc.
DetectVersion(ctx context.Context, env Environment) string
}
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
// Role returns whether this is a coding agent or an orchestrator
Role() AgentRole
}
AgentIdentity provides basic agent identification. Use this interface when you only need to identify an agent without needing detection or configuration capabilities.
type AgentRole ¶ added in v0.2.0
type AgentRole string
AgentRole distinguishes agents from orchestrators. Agents are coding tools (Claude Code, Cursor); orchestrators launch and manage agents (OpenClaw, Conductor, Gas Town).
type AgentType ¶
type AgentType string
AgentType identifies a coding agent or orchestrator.
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" // Orchestrators AgentTypeOpenClaw AgentType = "openclaw" AgentTypeConductor AgentType = "conductor" )
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 coding agent (RoleAgent), returning nil if none detected.
// Orchestrators are excluded — use DetectOrchestrator for those.
Detect(ctx context.Context) (Agent, error)
// DetectOrchestrator returns the active orchestrator (RoleOrchestrator), or nil.
// This is independent of Detect() which returns the coding agent.
DetectOrchestrator(ctx context.Context) (Agent, error)
// DetectAll returns all detected agents and orchestrators
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) and orchestrator(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
// Exec runs a command and returns its stdout output.
// Returns error if the command fails or is not found.
Exec(ctx context.Context, name string, args ...string) ([]byte, error)
// ReadFile reads a file and returns its contents.
ReadFile(path string) ([]byte, error)
}
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
ExecOutputs map[string][]byte // keyed by command name
ExecErrors map[string]error // keyed by command name
Files map[string][]byte // keyed by file path
PathBinaries map[string]string // keyed by binary name → path
ExistingFiles map[string]bool // keyed by path
ExistingDirs map[string]bool // keyed by path
}
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
func (*SystemEnvironment) LookPath ¶
func (e *SystemEnvironment) LookPath(name string) (string, error)
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. |