claudecode

package
v0.2.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 3, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Overview

Package claudecode is the Claude Code provider: a Claude Code session is an agent loop in its own process on the operator's machine. The package holds that session's agent address and ClaudeCodeBrain, the model.IBrain that drives Claude Code as a turn executor: CSF owns the session, and each turn runs one Claude Code process through the ipc/proc capability, forwarding every input and every stream-json event unchanged and reporting each one to a structured log under the turn's trace.

A Claude Code session reaches CSF as a host-tier agent: it calls CSF's per-agent authenticated MCP endpoint over a local socket (a unix socket, or loopback), registers its HostAddress, and fetches and acknowledges its inbox through MCP tools.

Index

Constants

View Source
const (
	// SocketUnix is a unix domain socket, named by its absolute path.
	SocketUnix = "unix"
	// SocketLoopback is a TCP socket on a loopback address.
	SocketLoopback = "tcp"
)
View Source
const (
	// EventTypeSystem is a Claude Code system event; its init subtype opens a
	// run and names the session.
	EventTypeSystem = "system"
	// EventTypeResult is the event that ends a turn.
	EventTypeResult = "result"
	// EventTypeMalformed names, in the report only, an output line that was
	// not a stream-json event. No [Event] ever carries it.
	EventTypeMalformed = "malformed"
)

Stream-json event types and subtypes the brain reads. It reads them only to report and to know when a turn is done; every event is forwarded unchanged.

View Source
const DefaultExecutable = "claude"

DefaultExecutable is the Claude Code command line, resolved on PATH.

View Source
const (

	// EventTypeControlResponse answers a control request; it is forwarded like
	// every other event.
	EventTypeControlResponse = "control_response"
)

Stream-json control messages the open session writes.

View Source
const ProviderName = "claudecode"

ProviderName names the Claude Code provider in addresses.

Variables

View Source
var (
	// ErrNoSession reports an address built without a session identifier.
	ErrNoSession = errors.New("claudecode address: a nonzero session identifier is required")
	// ErrNotLocal reports a socket another machine could reach, which a
	// host-tier address may not name.
	ErrNotLocal = errors.New("claudecode address: the socket must be a unix socket or a loopback address")
)
View Source
var (
	// ErrNoLauncher reports a brain constructed without the process
	// capability.
	ErrNoLauncher = errors.New("claudecode brain: a process launcher is required")
	// ErrInvalidOption reports a nil option or an option value the brain
	// cannot use.
	ErrInvalidOption = errors.New("claudecode brain: invalid option")
	// ErrNoTurn reports a nil turn or a turn with no input message.
	ErrNoTurn = errors.New("claudecode brain: a turn needs at least one input message")
	// ErrMalformedInput reports an input message that is not a JSON object.
	ErrMalformedInput = errors.New("claudecode brain: input message is not a JSON object")
	// ErrMalformedEvent reports an output line that is not a stream-json
	// event.
	ErrMalformedEvent = errors.New("claudecode brain: Claude Code wrote a line that is not a stream-json event")
	// ErrTurnIncomplete reports a Claude Code process that exited without the
	// result event that ends a turn.
	ErrTurnIncomplete = errors.New("claudecode brain: Claude Code exited before reporting the turn's result")
	// ErrSessionMismatch reports a Claude Code run that opened a session other
	// than the one CSF gave it.
	ErrSessionMismatch = errors.New("claudecode brain: Claude Code opened a different session")
)
View Source
var (
	// ErrSessionClosed reports a turn or an interrupt on an open session whose
	// Claude Code process has exited or been closed.
	ErrSessionClosed = errors.New("claudecode session: the Claude Code process is closed")
	// ErrTurnAbandoned reports a turn whose caller stopped waiting before
	// Claude Code reported the result; the process may still be working on it.
	ErrTurnAbandoned = errors.New("claudecode session: the turn was abandoned before its result")
)

Functions

This section is empty.

Types

type ClaudeCodeBrain

type ClaudeCodeBrain struct {
	// contains filtered or unexported fields
}

ClaudeCodeBrain drives Claude Code as a turn executor for one session CSF owns. Each Propose is one turn: one Claude Code process, launched through the granted process capability, fed the turn's messages and read to its result event. Inputs and events pass through unchanged; every one is reported to the brain's logger with the turn's trace.

Turns of one session never overlap: Propose waits for the previous turn of the same brain to finish, and a context canceled while waiting abandons the wait.

func NewClaudeCodeBrain

func NewClaudeCodeBrain(launcher proc.ILauncher, session uuid.UUID, options ...ClaudeCodeBrainOption) (*ClaudeCodeBrain, error)

NewClaudeCodeBrain builds the Claude Code turn executor for session. The launcher is the process capability every turn's Claude Code process is started through; the caller owns it.

func (*ClaudeCodeBrain) Open

func (brain *ClaudeCodeBrain) Open(ctx context.Context) (*ClaudeCodeSession, error)

Open starts Claude Code on the brain's session and keeps it open. The process is bounded by the session's own lifetime, not by ctx: ctx only carries the trace and bounds the start itself.

func (*ClaudeCodeBrain) Propose

func (brain *ClaudeCodeBrain) Propose(ctx context.Context, turn *Turn) (*model.Proposal[Event], error)

Propose runs one turn: it starts Claude Code on the session, writes the turn's messages and returns every event Claude Code reported, unchanged and in order, ending with the result event. A turn that does not reach its result returns a *TurnError carrying the events seen before the failure.

func (*ClaudeCodeBrain) Session

func (brain *ClaudeCodeBrain) Session() uuid.UUID

Session is the session identifier CSF gave this brain.

type ClaudeCodeBrainOption

type ClaudeCodeBrainOption func(brain *ClaudeCodeBrain) error

ClaudeCodeBrainOption configures a ClaudeCodeBrain.

func WithArguments

func WithArguments(arguments ...string) ClaudeCodeBrainOption

WithArguments appends arguments to every Claude Code invocation, after the flags the brain owns. They pass through unchanged; the brain's own flags (print mode, stream formats, verbose, session selection) may not be repeated.

func WithDirectory

func WithDirectory(directory string) ClaudeCodeBrainOption

WithDirectory runs Claude Code in directory instead of the caller's working directory.

func WithEnvironment

func WithEnvironment(variables ...string) ClaudeCodeBrainOption

WithEnvironment appends variables, as NAME=value, to the environment every Claude Code process inherits.

func WithExecutable

func WithExecutable(executable string) ClaudeCodeBrainOption

WithExecutable runs Claude Code from executable, a path or a name on PATH, instead of DefaultExecutable.

func WithLogger

func WithLogger(logger *slog.Logger) ClaudeCodeBrainOption

WithLogger reports every turn and event to logger instead of slog.Default().

func WithResumedSession

func WithResumedSession() ClaudeCodeBrainOption

WithResumedSession declares that Claude Code already holds the session, so the first turn resumes it rather than creating it.

type ClaudeCodeSession

type ClaudeCodeSession struct {
	// contains filtered or unexported fields
}

ClaudeCodeSession is one Claude Code process kept open across turns: the stream-json input stays open, every turn's messages are written to it, and the events of each turn are read to its result. It is the turn executor an open harness session holds, so a later Send is a turn on the same process rather than a new one resuming the session.

Open starts the process; Propose runs a turn on it; Interrupt asks Claude Code to end the running turn at its next safepoint; Close ends the input, waits for the process to exit and joins every goroutine the session started. Turns never overlap: Propose waits for the previous turn.

func (*ClaudeCodeSession) Close

func (open *ClaudeCodeSession) Close(ctx context.Context) error

Close ends the input, which makes Claude Code exit once its current turn is done, and waits for the process. When ctx ends first the process group is killed and the wait completes on that. Close joins every goroutine the session started; it is idempotent.

func (*ClaudeCodeSession) Exited

func (open *ClaudeCodeSession) Exited() <-chan struct{}

Exited is closed once the process has exited, however it ended.

func (*ClaudeCodeSession) Interrupt

func (open *ClaudeCodeSession) Interrupt(ctx context.Context) error

Interrupt asks Claude Code to end the running turn at its next safepoint, a tool boundary; the turn then reports its result like any other. It is the cancel a harness session delivers while a turn is in flight.

func (*ClaudeCodeSession) Propose

func (open *ClaudeCodeSession) Propose(ctx context.Context, turn *Turn) (*model.Proposal[Event], error)

Propose runs one turn on the open process: it writes the turn's messages and returns every event Claude Code reported until the result event, unchanged and in order. A turn the process ends before its result, or that ctx abandons, returns a *TurnError carrying the events seen so far.

func (*ClaudeCodeSession) Session

func (open *ClaudeCodeSession) Session() uuid.UUID

Session is the session identifier Claude Code was opened on.

type Event

type Event struct {
	Type string
	Raw  json.RawMessage
}

Event is one stream-json event Claude Code reported during a turn. Raw is the line exactly as Claude Code wrote it; Type is its "type" field, read for the report.

type HostAddress

type HostAddress struct {
	model.HostTier
	Session uuid.UUID
	Socket  LocalSocket
}

HostAddress is a Claude Code session on this machine: its session identifier and the local socket it is reached on.

func NewHostAddress

func NewHostAddress(session uuid.UUID, endpoint string) (HostAddress, error)

NewHostAddress addresses session at the local socket endpoint.

func (HostAddress) Key

func (address HostAddress) Key() string

Key is claudecode/host/<socket>/<session>.

func (HostAddress) Provider

func (address HostAddress) Provider() string

Provider is ProviderName.

type LocalSocket

type LocalSocket struct {
	// Network is [SocketUnix] or [SocketLoopback].
	Network string
	// Address is an absolute path for a unix socket and a loopback
	// host:port for TCP.
	Address string
}

LocalSocket is a socket only processes on this machine can reach.

func ParseLocalSocket

func ParseLocalSocket(endpoint string) (LocalSocket, error)

ParseLocalSocket reads "unix:/absolute/path", "/absolute/path" or a loopback "host:port", where the host is a loopback IP or "localhost". Anything another machine could reach is rejected: the tier of a Claude Code address is decided by the socket it registers, never inferred from where a request happened to arrive.

func (LocalSocket) String

func (socket LocalSocket) String() string

String is the socket in the form ParseLocalSocket reads.

type MalformedEventError

type MalformedEventError struct {
	// Line is the 1-based output line number.
	Line int
	Err  error
}

MalformedEventError locates the first output line that was not a stream-json event. It wraps ErrMalformedEvent.

func (*MalformedEventError) Error

func (failure *MalformedEventError) Error() string

func (*MalformedEventError) Unwrap

func (failure *MalformedEventError) Unwrap() []error

type Turn

type Turn struct {
	Messages []json.RawMessage
}

Turn is the context the Claude Code brain decides on: the stream-json input messages of one turn, each a JSON object such as {"type":"user","message":{"role":"user","content":"..."}}. They are written to Claude Code unchanged, one per line.

type TurnError

type TurnError struct {
	Turn   int
	Events []Event
	Err    error
}

TurnError reports a turn that did not complete. Events holds every event Claude Code reported before the failure, unchanged, so nothing it said is lost with the error.

func (*TurnError) Error

func (failure *TurnError) Error() string

func (*TurnError) Unwrap

func (failure *TurnError) Unwrap() error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL