loop

package
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: Mar 20, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package loop provides the core agent loop that orchestrates Claude Code to implement user stories. It includes the main Loop struct for single PRD execution, Manager for parallel PRD execution, and Parser for processing Claude's stream-json output.

Index

Constants

View Source
const DefaultWatchdogTimeout = 5 * time.Minute

DefaultWatchdogTimeout is the default duration of silence before the watchdog kills a hung process.

Variables

This section is empty.

Functions

This section is empty.

Types

type Event

type Event struct {
	Type       EventType
	Iteration  int
	Text       string
	Tool       string
	ToolInput  map[string]interface{}
	StoryID    string
	Err        error
	RetryCount int // Current retry attempt (1-based)
	RetryMax   int // Maximum retries allowed
}

Event represents a parsed event from Claude's stream-json output.

func ParseLine

func ParseLine(line string) *Event

ParseLine parses a single line of stream-json output and returns an Event. If the line cannot be parsed or is not relevant, it returns nil.

func ParseLineCodex

func ParseLineCodex(line string) *Event

ParseLineCodex parses a single line of Codex exec --json JSONL output and returns an Event. If the line cannot be parsed or is not relevant, it returns nil.

func ParseLineCursor added in v0.8.0

func ParseLineCursor(line string) *Event

ParseLineCursor parses a single line of Cursor CLI stream-json NDJSON and returns an Event. If the line cannot be parsed or is not relevant, it returns nil.

func ParseLineOpenCode

func ParseLineOpenCode(line string) *Event

type EventType

type EventType int

EventType represents the type of event parsed from Claude's stream-json output.

const (
	// EventUnknown represents an unrecognized event type.
	EventUnknown EventType = iota
	// EventIterationStart is emitted at the start of a Claude iteration (system init).
	EventIterationStart
	// EventAssistantText is emitted when Claude outputs text.
	EventAssistantText
	// EventToolStart is emitted when Claude invokes a tool.
	EventToolStart
	// EventToolResult is emitted when a tool returns a result.
	EventToolResult
	// EventStoryDone is emitted when Claude signals a story is done via <chief-done/>.
	EventStoryDone
	// EventComplete is emitted when all stories are complete (buildPrompt returns error).
	EventComplete
	// EventMaxIterationsReached is emitted when max iterations are reached.
	EventMaxIterationsReached
	// EventError is emitted when an error occurs.
	EventError
	// EventRetrying is emitted when retrying after a crash.
	EventRetrying
	// EventWatchdogTimeout is emitted when the watchdog kills a hung process.
	EventWatchdogTimeout
)

func (EventType) String

func (e EventType) String() string

String returns the string representation of an EventType.

type Loop

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

Loop manages the core agent loop that invokes the configured agent repeatedly until all stories are complete.

func NewLoop

func NewLoop(prdPath, prompt string, maxIter int, provider Provider) *Loop

NewLoop creates a new Loop instance.

func NewLoopWithEmbeddedPrompt

func NewLoopWithEmbeddedPrompt(prdPath string, maxIter int, provider Provider) *Loop

NewLoopWithEmbeddedPrompt creates a new Loop instance using the embedded agent prompt. The prompt is rebuilt on each iteration to inline the current story context.

func NewLoopWithWorkDir

func NewLoopWithWorkDir(prdPath, workDir string, prompt string, maxIter int, provider Provider) *Loop

NewLoopWithWorkDir creates a new Loop instance with a configurable working directory. When workDir is empty, defaults to the project root for backward compatibility.

func (*Loop) DisableRetry

func (l *Loop) DisableRetry()

DisableRetry disables automatic retry on crash.

func (*Loop) Events

func (l *Loop) Events() <-chan Event

Events returns the channel for receiving events from the loop.

func (*Loop) IsPaused

func (l *Loop) IsPaused() bool

IsPaused returns whether the loop is paused.

func (*Loop) IsRunning

func (l *Loop) IsRunning() bool

IsRunning returns whether an agent process is currently running.

func (*Loop) IsStopped

func (l *Loop) IsStopped() bool

IsStopped returns whether the loop is stopped.

func (*Loop) Iteration

func (l *Loop) Iteration() int

Iteration returns the current iteration number.

func (*Loop) MaxIterations

func (l *Loop) MaxIterations() int

MaxIterations returns the current max iterations limit.

func (*Loop) Pause

func (l *Loop) Pause()

Pause sets the pause flag. The loop will stop after the current iteration completes.

func (*Loop) Resume

func (l *Loop) Resume()

Resume clears the pause flag.

func (*Loop) Run

func (l *Loop) Run(ctx context.Context) error

Run executes the agent loop until completion or max iterations.

func (*Loop) SetMaxIterations

func (l *Loop) SetMaxIterations(maxIter int)

SetMaxIterations updates the maximum iterations limit.

func (*Loop) SetRetryConfig

func (l *Loop) SetRetryConfig(config RetryConfig)

SetRetryConfig updates the retry configuration.

func (*Loop) SetWatchdogTimeout

func (l *Loop) SetWatchdogTimeout(timeout time.Duration)

SetWatchdogTimeout sets the watchdog timeout duration. Setting timeout to 0 disables the watchdog.

func (*Loop) Stop

func (l *Loop) Stop()

Stop terminates the current agent process and stops the loop.

func (*Loop) WatchdogTimeout

func (l *Loop) WatchdogTimeout() time.Duration

WatchdogTimeout returns the current watchdog timeout duration.

type LoopInstance

type LoopInstance struct {
	Name        string
	PRDPath     string
	WorktreeDir string // Working directory for this PRD (empty = project root)
	Branch      string // Git branch for this PRD (empty = current branch)
	Loop        *Loop
	State       LoopState
	Iteration   int
	StartTime   time.Time
	Error       error
	// contains filtered or unexported fields
}

LoopInstance represents a single loop with its metadata.

type LoopState

type LoopState int

LoopState represents the state of a loop instance.

const (
	LoopStateReady LoopState = iota
	LoopStateRunning
	LoopStatePaused
	LoopStateStopped
	LoopStateComplete
	LoopStateError
)

func (LoopState) String

func (s LoopState) String() string

type Manager

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

Manager manages multiple Loop instances for parallel PRD execution.

func NewManager

func NewManager(maxIter int, provider Provider) *Manager

NewManager creates a new loop manager.

func (*Manager) ClearWorktreeInfo

func (m *Manager) ClearWorktreeInfo(name string, clearBranch bool) error

ClearWorktreeInfo clears the worktree directory and optionally the branch for a PRD instance.

func (*Manager) Config

func (m *Manager) Config() *config.Config

Config returns the current project config.

func (*Manager) DisableRetry

func (m *Manager) DisableRetry()

DisableRetry disables automatic retry for new loops.

func (*Manager) Events

func (m *Manager) Events() <-chan ManagerEvent

Events returns the channel for receiving events from all loops.

func (*Manager) GetAllInstances

func (m *Manager) GetAllInstances() []*LoopInstance

GetAllInstances returns a snapshot of all loop instances.

func (*Manager) GetInstance

func (m *Manager) GetInstance(name string) *LoopInstance

GetInstance returns a copy of the loop instance data for a specific PRD.

func (*Manager) GetRunningCount

func (m *Manager) GetRunningCount() int

GetRunningCount returns the number of currently running loops.

func (*Manager) GetRunningPRDs

func (m *Manager) GetRunningPRDs() []string

GetRunningPRDs returns the names of all currently running PRDs.

func (*Manager) GetState

func (m *Manager) GetState(name string) (LoopState, int, error)

GetState returns the state of a specific PRD loop.

func (*Manager) IsAnyRunning

func (m *Manager) IsAnyRunning() bool

IsAnyRunning returns true if any loop is currently running.

func (*Manager) MaxIterations

func (m *Manager) MaxIterations() int

MaxIterations returns the current default max iterations.

func (*Manager) Pause

func (m *Manager) Pause(name string) error

Pause pauses the loop for a specific PRD (stops after current iteration).

func (*Manager) Register

func (m *Manager) Register(name, prdPath string) error

Register registers a PRD with the manager (does not start it).

func (*Manager) RegisterWithWorktree

func (m *Manager) RegisterWithWorktree(name, prdPath, worktreeDir, branch string) error

RegisterWithWorktree registers a PRD with worktree metadata (does not start it).

func (*Manager) SetBaseDir

func (m *Manager) SetBaseDir(baseDir string)

SetBaseDir sets the project root directory so Claude runs from there and picks up CLAUDE.md.

func (*Manager) SetCompletionCallback

func (m *Manager) SetCompletionCallback(fn func(prdName string))

SetCompletionCallback sets a callback that is called when any PRD completes.

func (*Manager) SetConfig

func (m *Manager) SetConfig(cfg *config.Config)

SetConfig sets the project config for post-completion actions.

func (*Manager) SetMaxIterations

func (m *Manager) SetMaxIterations(maxIter int)

SetMaxIterations updates the default max iterations for new loops.

func (*Manager) SetMaxIterationsForInstance

func (m *Manager) SetMaxIterationsForInstance(name string, maxIter int) error

SetMaxIterationsForInstance updates max iterations for a specific running loop.

func (*Manager) SetPostCompleteCallback

func (m *Manager) SetPostCompleteCallback(fn func(prdName, branch, workDir string))

SetPostCompleteCallback sets a callback for post-completion actions (push, PR creation). The callback receives the PRD name, branch name, and working directory.

func (*Manager) SetRetryConfig

func (m *Manager) SetRetryConfig(config RetryConfig)

SetRetryConfig sets the retry configuration for new loops.

func (*Manager) Start

func (m *Manager) Start(name string) error

Start starts the loop for a specific PRD.

func (*Manager) Stop

func (m *Manager) Stop(name string) error

Stop stops the loop for a specific PRD immediately.

func (*Manager) StopAll

func (m *Manager) StopAll()

StopAll stops all running loops.

func (*Manager) Unregister

func (m *Manager) Unregister(name string) error

Unregister removes a PRD from the manager (stops it first if running).

func (*Manager) UpdateWorktreeInfo

func (m *Manager) UpdateWorktreeInfo(name, worktreeDir, branch string) error

UpdateWorktreeInfo updates the worktree directory and branch for an existing PRD instance.

type ManagerEvent

type ManagerEvent struct {
	PRDName   string
	Event     Event
	Completed bool // True if this PRD just completed all stories
}

ManagerEvent represents an event from any managed loop.

type Provider

type Provider interface {
	Name() string
	CLIPath() string
	LoopCommand(ctx context.Context, prompt, workDir string) *exec.Cmd
	InteractiveCommand(workDir, prompt string) *exec.Cmd
	// CleanOutput extracts JSON from the provider's output format (e.g., NDJSON).
	// Returns the original output if no cleaning needed.
	CleanOutput(output string) string
	ParseLine(line string) *Event
	LogFileName() string
}

Provider is the interface for an agent CLI (e.g. Claude, Codex). Implementations live in internal/agent to avoid import cycles.

type RetryConfig

type RetryConfig struct {
	MaxRetries  int             // Maximum number of retry attempts (default: 3)
	RetryDelays []time.Duration // Delays between retries (default: 0s, 5s, 15s)
	Enabled     bool            // Whether retry is enabled (default: true)
}

RetryConfig configures automatic retry behavior on Claude crashes.

func DefaultRetryConfig

func DefaultRetryConfig() RetryConfig

DefaultRetryConfig returns the default retry configuration.

Jump to

Keyboard shortcuts

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