Documentation
¶
Overview ¶
Package agenthost provides client/server communication with agent host processes.
Package agenthost defines the IPC protocol for agent host processes.
The agent host is a lightweight process that wraps a Claude Code agent, allowing the daemon to restart and reattach to running agent subprocesses. The host maintains its own Unix socket for bidirectional communication.
Protocol Overview ¶
The protocol uses JSON-encoded request/response messaging over Unix sockets, following the same envelope pattern as the main daemon protocol.
Versioning ¶
The protocol includes a version field for compatibility checking. Clients should verify ProtocolVersion matches before proceeding. Breaking changes increment the major version; additive changes increment minor.
Package agenthost implements the agent host process that wraps Claude Code agents.
Index ¶
- Constants
- Variables
- func DecodePayload[T any](payload any) (*T, error)
- func UnmarshalPayload(payload any, dst any) error
- type AgentInfo
- type AttachRequest
- type AttachResponse
- type Client
- func (c *Client) AgentID() string
- func (c *Client) Attach(offset int64) (*AttachResponse, error)
- func (c *Client) Close() error
- func (c *Client) Connect() error
- func (c *Client) Detach() error
- func (c *Client) IsConnected() bool
- func (c *Client) List() (*ListResponse, error)
- func (c *Client) Ping() (*PingResponse, error)
- func (c *Client) RecvStreamEvent() (*StreamEvent, error)
- func (c *Client) Send(req *Request) (*Response, error)
- func (c *Client) SendInput(input string) error
- func (c *Client) SocketPath() string
- func (c *Client) Status() (*StatusResponse, error)
- func (c *Client) Stop(force bool, timeout int, reason string) (*StopResponse, error)
- type DiscoveredHost
- type HistoryEntry
- type HistoryRequest
- type HistoryResponse
- type HostInfo
- type ListResponse
- type Manager
- func (m *Manager) AgentID() string
- func (m *Manager) AgentInfo() AgentInfo
- func (m *Manager) GetBufferedEvents(fromOffset int64) []*StreamEvent
- func (m *Manager) SendMessage(content string) error
- func (m *Manager) SetServer(s *Server)
- func (m *Manager) StartReadLoop() error
- func (m *Manager) Stop(force bool, timeout time.Duration) error
- func (m *Manager) StreamOffset() int64
- type MessageType
- type PingResponse
- type Request
- type Response
- type SendRequest
- type Server
- type StatusResponse
- type StopRequest
- type StopResponse
- type StreamEvent
Constants ¶
const BroadcastTimeout = 100 * time.Millisecond
BroadcastTimeout is how long to wait for a client write before giving up.
const ConnectTimeout = 2 * time.Second
ConnectTimeout is the default timeout for connecting to an agent host.
const HistoryBufferSize = 1000
HistoryBufferSize is the number of stream events to keep in the ring buffer.
const MinProtocolVersion = "1.0"
MinProtocolVersion is the minimum supported protocol version. Hosts and clients should reject connections with older versions.
const ProtocolVersion = "1.0"
ProtocolVersion is the current agent host protocol version. Format: major.minor where major changes break compatibility.
const RequestTimeout = 10 * time.Second
RequestTimeout is the default timeout for request/response operations.
Variables ¶
var ( ErrNotConnected = errors.New("not connected to agent host") ErrHostNotFound = errors.New("agent host not found") )
Client errors.
var ( ErrAgentNotRunning = errors.New("agent is not running") ErrAgentNotSet = errors.New("agent not set") )
Errors returned by manager operations.
Functions ¶
func DecodePayload ¶
DecodePayload is a generic helper that decodes a response payload to type T.
func UnmarshalPayload ¶
UnmarshalPayload converts a generic payload to a specific type. This handles the JSON round-trip needed because payloads arrive as map[string]any.
Types ¶
type AgentInfo ¶
type AgentInfo struct {
ID string `json:"id"` // Agent ID
Project string `json:"project"` // Project name
State string `json:"state"` // starting, running, idle, done, error
PID int `json:"pid"` // Agent subprocess PID (0 if not running)
Worktree string `json:"worktree"` // Worktree path
StartedAt time.Time `json:"started_at"` // When agent started
Task string `json:"task,omitempty"` // Current task ID
Description string `json:"description,omitempty"` // Agent description
Backend string `json:"backend,omitempty"` // CLI backend (claude, codex)
}
AgentInfo contains agent subprocess status.
type AttachRequest ¶
type AttachRequest struct {
Offset int64 `json:"offset,omitempty"` // Stream offset to resume from (0 = beginning)
}
AttachRequest is the payload for host.attach requests.
type AttachResponse ¶
type AttachResponse struct {
AgentID string `json:"agent_id"` // Agent being attached to
StreamOffset int64 `json:"stream_offset"` // Current stream position
}
AttachResponse is the payload for host.attach responses.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client connects to an agent host process over Unix socket.
func NewClient ¶
NewClient creates a new agent host client for the given agent ID. The socket path is determined from the agent ID using paths.AgentHostSocketPath.
func NewClientWithSocket ¶
NewClientWithSocket creates a new agent host client with an explicit socket path. This is useful for testing or when the socket path is already known.
func (*Client) Attach ¶
func (c *Client) Attach(offset int64) (*AttachResponse, error)
Attach attaches to the agent's output stream. After attaching, use RecvStreamEvent to receive events.
func (*Client) IsConnected ¶
IsConnected returns true if the client is connected.
func (*Client) List ¶
func (c *Client) List() (*ListResponse, error)
List returns all agents managed by this host.
func (*Client) Ping ¶
func (c *Client) Ping() (*PingResponse, error)
Ping sends a ping request to check host connectivity.
func (*Client) RecvStreamEvent ¶
func (c *Client) RecvStreamEvent() (*StreamEvent, error)
RecvStreamEvent receives the next stream event from an attached connection. Only call this after Attach has been called.
func (*Client) SocketPath ¶
SocketPath returns the socket path this client connects to.
func (*Client) Status ¶
func (c *Client) Status() (*StatusResponse, error)
Status gets the detailed host and agent status.
type DiscoveredHost ¶
type DiscoveredHost struct {
AgentID string // Agent ID extracted from socket filename
SocketPath string // Full path to the socket file
Status *StatusResponse // Status from the host (nil if probe failed)
}
DiscoveredHost contains information about a discovered agent host.
func DiscoverActiveHosts ¶
func DiscoverActiveHosts() ([]DiscoveredHost, error)
DiscoverActiveHosts scans the hosts directory for socket files and probes each one. Returns a list of hosts that successfully responded to a status request.
func DiscoverHostsForProject ¶
func DiscoverHostsForProject(projectName string) ([]DiscoveredHost, error)
DiscoverHostsForProject returns active hosts that belong to a specific project.
type HistoryEntry ¶
type HistoryEntry struct {
Role string `json:"role"` // assistant, user, tool
Content string `json:"content,omitempty"` // Message content
ToolName string `json:"tool_name,omitempty"` // For tool calls
ToolInput string `json:"tool_input,omitempty"` // Tool input data
ToolResult string `json:"tool_result,omitempty"` // Tool result data
Timestamp string `json:"timestamp"` // RFC3339 timestamp
}
HistoryEntry represents a single chat history entry. This mirrors daemon.ChatEntryDTO but is specific to the agent host protocol.
type HistoryRequest ¶
type HistoryRequest struct {
Limit int `json:"limit,omitempty"` // Maximum entries to return (0 = all)
}
HistoryRequest is the payload for host.history requests.
type HistoryResponse ¶
type HistoryResponse struct {
AgentID string `json:"agent_id"` // Agent ID
Entries []HistoryEntry `json:"entries"` // Chat history entries
Offset int64 `json:"offset"` // Stream offset at time of response
Total int `json:"total,omitempty"` // Total entries available (before limit)
}
HistoryResponse is the payload for host.history responses.
type HostInfo ¶
type HostInfo struct {
PID int `json:"pid"` // Host process ID
Version string `json:"version"` // Host version
ProtocolVersion string `json:"protocol_version"` // Protocol version
StartedAt time.Time `json:"started_at"` // When host started
SocketPath string `json:"socket_path"` // Path to host socket
}
HostInfo contains host process status.
type ListResponse ¶
type ListResponse struct {
Agents []AgentInfo `json:"agents"`
}
ListResponse is the payload for host.list responses.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager manages a single agent and its output streaming. It wraps an agent.Agent and provides methods for the host server.
func NewManager ¶
NewManager creates a new manager for the given agent.
func (*Manager) GetBufferedEvents ¶
func (m *Manager) GetBufferedEvents(fromOffset int64) []*StreamEvent
GetBufferedEvents returns events from the history buffer starting from the given offset. Events are returned in chronological order (sorted by offset).
func (*Manager) SendMessage ¶
SendMessage sends a message to the agent.
func (*Manager) StartReadLoop ¶
StartReadLoop starts the agent's read loop with callbacks for streaming.
func (*Manager) StreamOffset ¶
StreamOffset returns the current stream offset.
type MessageType ¶
type MessageType string
MessageType identifies the type of agent host IPC message.
const ( // Host management MsgHostPing MessageType = "host.ping" // Health check and version info MsgHostStatus MessageType = "host.status" // Get detailed host and agent status // Agent listing MsgHostList MessageType = "host.list" // List all agents managed by this host // Stream management MsgHostAttach MessageType = "host.attach" // Attach to agent output stream MsgHostDetach MessageType = "host.detach" // Detach from agent output stream // History retrieval MsgHostHistory MessageType = "host.history" // Retrieve buffered chat history // Agent communication MsgHostSend MessageType = "host.send" // Send input to the agent // Lifecycle control MsgHostStop MessageType = "host.stop" // Gracefully stop the agent and host )
type PingResponse ¶
type PingResponse struct {
Version string `json:"version"` // Host process version
ProtocolVersion string `json:"protocol_version"` // IPC protocol version
Uptime string `json:"uptime"` // Human-readable uptime
StartedAt time.Time `json:"started_at"` // When the host started
}
PingResponse is the payload for host.ping responses.
type Request ¶
type Request struct {
Type MessageType `json:"type"`
ID string `json:"id,omitempty"` // Optional request ID for correlation
Payload any `json:"payload,omitempty"` // Type-specific payload
}
Request is the envelope for all agent host IPC requests.
type Response ¶
type Response struct {
Type MessageType `json:"type"`
ID string `json:"id,omitempty"` // Correlates with request ID
Success bool `json:"success"`
Error string `json:"error,omitempty"`
Payload any `json:"payload,omitempty"` // Type-specific payload
}
Response is the envelope for all agent host IPC responses.
func ErrorResponse ¶
ErrorResponse creates an error response for a request.
func SuccessResponse ¶
SuccessResponse creates a success response for a request.
type SendRequest ¶
type SendRequest struct {
Input string `json:"input"` // Raw input to send to agent
}
SendRequest is the payload for host.send requests.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the Unix socket RPC server for an agent host process. Each agent host manages a single coding agent and its associated socket.
func (*Server) AttachedCount ¶
AttachedCount returns the number of attached streaming clients.
func (*Server) Broadcast ¶
func (s *Server) Broadcast(event *StreamEvent)
Broadcast sends a stream event to all attached clients.
func (*Server) SocketPath ¶
SocketPath returns the socket path this server listens on.
type StatusResponse ¶
StatusResponse is the payload for host.status responses.
func ProbeHost ¶
func ProbeHost(agentID string) (*StatusResponse, error)
ProbeHost attempts to connect to an agent host and returns its status. Returns ErrHostNotFound if the host socket doesn't exist or isn't responding.
type StopRequest ¶
type StopRequest struct {
Force bool `json:"force,omitempty"` // Force kill (SIGKILL) vs graceful (/quit)
Timeout int `json:"timeout,omitempty"` // Graceful shutdown timeout in seconds (default: 30)
Reason string `json:"reason,omitempty"` // Optional reason for stopping
}
StopRequest is the payload for host.stop requests.
type StopResponse ¶
type StopResponse struct {
Stopped bool `json:"stopped"` // Whether agent was successfully stopped
ExitCode int `json:"exit_code,omitempty"` // Agent exit code if available
Graceful bool `json:"graceful"` // Whether shutdown was graceful
Duration string `json:"duration,omitempty"` // How long shutdown took
FinalState string `json:"final_state"` // Final agent state before exit
}
StopResponse is the payload for host.stop responses.
type StreamEvent ¶
type StreamEvent struct {
Type string `json:"type"` // output, state, chat_entry, error
AgentID string `json:"agent_id"` // Agent that produced the event
Offset int64 `json:"offset"` // Stream position of this event
Timestamp string `json:"timestamp"` // RFC3339 timestamp
Data string `json:"data,omitempty"` // For output events: raw output data
State string `json:"state,omitempty"` // For state events: new state
ChatEntry any `json:"chat_entry,omitempty"` // For chat_entry events: parsed chat message
Error string `json:"error,omitempty"` // For error events: error message
}
StreamEvent is sent to attached clients when agent output occurs. This mirrors the daemon StreamEvent but is specific to a single agent.