Documentation
¶
Overview ¶
Package agent provides interfaces and types for integrating with coding agents. It abstracts agent-specific behavior (hooks, log parsing, session storage) so that the same Strategy implementations can work with any coding agent.
Index ¶
- Constants
- func ChunkFileName(baseName string, index int) string
- func ChunkJSONL(content []byte, maxSize int) ([][]byte, error)
- func ChunkTranscript(content []byte, agentType AgentType) ([][]byte, error)
- func ParseChunkIndex(filename, baseName string) int
- func ReassembleJSONL(chunks [][]byte) []byte
- func ReassembleTranscript(chunks [][]byte, agentType AgentType) ([]byte, error)
- func Register(name AgentName, factory Factory)
- func SortChunkFiles(files []string, baseName string) []string
- type Agent
- type AgentName
- type AgentSession
- type AgentType
- type EntryType
- type Factory
- type FileWatcher
- type HookHandler
- type HookInput
- type HookSupport
- type HookType
- type SessionChange
- type SessionEntry
- type TokenUsage
- type TranscriptAnalyzer
- type TranscriptChunker
Constants ¶
const ( // MaxChunkSize is the maximum size for a single transcript chunk. // GitHub has a 100MB limit per blob, so we use 50MB to be safe. MaxChunkSize = 50 * 1024 * 1024 // 50MB // ChunkSuffix is the format for chunk file suffixes (e.g., ".001", ".002") ChunkSuffix = ".%03d" )
Variables ¶
This section is empty.
Functions ¶
func ChunkFileName ¶
ChunkFileName returns the filename for a chunk at the given index. Index 0 returns the base filename, index 1+ returns with chunk suffix.
func ChunkJSONL ¶
ChunkJSONL splits JSONL content at line boundaries. This is the default chunking for agents using JSONL format (like Claude Code).
func ChunkTranscript ¶
ChunkTranscript splits a transcript into chunks using the appropriate agent. If agentType is empty or the agent doesn't implement TranscriptChunker, falls back to JSONL (line-based) chunking.
func ParseChunkIndex ¶
ParseChunkIndex extracts the chunk index from a filename. Returns 0 for the base file (no suffix), or the chunk number for suffixed files. Returns -1 if the filename doesn't match the expected pattern.
func ReassembleJSONL ¶
ReassembleJSONL concatenates JSONL chunks with newlines.
func ReassembleTranscript ¶
ReassembleTranscript combines chunks back into a single transcript. If agentType is empty or the agent doesn't implement TranscriptChunker, falls back to JSONL (line-based) reassembly.
func Register ¶
Register adds an agent factory to the registry. Called from init() in each agent implementation.
func SortChunkFiles ¶
SortChunkFiles sorts chunk filenames in order (base file first, then numbered chunks).
Types ¶
type Agent ¶
type Agent interface {
// Name returns the agent registry key (e.g., "claude-code", "gemini")
Name() AgentName
// Type returns the agent type identifier (e.g., "Claude Code", "Gemini CLI")
// This is stored in metadata and trailers.
Type() AgentType
// Description returns a human-readable description for UI
Description() string
// DetectPresence checks if this agent is configured in the repository
DetectPresence() (bool, error)
// GetHookConfigPath returns path to hook config file (empty if none)
GetHookConfigPath() string
// SupportsHooks returns true if agent supports lifecycle hooks
SupportsHooks() bool
// ParseHookInput parses hook callback input from stdin
ParseHookInput(hookType HookType, reader io.Reader) (*HookInput, error)
// GetSessionID extracts session ID from hook input
GetSessionID(input *HookInput) string
// TransformSessionID converts agent session ID to Entire session ID
TransformSessionID(agentSessionID string) string
// ExtractAgentSessionID extracts agent session ID from Entire ID
ExtractAgentSessionID(entireSessionID string) string
// GetSessionDir returns where agent stores session data for this repo.
// Examples:
// Claude: ~/.claude/projects/<sanitized-repo-path>/
// Aider: current working directory (returns repoPath)
// Cursor: ~/Library/Application Support/Cursor/User/globalStorage/
GetSessionDir(repoPath string) (string, error)
// ReadSession reads session data from agent's storage.
// Handles different formats: JSONL (Claude), SQLite (Cursor), Markdown (Aider)
ReadSession(input *HookInput) (*AgentSession, error)
// WriteSession writes session data for resumption.
// Agent handles format conversion (JSONL, SQLite, etc.)
WriteSession(session *AgentSession) error
// FormatResumeCommand returns command to resume a session
FormatResumeCommand(sessionID string) string
}
Agent defines the interface for interacting with a coding agent. Each agent implementation (Claude Code, Cursor, Aider, etc.) converts its native format to the normalized types defined in this package.
func Default ¶
func Default() Agent
Default returns the default agent. Returns nil if the default agent is not registered.
func GetByAgentType ¶
GetByAgentType retrieves an agent by its type identifier.
Note: This uses a linear search that instantiates agents until a match is found. This is acceptable because:
- Agent count is small (~2-20 agents)
- Agent factories are lightweight (empty struct allocation)
- Called infrequently (commit hooks, rewind, debug commands - not hot paths)
- Cost is ~400ns worst case vs milliseconds for I/O operations
Only optimize if agent count exceeds 100 or profiling shows this as a bottleneck.
type AgentName ¶
type AgentName string
AgentName is the registry key type for agents (e.g., "claude-code", "gemini").
Agent name constants (registry keys)
const DefaultAgentName AgentName = AgentNameClaudeCode
DefaultAgentName is the registry key for the default agent.
type AgentSession ¶
type AgentSession struct {
SessionID string
AgentName AgentName
RepoPath string
SessionRef string // Path/reference to session in agent's storage
StartTime time.Time
// NativeData holds the session content in the agent's native format.
// Only the originating agent can interpret this data.
// Examples:
// - Claude Code: raw JSONL bytes
// - Cursor: serialized SQLite rows
// - Aider: Markdown content
NativeData []byte
// Computed fields - populated by the agent when reading
ModifiedFiles []string
NewFiles []string
DeletedFiles []string
// Optional normalized entries - agents may populate this if needed
// for operations that benefit from structured access
Entries []SessionEntry
}
AgentSession represents a coding session's data. Each agent stores data in its native format (JSONL, SQLite, Markdown, etc.) and only the originating agent can read/write it.
Design: Sessions are NOT interoperable between agents. A session created by Claude Code can only be read/written by Claude Code. This simplifies the implementation as we don't need format conversion.
func (*AgentSession) FindToolResultUUID ¶
func (s *AgentSession) FindToolResultUUID(toolUseID string) (string, bool)
FindToolResultUUID finds the UUID of the entry containing the tool result for the given tool use ID. Returns the UUID and true if found.
func (*AgentSession) GetLastAssistantResponse ¶
func (s *AgentSession) GetLastAssistantResponse() string
GetLastAssistantResponse returns the last assistant message content
func (*AgentSession) GetLastUserPrompt ¶
func (s *AgentSession) GetLastUserPrompt() string
GetLastUserPrompt returns the last user message content
func (*AgentSession) TruncateAtUUID ¶
func (s *AgentSession) TruncateAtUUID(uuid string) *AgentSession
TruncateAtUUID returns a new session truncated at the given UUID (inclusive)
type AgentType ¶
type AgentType string
AgentType is the display name type stored in metadata/trailers (e.g., "Claude Code", "Gemini CLI").
const ( AgentTypeClaudeCode AgentType = "Claude Code" AgentTypeGemini AgentType = "Gemini CLI" AgentTypeUnknown AgentType = "Agent" // Fallback for backwards compatibility )
Agent type constants (type identifiers stored in metadata/trailers)
func DetectAgentTypeFromContent ¶
DetectAgentTypeFromContent detects the agent type from transcript content. Returns AgentTypeGemini if it appears to be Gemini JSON format, empty AgentType otherwise. This is used when the agent type is unknown but we need to chunk/reassemble correctly.
type FileWatcher ¶
type FileWatcher interface {
Agent
// GetWatchPaths returns paths to watch for session changes
GetWatchPaths() ([]string, error)
// OnFileChange handles a detected file change and returns session info
OnFileChange(path string) (*SessionChange, error)
}
FileWatcher is implemented by agents that use file-based detection. Agents like Aider that don't support hooks can use file watching to detect session activity.
type HookHandler ¶
type HookHandler interface {
Agent
// GetHookNames returns the hook verbs this agent supports.
// These are the subcommand names that will appear under `entire hooks <agent>`.
// e.g., ["stop", "user-prompt-submit", "pre-task", "post-task", "post-todo"]
GetHookNames() []string
}
HookHandler is implemented by agents that define their own hook vocabulary. Each agent defines its own hook names (verbs) which become subcommands under `entire hooks <agent>`. The actual handling is done by handlers registered in the CLI package to avoid circular dependencies.
This allows different agents to have completely different hook vocabularies (e.g., Claude Code has "stop", Cursor might have "completion").
type HookInput ¶
type HookInput struct {
HookType HookType
SessionID string
// SessionRef is an agent-specific session reference (file path, db key, etc.)
SessionRef string
Timestamp time.Time
// UserPrompt is the user's prompt text (from UserPromptSubmit hooks)
UserPrompt string
// Tool-specific fields (PreToolUse/PostToolUse)
ToolName string
ToolUseID string
ToolInput []byte // Raw JSON
ToolResponse []byte // Raw JSON (PostToolUse only)
// RawData preserves agent-specific data for extension
RawData map[string]interface{}
}
HookInput contains normalized data from hook callbacks
type HookSupport ¶
type HookSupport interface {
Agent
// InstallHooks installs agent-specific hooks.
// If localDev is true, hooks point to local development build.
// If force is true, removes existing Entire hooks before installing.
// Returns the number of hooks installed.
InstallHooks(localDev bool, force bool) (int, error)
// UninstallHooks removes installed hooks
UninstallHooks() error
// AreHooksInstalled checks if hooks are currently installed
AreHooksInstalled() bool
// GetSupportedHooks returns the hook types this agent supports
GetSupportedHooks() []HookType
}
HookSupport is implemented by agents with lifecycle hooks. This optional interface allows agents like Claude Code and Cursor to install and manage hooks that notify Entire of agent events.
type SessionChange ¶
type SessionChange struct {
SessionID string
SessionRef string
EventType HookType
Timestamp time.Time
}
SessionChange represents detected session activity (for FileWatcher)
type SessionEntry ¶
type SessionEntry struct {
UUID string
Type EntryType
Timestamp time.Time
Content string
// Tool-specific fields
ToolName string
ToolInput interface{}
ToolOutput interface{}
FilesAffected []string
}
SessionEntry represents a single entry in the session
type TokenUsage ¶
type TokenUsage struct {
// InputTokens is the number of input tokens (fresh, not from cache)
InputTokens int `json:"input_tokens"`
// CacheCreationTokens is tokens written to cache (billable at cache write rate)
CacheCreationTokens int `json:"cache_creation_tokens"`
// CacheReadTokens is tokens read from cache (discounted rate)
CacheReadTokens int `json:"cache_read_tokens"`
// OutputTokens is the number of output tokens generated
OutputTokens int `json:"output_tokens"`
// APICallCount is the number of API calls made
APICallCount int `json:"api_call_count"`
// SubagentTokens contains token usage from spawned subagents (if any)
SubagentTokens *TokenUsage `json:"subagent_tokens,omitempty"`
}
TokenUsage represents aggregated token usage for a checkpoint. This is agent-agnostic and can be populated by any agent that tracks token usage.
type TranscriptAnalyzer ¶
type TranscriptAnalyzer interface {
Agent
// GetTranscriptPosition returns the current position (length) of a transcript.
// For JSONL formats (Claude Code), this is the line count.
// For JSON formats (Gemini CLI), this is the message count.
// Returns 0 if the file doesn't exist or is empty.
// Use this to efficiently check if the transcript has grown since last checkpoint.
GetTranscriptPosition(path string) (int, error)
// ExtractModifiedFilesFromOffset extracts files modified since a given offset.
// For JSONL formats (Claude Code), offset is the starting line number.
// For JSON formats (Gemini CLI), offset is the starting message index.
// Returns:
// - files: list of file paths modified by the agent (from Write/Edit tools)
// - currentPosition: the current position (line count or message count)
// - error: any error encountered during reading
ExtractModifiedFilesFromOffset(path string, startOffset int) (files []string, currentPosition int, err error)
}
TranscriptAnalyzer is implemented by agents that support transcript analysis. This allows agent-agnostic detection of work done between checkpoints.
type TranscriptChunker ¶
type TranscriptChunker interface {
Agent
// ChunkTranscript splits a transcript into chunks if it exceeds maxSize.
// Returns a slice of chunks. If the transcript fits in one chunk, returns single-element slice.
// The chunking is format-aware: JSONL splits at line boundaries, JSON splits message arrays.
ChunkTranscript(content []byte, maxSize int) ([][]byte, error)
// ReassembleTranscript combines chunks back into a single transcript.
// Handles format-specific reassembly (JSONL concatenation, JSON message merging).
ReassembleTranscript(chunks [][]byte) ([]byte, error)
}
TranscriptChunker is implemented by agents that support transcript chunking. This allows agents to split large transcripts into chunks for storage (GitHub has a 100MB blob limit) and reassemble them when reading.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package claudecode implements the Agent interface for Claude Code.
|
Package claudecode implements the Agent interface for Claude Code. |
|
Package geminicli implements the Agent interface for Gemini CLI.
|
Package geminicli implements the Agent interface for Gemini CLI. |