Documentation
¶
Index ¶
- Variables
- func AdapterDirs() []string
- func CanonicalAdapterName(name string) string
- func ListAdapters() []string
- func Register(adapter Adapter)
- func RegisterExternalAdapters() error
- func ResetRegistry()
- func SanitizedEnv(environ []string, requiredEnv []string) []string
- func Unregister(name string)
- type Adapter
- type BatchTransformFunc
- type ExternalAdapter
- func (ea *ExternalAdapter) BinaryPath() string
- func (ea *ExternalAdapter) CapturePrior(params adapterprotocol.CapturePriorParams) (*adapterprotocol.CapturePriorResult, error)
- func (ea *ExternalAdapter) CheckCommands(repoRoot, version string) (*adapterprotocol.CheckCommandsResponse, error)
- func (ea *ExternalAdapter) CheckHooks(repoRoot, scope string) (*adapterprotocol.CheckHooksResponse, error)
- func (ea *ExternalAdapter) CheckRules(repoRoot, version string) (*adapterprotocol.CheckRulesResponse, error)
- func (ea *ExternalAdapter) Close() error
- func (ea *ExternalAdapter) Detect() bool
- func (ea *ExternalAdapter) Diagnose(repoRoot, scope, version string) (*adapterprotocol.DiagnoseResult, error)
- func (ea *ExternalAdapter) FindSessionFile(lookup SessionLookup) (string, error)
- func (ea *ExternalAdapter) HasCapability(cap string) bool
- func (ea *ExternalAdapter) ImportSession(sessionID, repoRoot string) (*adapterprotocol.ImportSessionResult, error)
- func (ea *ExternalAdapter) Info() *adapterprotocol.InfoResponse
- func (ea *ExternalAdapter) InstallCommands(repoRoot, version string) (*adapterprotocol.InstallCommandsResponse, error)
- func (ea *ExternalAdapter) InstallHooks(repoRoot, scope string) (*adapterprotocol.InstallHooksResponse, error)
- func (ea *ExternalAdapter) InstallRules(repoRoot, version string) (*adapterprotocol.InstallRulesResponse, error)
- func (ea *ExternalAdapter) Name() string
- func (ea *ExternalAdapter) Read(sessionPath string) ([]RawEntry, error)
- func (ea *ExternalAdapter) ReadFromOffset(path string, offset int64) ([]RawEntry, int64, error)
- func (ea *ExternalAdapter) ReadMetadata(sessionPath string) (*SessionMetadata, error)
- func (ea *ExternalAdapter) UninstallCommands(repoRoot, version string) (*adapterprotocol.UninstallCommandsResponse, error)
- func (ea *ExternalAdapter) UninstallHooks(repoRoot, scope string) (*adapterprotocol.UninstallHooksResponse, error)
- func (ea *ExternalAdapter) UninstallRules(repoRoot, version string) (*adapterprotocol.UninstallRulesResponse, error)
- func (ea *ExternalAdapter) Watch(ctx context.Context, sessionPath string) (<-chan RawEntry, error)
- type ExternalAdapterInfo
- type GenericJSONLAdapter
- func (a *GenericJSONLAdapter) Detect() bool
- func (a *GenericJSONLAdapter) FindSessionFile(_ SessionLookup) (string, error)
- func (a *GenericJSONLAdapter) Name() string
- func (a *GenericJSONLAdapter) Read(sessionPath string) ([]RawEntry, error)
- func (a *GenericJSONLAdapter) ReadMetadata(sessionPath string) (*SessionMetadata, error)
- func (a *GenericJSONLAdapter) Watch(_ context.Context, _ string) (<-chan RawEntry, error)
- type IncrementalReader
- type ParseLineFunc
- type RawEntry
- type SessionLookup
- type SessionMetadata
- type TailWatcher
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNoAdapterDetected is returned when no adapter can handle the current environment ErrNoAdapterDetected = errors.New("no adapter detected for current environment") // ErrAdapterNotFound is returned when a specific adapter is not registered ErrAdapterNotFound = errors.New("adapter not found") // ErrSessionNotFound is returned when a session file cannot be located ErrSessionNotFound = errors.New("session file not found") // ErrWatchNotSupported is returned when an adapter does not support real-time watching ErrWatchNotSupported = errors.New("watch not supported for this adapter") )
var ( // ErrAdapterTimeout is returned when an adapter binary does not respond within the timeout. ErrAdapterTimeout = errors.New("adapter timed out") // ErrAdapterCrashed is returned when an adapter process exits unexpectedly. ErrAdapterCrashed = errors.New("adapter process crashed") // ErrInvalidResponse is returned when an adapter produces invalid JSON. ErrInvalidResponse = errors.New("adapter returned invalid response") // ErrProtocolMismatch is returned when an adapter's protocol version is incompatible. ErrProtocolMismatch = errors.New("adapter protocol version mismatch") )
Functions ¶
func AdapterDirs ¶ added in v0.6.2
func AdapterDirs() []string
AdapterDirs returns the ordered list of directories to scan for adapter binaries. Priority: OX_ADAPTER_PATH (highest), bundled dir, user local dir.
func CanonicalAdapterName ¶ added in v0.6.2
CanonicalAdapterName returns the canonical adapter name for a given name or alias. If the name is already canonical or unknown, it is returned as-is.
func ListAdapters ¶
func ListAdapters() []string
ListAdapters returns the names of all registered adapters
func Register ¶
func Register(adapter Adapter)
Register adds an adapter to the registry Panics if an adapter with the same name is already registered
func RegisterExternalAdapters ¶ added in v0.6.2
func RegisterExternalAdapters() error
RegisterExternalAdapters discovers and registers external adapters. External adapters with the same name as a built-in adapter take priority: the built-in is unregistered and the external adapter replaces it. This allows users to override built-in parsing logic by dropping a newer adapter binary into a controlled directory (see ADR-006 for allowed paths).
Safe to call multiple times — rediscovery is idempotent since the same binary produces the same adapter name.
func ResetRegistry ¶
func ResetRegistry()
ResetRegistry clears all registered adapters (for testing only)
func SanitizedEnv ¶ added in v0.6.2
SanitizedEnv builds a sanitized environment for adapter subprocess execution. It filters environ (typically os.Environ()) to only include:
- Exact-match allowlisted vars: HOME, PATH, TMPDIR
- Prefix-match allowlisted vars: XDG_*
- OX_* protocol vars (OX_PROTOCOL_VERSION, OX_REPO_ROOT, OX_REPO_ID, OX_TEAM_ID)
- Any additional vars declared in the adapter's required_env list
All other variables (API keys, tokens, secrets) are stripped.
func Unregister ¶ added in v0.6.2
func Unregister(name string)
Unregister removes a specific adapter from the registry by name. Prefer this over ResetRegistry() in tests to avoid clearing other adapters.
Types ¶
type Adapter ¶
type Adapter interface {
// Name returns the adapter name (e.g., "claude-code")
Name() string
// Detect checks if this adapter can handle the current environment
// Returns true if the agent's session files are present and readable
Detect() bool
// FindSessionFile locates the session file for correlation.
// Called after ox agent prime to find the matching agent session.
// The lookup struct carries all needed context (repoRoot, agentID, since)
// so the adapter never needs to derive repoRoot from ambient state.
FindSessionFile(lookup SessionLookup) (string, error)
// Read reads all entries from a session file
// Returns entries in chronological order
Read(sessionPath string) ([]RawEntry, error)
// ReadMetadata extracts session metadata (agent version, model) from a session file.
// Returns nil if metadata cannot be determined.
ReadMetadata(sessionPath string) (*SessionMetadata, error)
// Watch monitors a session file for new entries (for real-time capture)
// The returned channel receives entries as they appear
// The channel is closed when ctx is canceled or an error occurs
Watch(ctx context.Context, sessionPath string) (<-chan RawEntry, error)
}
Adapter reads conversation data from a coding agent's session files
func DetectAdapter ¶
DetectAdapter finds the appropriate adapter for the current environment. First checks registered (built-in) adapters, then falls through to external adapter discovery if no registered adapter matches. Returns ErrNoAdapterDetected if no adapter can handle the environment.
func GetAdapter ¶
GetAdapter returns a specific adapter by name. Accepts canonical names ("claude-code"), display names ("Claude Code"), and shorthand ("claude"). Case-insensitive for aliases. Falls through to external adapter discovery if not found in registry. Returns ErrAdapterNotFound if no adapter with that name is registered.
type BatchTransformFunc ¶ added in v0.6.1
BatchTransformFunc post-processes a batch of entries before they are sent through the Watch channel. Used by adapters that need cross-entry correlation (e.g. Codex merges function_call + function_call_output by CallID).
type ExternalAdapter ¶ added in v0.6.2
type ExternalAdapter struct {
// contains filtered or unexported fields
}
ExternalAdapter implements Adapter and IncrementalReader by calling an external adapter binary via subprocess (one-shot) or serve-mode pipe.
func DiscoverExternalAdapters ¶ added in v0.6.2
func DiscoverExternalAdapters() []*ExternalAdapter
DiscoverExternalAdapters scans known directories for ox-adapter-* binaries, calls info on each, and returns successfully discovered adapters.
The returned adapters are not yet registered. The caller decides whether to register them (and whether they supersede built-in adapters).
func NewExternalAdapter ¶ added in v0.6.2
func NewExternalAdapter(binaryPath string) (*ExternalAdapter, error)
NewExternalAdapter creates an ExternalAdapter wrapping the binary at the given path. It calls `info` to populate adapter metadata.
func NewExternalAdapterWithInfo ¶ added in v0.6.2
func NewExternalAdapterWithInfo(binaryPath string, info *adapterprotocol.InfoResponse) *ExternalAdapter
NewExternalAdapterWithInfo creates an ExternalAdapter with pre-populated info. Used when info has already been called (e.g., during discovery).
func (*ExternalAdapter) BinaryPath ¶ added in v0.6.2
func (ea *ExternalAdapter) BinaryPath() string
BinaryPath returns the path to the adapter binary.
func (*ExternalAdapter) CapturePrior ¶ added in v0.6.2
func (ea *ExternalAdapter) CapturePrior(params adapterprotocol.CapturePriorParams) (*adapterprotocol.CapturePriorResult, error)
CapturePrior delegates session capture to the adapter, which owns the agent-specific session discovery and parsing logic.
func (*ExternalAdapter) CheckCommands ¶ added in v0.6.4
func (ea *ExternalAdapter) CheckCommands(repoRoot, version string) (*adapterprotocol.CheckCommandsResponse, error)
CheckCommands calls the adapter's check-commands subcommand.
func (*ExternalAdapter) CheckHooks ¶ added in v0.6.2
func (ea *ExternalAdapter) CheckHooks(repoRoot, scope string) (*adapterprotocol.CheckHooksResponse, error)
CheckHooks calls the adapter's check-hooks subcommand.
func (*ExternalAdapter) CheckRules ¶ added in v0.6.2
func (ea *ExternalAdapter) CheckRules(repoRoot, version string) (*adapterprotocol.CheckRulesResponse, error)
CheckRules calls the adapter's check-rules subcommand.
func (*ExternalAdapter) Close ¶ added in v0.6.2
func (ea *ExternalAdapter) Close() error
Close shuts down any serve-mode process.
func (*ExternalAdapter) Detect ¶ added in v0.6.2
func (ea *ExternalAdapter) Detect() bool
Detect calls the adapter's detect subcommand.
func (*ExternalAdapter) Diagnose ¶ added in v0.6.2
func (ea *ExternalAdapter) Diagnose(repoRoot, scope, version string) (*adapterprotocol.DiagnoseResult, error)
Diagnose calls the adapter's diagnose subcommand.
func (*ExternalAdapter) FindSessionFile ¶ added in v0.6.2
func (ea *ExternalAdapter) FindSessionFile(lookup SessionLookup) (string, error)
FindSessionFile calls find-session via one-shot mode. The lookup.RepoRoot is passed directly to the adapter subprocess; no ambient state (env/cwd) is consulted.
func (*ExternalAdapter) HasCapability ¶ added in v0.6.2
func (ea *ExternalAdapter) HasCapability(cap string) bool
hasCapability checks if the adapter declares a specific capability. HasCapability returns true if the adapter reports the given capability.
func (*ExternalAdapter) ImportSession ¶ added in v0.6.2
func (ea *ExternalAdapter) ImportSession(sessionID, repoRoot string) (*adapterprotocol.ImportSessionResult, error)
ImportSession reads an entire session by its native session ID.
func (*ExternalAdapter) Info ¶ added in v0.6.2
func (ea *ExternalAdapter) Info() *adapterprotocol.InfoResponse
Info returns the cached adapter info.
func (*ExternalAdapter) InstallCommands ¶ added in v0.6.4
func (ea *ExternalAdapter) InstallCommands(repoRoot, version string) (*adapterprotocol.InstallCommandsResponse, error)
InstallCommands calls the adapter's install-commands subcommand.
func (*ExternalAdapter) InstallHooks ¶ added in v0.6.2
func (ea *ExternalAdapter) InstallHooks(repoRoot, scope string) (*adapterprotocol.InstallHooksResponse, error)
InstallHooks calls the adapter's install-hooks subcommand.
func (*ExternalAdapter) InstallRules ¶ added in v0.6.2
func (ea *ExternalAdapter) InstallRules(repoRoot, version string) (*adapterprotocol.InstallRulesResponse, error)
InstallRules calls the adapter's install-rules subcommand.
func (*ExternalAdapter) Name ¶ added in v0.6.2
func (ea *ExternalAdapter) Name() string
Name returns the adapter name from the info response.
func (*ExternalAdapter) Read ¶ added in v0.6.2
func (ea *ExternalAdapter) Read(sessionPath string) ([]RawEntry, error)
Read calls the adapter's read subcommand.
func (*ExternalAdapter) ReadFromOffset ¶ added in v0.6.2
ReadFromOffset implements IncrementalReader via one-shot subprocess call.
func (*ExternalAdapter) ReadMetadata ¶ added in v0.6.2
func (ea *ExternalAdapter) ReadMetadata(sessionPath string) (*SessionMetadata, error)
ReadMetadata calls the adapter's read-metadata subcommand.
func (*ExternalAdapter) UninstallCommands ¶ added in v0.6.4
func (ea *ExternalAdapter) UninstallCommands(repoRoot, version string) (*adapterprotocol.UninstallCommandsResponse, error)
UninstallCommands calls the adapter's uninstall-commands subcommand.
func (*ExternalAdapter) UninstallHooks ¶ added in v0.6.2
func (ea *ExternalAdapter) UninstallHooks(repoRoot, scope string) (*adapterprotocol.UninstallHooksResponse, error)
UninstallHooks calls the adapter's uninstall-hooks subcommand.
func (*ExternalAdapter) UninstallRules ¶ added in v0.6.2
func (ea *ExternalAdapter) UninstallRules(repoRoot, version string) (*adapterprotocol.UninstallRulesResponse, error)
UninstallRules calls the adapter's uninstall-rules subcommand.
type ExternalAdapterInfo ¶ added in v0.6.2
type ExternalAdapterInfo struct {
Name string `json:"name"`
DisplayName string `json:"display_name"`
Version string `json:"version"`
Type string `json:"type"`
BinaryPath string `json:"binary_path"`
ProtocolVersion int `json:"protocol_version"`
Capabilities []string `json:"capabilities"`
ServeMode bool `json:"serve_mode"`
}
ExternalAdapterInfo is a summary of a discovered external adapter.
func ListExternalAdapters ¶ added in v0.6.2
func ListExternalAdapters() []ExternalAdapterInfo
ListExternalAdapters returns info about all discovered external adapters without registering them. Useful for `ox adapter list`.
func (ExternalAdapterInfo) String ¶ added in v0.6.2
func (i ExternalAdapterInfo) String() string
String implements fmt.Stringer.
type GenericJSONLAdapter ¶ added in v0.3.0
type GenericJSONLAdapter struct{}
GenericJSONLAdapter reads SageOx-compatible JSONL from a file that any coding agent writes to. Unlike the Claude Code adapter which reads agent-native files, this adapter reads a standardized format that agents write to via `ox agent session log` or direct JSONL writes.
func (*GenericJSONLAdapter) Detect ¶ added in v0.3.0
func (a *GenericJSONLAdapter) Detect() bool
Detect always returns false. The generic adapter is never auto-detected -- it is used via explicit GetAdapter() or alias resolution. Deep adapters (e.g. Claude Code) take priority via DetectAdapter().
func (*GenericJSONLAdapter) FindSessionFile ¶ added in v0.3.0
func (a *GenericJSONLAdapter) FindSessionFile(_ SessionLookup) (string, error)
FindSessionFile is not supported by the generic adapter. The session file path is created by session start and passed through recording state.
func (*GenericJSONLAdapter) Name ¶ added in v0.3.0
func (a *GenericJSONLAdapter) Name() string
Name returns the adapter identifier.
func (*GenericJSONLAdapter) Read ¶ added in v0.3.0
func (a *GenericJSONLAdapter) Read(sessionPath string) ([]RawEntry, error)
Read parses all entries from a SageOx-compatible JSONL session file. It streams line-by-line, skipping header/footer lines and malformed JSON. Empty files return an empty slice (not an error).
func (*GenericJSONLAdapter) ReadMetadata ¶ added in v0.3.0
func (a *GenericJSONLAdapter) ReadMetadata(sessionPath string) (*SessionMetadata, error)
ReadMetadata extracts session metadata from the first line of a JSONL file. If the first line is a header with a metadata object, agent_version and model are extracted. Returns nil if no header or the fields are missing.
type IncrementalReader ¶ added in v0.5.0
type IncrementalReader interface {
ReadFromOffset(path string, offset int64) ([]RawEntry, int64, error)
}
IncrementalReader is an optional interface for adapters that support offset-based incremental reading (used by hook-driven recording).
type ParseLineFunc ¶ added in v0.6.1
ParseLineFunc converts a raw JSONL line into zero or more RawEntries. Each adapter provides its own implementation.
type RawEntry ¶
type RawEntry struct {
// Timestamp when this entry was created
Timestamp time.Time
// Role identifies the speaker: "user", "assistant", "system", "tool"
Role string
// Content is the message text or tool output
Content string
// ToolName is the name of the tool invoked (only for role="tool")
ToolName string
// ToolInput is the input provided to the tool (only for role="tool")
ToolInput string
// ToolOutput is the output from the tool (only for role="tool").
// Only populated for error results to keep recordings lean.
ToolOutput string
// IsError indicates the tool call failed (only for role="tool")
IsError bool
// CallID correlates function_call with function_call_output (adapter-specific)
CallID string
// Raw contains the original data for debugging and auditing
Raw json.RawMessage
}
RawEntry represents a conversation turn from any agent
type SessionLookup ¶ added in v0.6.2
type SessionLookup struct {
RepoRoot string // absolute path to the project root (required, validated)
AgentID string // agent identifier (required)
Since time.Time // filter to sessions created after this time (required)
AgentSessionID string // adapter-native session UUID if known (optional)
}
SessionLookup contains all parameters needed to locate an agent's session file. Constructed from RecordingState at stop/hook time, or from command context at start time. Replaces the old (agentID, since) signature that forced ambient repoRoot lookup.
func (SessionLookup) Validate ¶ added in v0.6.2
func (sl SessionLookup) Validate() error
Validate checks that SessionLookup fields are well-formed. RepoRoot must be absolute and contain a .sageox/ directory. Delegates path validation to adapterruntime.ValidateRepoRoot (single implementation, includes 500ms stat timeout for NFS resilience).
type SessionMetadata ¶
type SessionMetadata struct {
// AgentVersion is the version of the coding agent (e.g., "1.0.3" for Claude Code)
AgentVersion string
// Model is the LLM model used (e.g., "claude-sonnet-4-20250514")
Model string
}
SessionMetadata contains metadata extracted from agent session files. This captures which agent and model were used for the session.
type TailWatcher ¶ added in v0.6.1
type TailWatcher struct {
// contains filtered or unexported fields
}
TailWatcher provides file-tailing with fsnotify, debounce, and offset tracking. Used by daemon for hookless agents and by adapter Watch() methods. The caller provides a parseLine function; TailWatcher handles file I/O plumbing.
func NewTailWatcher ¶ added in v0.6.1
func NewTailWatcher(path string, offset int64, parseLine ParseLineFunc) *TailWatcher
NewTailWatcher creates a TailWatcher that tails the given file starting at offset. parseLine converts each JSONL line into adapter-specific RawEntries.
func (*TailWatcher) Offset ¶ added in v0.6.1
func (tw *TailWatcher) Offset() int64
Offset returns the current read position.
func (*TailWatcher) ReadFromOffset ¶ added in v0.6.1
func (tw *TailWatcher) ReadFromOffset(offset int64) ([]RawEntry, int64, error)
ReadFromOffset reads new entries starting at the given byte offset, applying batchTransform if set. Returns entries and the new offset position.
func (*TailWatcher) Watch ¶ added in v0.6.1
func (tw *TailWatcher) Watch(ctx context.Context) (<-chan RawEntry, error)
Watch starts tailing the file and sends new entries to the returned channel. The channel is closed when ctx is canceled or the watcher encounters an error.
func (*TailWatcher) WithBatchTransform ¶ added in v0.6.1
func (tw *TailWatcher) WithBatchTransform(fn BatchTransformFunc) *TailWatcher
WithBatchTransform sets a post-processing function applied to each batch of entries before they are sent through the Watch channel or returned by ReadFromOffset. Returns the TailWatcher for chaining.