Help us shape the future of Go! Take the 2026 Go Developer Survey

factory

package
v0.7.218 Latest Latest
Warning

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

Go to latest
Published: Oct 20, 2026 License: MIT Imports: 31 Imported by: 0

Documentation

Overview

Package factory runs an implementer agent on a sidecar and loops it through review and validation until the checks pass or attempts run out.

Index

Constants

View Source
const BootstrapImage = "cimg-base:2026.09-claude"

BootstrapImage is the sidecar image bootstrap runs on unless told otherwise: a system template with Claude Code installed. Bootstrap only reads the project, so it needs Claude rather than the project's toolchain, and the project's own image may not have Claude. The provisioner has no alias for the newest template, so this names one and needs bumping as they are added.

View Source
const BootstrapPoolName = "factory-bootstrap"

BootstrapPoolName names the pool bootstrap runs on. It is its own pool, not the review pool: bootstrap needs one sidecar, and asking the review pool for one would delete the rest of it.

View Source
const DefaultBootstrapTimeout = 30 * time.Minute

DefaultBootstrapTimeout bounds writing the review prompts. Claude reads widely around the repository before it writes anything, and on a large one that takes longer than a review does.

View Source
const DefaultImplementTimeout = 30 * time.Minute

DefaultImplementTimeout bounds one implementer turn. A turn writes code and may run the tests several times, so it gets longer than a review.

View Source
const HistoryPath = ".chunk/review-history.md"

HistoryPath is where, in the sidecar's copy of the repository, bootstrap puts the team's review history for Claude to read. It is a file rather than part of the prompt because a busy repository's history is too large for one.

View Source
const LogDefault = "default"

LogDefault is the RunOptions.Log that puts the run's log at DefaultLogPath.

View Source
const SeverityRubric = severityScope

SeverityRubric is the rubric every review is held to, for whatever judges reviews by the bar they were given, such as eval's grader.

Variables

View Source
var ErrDiffAlreadyApplied = errors.New("the diff is already in your files")

ErrDiffAlreadyApplied is returned by Start when the diff is already in the developer's files, as a git diff of the same checkout is: the worktree starts from those files, so there is no first pass left to lay on them.

View Source
var ErrNoClaude = errors.New("claude is not installed")

ErrNoClaude is returned when Claude Code is not installed on the developer's machine, so there is nothing to make a first pass with.

View Source
var ErrNoRecord = errors.New("no record of the run")

ErrNoRecord means a run left no record to continue it from: there was no such run, or chunk made it before runs kept one.

View Source
var ErrNothingToCheck = errors.New("nothing to check the implementer's work with")

ErrNothingToCheck means a run has neither review prompts nor validation commands, so its loop would pass whatever the implementer wrote.

View Source
var ErrNothingToRefine = errors.New("nothing was done in the run's worktree to refine")

ErrNothingToRefine is returned when a run whose record needs work, such as one made by Start, is continued before anything was done in its worktree: the factory refines a diff, and there is none.

View Source
var ErrPromptsExist = errors.New("review prompts already exist")

ErrPromptsExist means the directory bootstrap would write to already has review prompts, which it never overwrites.

View Source
var ErrUnknownTemplate = errors.New("unknown review template")

ErrUnknownTemplate means no standard set of review prompts has the name.

Functions

func BaselineCommitScript added in v0.7.212

func BaselineCommitScript(repoPath string) string

BaselineCommitScript is the commit that makes the developer's synced tree the baseline, so their uncommitted work is part of what the reviewers measure against rather than part of the change.

func CheckClaude added in v0.7.217

func CheckClaude() error

CheckClaude returns ErrNoClaude when there is no claude on PATH to make a first pass with, so a developer is told before typing a prompt.

func CheckPromptsDir added in v0.7.206

func CheckPromptsDir(dir string) error

CheckPromptsDir reports ErrPromptsExist when dir already has review prompts, so a caller can refuse before any sidecar starts. A missing dir is fine.

func CommitMessage added in v0.7.197

func CommitMessage(prompt, runID string, o Outcome) string

CommitMessage is the work's commit message: the prompt's first line as the subject, the rest of the prompt below it, and how the run ended.

func DefaultLogPath added in v0.7.197

func DefaultLogPath(root, runID string) (string, error)

DefaultLogPath is where a run's log goes when no path is given: beside the run's record in the repository at root. The run ID is already the run's start time, so it alone names the file.

func Feedback

func Feedback(checks []Check) string

Feedback renders the failed checks of a round as the implementer's next prompt, or "" when nothing failed. Errored checks are left out: they say nothing about the code, and asking the implementer to fix them would send it chasing infrastructure.

func HostRecordScript added in v0.7.215

func HostRecordScript() string

HostRecordScript finds a per-run remote host's own factory run record and prints it: on a per-run box there is exactly one *.json under its data directory that is not a *.pool.json. The data directory is found the way config.AppData finds it, XDG_DATA_HOME first. A pull reads the host's worktree from it rather than from anything the run itself printed, so it works however little output the server still has.

func LoadChecks added in v0.7.197

func LoadChecks(dir string, optional bool, cfg *config.ProjectConfig, noValidate bool) ([]review.Prompt, []config.Command, error)

LoadChecks loads what the implementer's work is checked with: the review prompts in dir and, unless noValidate, cfg's validation commands. With optional, a missing or empty dir means no reviews rather than an error, so validation commands alone may do.

func Members added in v0.7.197

func Members(impl *sidecar.PoolEntry, ids []string) []*sidecar.PoolEntry

Members describes every sidecar in a pool other than the implementer, the ones its tree is relayed to. ids are the pool's, once it is synced.

func NewRunID added in v0.7.211

func NewRunID() string

NewRunID names a run by its start time and a short random suffix. Runs are keyed by repository, so two started in the same second, from different clones of one repository, would otherwise share a worktree, record and pool.

func ParseRunID added in v0.7.204

func ParseRunID(s string) string

ParseRunID accepts a run's ID or its branch, as chunk factory prints both. Factory branch names end in the stable run ID; older branches contain only that ID after branchPrefix.

func Passed

func Passed(checks []Check) bool

Passed reports whether every check passed. An errored check is not a pass: a round where a review could not run has not shown the code is clean.

func PoolName added in v0.7.197

func PoolName(runID string) string

PoolName names a run's sidecar pool. Each run has a pool of its own, rather than one per project reused as `chunk review` does: every member is synced from the run's worktree and gets a baseline commit on top of it, which a later run's sync does not expect. Two runs in one project must not share sidecars either.

func PoolSize added in v0.7.197

func PoolSize(reviewers int) int

PoolSize is how many sidecars a run needs: the implementer, which runs the validation commands too, and one per reviewer.

func PoolStatePath added in v0.7.209

func PoolStatePath(dataDir, runID string) string

PoolStatePath is where the run's sidecar pool keeps its state, beside the run's record in dataDir.

func PullRequestBody added in v0.7.212

func PullRequestBody(prompt string, rep Report, src PromptSource) string

PullRequestBody is a run's pull request description: what was asked and how the review went. The diff and its stat are on the pull request already.

func PullRequestTitle added in v0.7.212

func PullRequestTitle(prompt, runID string) string

PullRequestTitle is the title a run's pull request gets: the prompt's first line, cut between words to what a listing shows. A prompt with no words in it falls back to naming the run.

func RemoteHasBranch added in v0.7.212

func RemoteHasBranch(ctx context.Context, dir, remote, name string) (bool, error)

RemoteHasBranch reports whether remote, as the repository at dir knows it, has a branch called name. It asks the remote, not the last fetch, since a pull request needs the branch to be there now.

func ReviewPrompts added in v0.7.209

func ReviewPrompts(request string, prompts []review.Prompt) []review.Prompt

ReviewPrompts is prompts as a run's first round of reviews is sent them, for running them the way factory does outside a run.

func ReviewerCount added in v0.7.197

func ReviewerCount(requested int, prompts []review.Prompt) int

ReviewerCount is how many reviewer sidecars a run with prompts needs when asked for requested: one per prompt unless fewer are asked for, and none without prompts.

func SaveRecord added in v0.7.215

func SaveRecord(dataDir string, r Record) error

SaveRecord writes r to the repository's data directory, replacing what an earlier save wrote.

func Templates added in v0.7.209

func Templates() []string

Templates names the standard sets of review prompts, sorted.

func ValidationCommands

func ValidationCommands(cmds []config.Command) []config.Command

ValidationCommands picks the configured commands the loop runs: those that check rather than fix, can run remotely, and need no template expanded against the developer's local changes.

func WorkDiff added in v0.7.217

func WorkDiff(ctx context.Context, rec Record) (string, error)

WorkDiff is a started run's work so far, committed or not, as a patch against its baseline, for the developer to read before handing it over.

func WorkStat added in v0.7.217

func WorkStat(ctx context.Context, rec Record) (string, error)

WorkStat is git's per-file summary of a started run's work so far, committed or not, against its baseline, or "" when there is none.

func WritePrompts added in v0.7.206

func WritePrompts(dir string, prompts []GeneratedPrompt) ([]string, error)

WritePrompts writes each prompt to dir as <name>.md and returns the paths written. It refuses a dir that already has review prompts, checked again here because time passes between the caller's check and the answer.

Types

type Bootstrap added in v0.7.206

type Bootstrap struct {
	Prompts []GeneratedPrompt
	// Summary is the agent's account of the repository and its choices.
	Summary string
	// Dropped counts prompts in the answer that were unusable: a bad or
	// repeated name, an empty or oversized body, or past the limit.
	Dropped int
	// CostUSD is what the run cost, as claude reported it.
	CostUSD float64
}

Bootstrap is the outcome of writing a project's first review prompts.

func RunBootstrap added in v0.7.206

func RunBootstrap(ctx context.Context, opts BootstrapOptions) (Bootstrap, error)

RunBootstrap has Claude Code read the repository on the entry's sidecar and write review prompts for it. It writes nothing locally; see WritePrompts.

type BootstrapOptions added in v0.7.206

type BootstrapOptions struct {
	Exec       sidecar.Execer
	WriteFile  sidecar.FileWriter
	Entry      *sidecar.PoolEntry
	Credential claudecode.Credential
	BaseURL    string
	Model      string        // optional; Claude Code's default when empty
	Timeout    time.Duration // DefaultBootstrapTimeout when zero
	// Commands are the project's validation commands, which run on every
	// change, so the reviews need not check what they already enforce.
	Commands []config.Command
	// History is the review comments the team left on the repository's pull
	// requests. Nil or empty, the prompts are written from the code alone.
	History *reviewhistory.History
	// OnActivity is called with each tool call and piece of text as claude
	// makes it, since reading a large project takes many minutes.
	OnActivity func(claudecode.Activity)
}

BootstrapOptions configures writing a project's first review prompts.

type Change

type Change struct {
	// Fingerprint identifies the content of the change, so a round in which
	// the implementer changed nothing can be detected.
	Fingerprint string
	// Stat is git's one-line summary, such as "3 files changed, 40 insertions(+)".
	Stat string
}

Change is the implementer's work so far, relative to the baseline.

func (Change) Empty

func (c Change) Empty() bool

Empty reports whether the implementer has changed nothing.

type Check

type Check struct {
	Name      string
	Kind      Kind
	Status    Status
	SidecarID string
	Duration  time.Duration
	// Feedback is what the implementer is told when the check failed.
	Feedback string
	// Error is why the check could not run, for StatusErrored.
	Error string
	// Findings are a review's findings, kept as data for display.
	Findings []review.Finding
	// Prose is a review's prose alongside its findings, kept for display.
	Prose string
	// ExitCode and Output are a validation command's exit code and the tail of
	// its output, kept for display and the run's log.
	ExitCode int
	Output   string
}

Check is the outcome of one review or validation command in one round. A review is treated like any other command run on a sidecar: it passes or fails, and a failure carries feedback for the implementer.

func FromCommand

func FromCommand(name, sidecarID string, exitCode int, output string, d time.Duration, runErr error) Check

FromCommand converts one validation command's run into a check. runErr is a failure to run the command at all, as opposed to it exiting non-zero.

func FromReview

func FromReview(r review.Result) Check

FromReview converts one review result, run with structured findings, into a check. A review fails only on findings worth changing (high or medium), the same bar the session loop uses, so the implementer is not sent round after round to polish style remarks. Lower findings are kept for display. A review that could not run errored.

type Continuation added in v0.7.204

type Continuation struct {
	From Record
	// Guidance is what the developer adds to the original request, or "".
	// Without it the run checks the work as it is before the implementer's
	// first turn, so that turn is sent what failed.
	Guidance string
}

Continuation is a run that picks up the work an earlier run left on its branch, typically one whose checks still failed when its attempts ran out. It works in that run's worktree and adds a commit to its branch, and its reviewers see the whole change since the original baseline, not only what the continuation adds.

type Event

type Event struct {
	Kind   EventKind
	Round  int
	Prompt string
	Turn   Turn
	Change Change
	Checks []Check
}

Event reports progress through the loop.

type EventKind

type EventKind int

EventKind identifies a step of the loop for display.

const (
	EventImplementing EventKind = iota // a turn started; Round, Prompt
	EventImplemented                   // a turn ended; Round, Turn
	EventCollected                     // the work was collected; Round, Change
	EventChecking                      // checks started; Round
	EventChecked                       // checks ended; Round, Checks
)

Event kinds, in the order a round emits them.

type GeneratedPrompt added in v0.7.206

type GeneratedPrompt struct {
	Name string
	Body string
}

GeneratedPrompt is one review prompt bootstrap wrote.

func Template added in v0.7.209

func Template(name string) ([]GeneratedPrompt, error)

Template returns the review prompts in the named standard set, sorted by name, ready for WritePrompts.

type Handoff added in v0.7.211

type Handoff struct {
	Prompt string
	// SpecOrigin is the path Prompt was read from, when it named a file rather
	// than being literal text.
	SpecOrigin string
	Diff       []byte
}

Handoff is the work a developer gives the factory to refine: the prompt that says what the change is for, and the work so far as a diff against their files. Where the diff was made, by hand, by a local agent or on a sidecar, is up to them. With no diff, the work is whatever they go on to do in the run's worktree.

type Implementer

type Implementer struct {
	Exec         sidecar.Execer
	Entry        *sidecar.PoolEntry
	Credential   claudecode.Credential
	BaseURL      string
	Model        string
	Timeout      time.Duration
	Instructions string
	OnActivity   func(claudecode.Activity)
	// contains filtered or unexported fields
}

Implementer runs Claude Code on a sidecar to write code. Every turn resumes the same session, so feedback arrives with the context of the work so far.

func (*Implementer) Run

func (im *Implementer) Run(ctx context.Context, prompt string) (Turn, error)

Run sends prompt to the implementer and waits for its turn to end.

type Kind

type Kind string

Kind is what produced a check: a review prompt or a validation command.

const (
	KindReview   Kind = "review"
	KindValidate Kind = "validate"
)

Check kinds.

type Loop

type Loop struct {
	// Attempts is the most rounds to check. Each round after the first starts
	// with an implementer turn fixing the previous round's failures.
	Attempts int
	// CheckFirst checks the work already there before the implementer's first
	// turn, which is then sent the prompt with what failed. Work that passes
	// as it is ends the loop without a turn. The first round counts as one of
	// the attempts.
	CheckFirst bool
	OnEvent    func(Event)
}

Loop drives the implementer through rounds of review and validation.

func (Loop) Run

func (l Loop) Run(ctx context.Context, steps Steps, prompt string) (Outcome, error)

Run implements prompt, then checks the work and feeds failures back until the checks pass, the implementer stops changing anything, or attempts run out. The returned error is for a step that could not run, not for checks that failed; the outcome so far is returned with it.

type Outcome

type Outcome struct {
	Result Result
	// Rounds is how many rounds were checked.
	Rounds int
	Change Change
	// Checks are the last round's checks.
	Checks []Check
}

Outcome is the end state of a loop.

type PromptSource added in v0.7.218

type PromptSource struct {
	Prompts []review.Prompt
	// Owner, Repo and Commit make a link to a prompt's file. Without all three
	// the checks are listed without links.
	Owner, Repo, Commit string
	// Dir is the prompts' directory relative to the project root, "" for the
	// default.
	Dir string
}

PromptSource says where a pull request's review prompts can be read: which prompts ran, and how to link to them at the commit the pull request shows.

type Record added in v0.7.204

type Record struct {
	RunID string `json:"run_id"`
	// Prompt is the original request. A continued run keeps it, so a chain of
	// runs is all one change.
	Prompt string `json:"prompt"`
	// SpecOrigin is the path Prompt was read from, when it named a file rather
	// than being literal text. A continued run keeps it along with Prompt.
	SpecOrigin string `json:"spec_origin,omitempty"`
	Worktree   string `json:"worktree"`
	Branch     string `json:"branch"`
	Baseline   string `json:"baseline"`
	Head       string `json:"head"`
	// Brief is what a run continuing this one tells its implementer about the
	// work, when whoever made the record knows better than the default: that
	// an earlier session started it and did not finish.
	Brief string `json:"brief,omitempty"`
	// NeedsWork means a run continuing this one refuses to start until there
	// is a change in the worktree to refine.
	NeedsWork bool `json:"needs_work,omitempty"`
	// ContinuesRunID is the run this one continued, if it did.
	ContinuesRunID string `json:"continues_run_id,omitempty"`
	// Result and Rounds are how the run ended, once it has.
	Result Result `json:"result,omitempty"`
	Rounds int    `json:"rounds,omitempty"`
	// Remote is where this run is happening, when it is on a per-run sidecar
	// rather than local. A local run never sets it.
	Remote *RemoteRun `json:"remote,omitempty"`
}

Record is what a later run needs to continue a run: the request, and where its work is and what it is measured against. It is kept in the repository's data directory beside the run's worktree, so it outlives the daemon's sessions.

func LoadRecord added in v0.7.204

func LoadRecord(root, runID string) (Record, error)

LoadRecord reads the record of the run runID in the repository at root, falling back to its legacy location, the data directory of the checkout at root.

func Start added in v0.7.211

func Start(ctx context.Context, root string, h Handoff) (Record, error)

Start makes a run's worktree and branch for work handed to the factory, and records it so 'chunk factory build --continue' can refine it. Nothing runs on a sidecar. The worktree starts from the developer's files as they are, as a build's does, with h's diff applied on top as the work so far.

type Relay

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

Relay carries the implementer's workspace to the reviewers through the run's worktree on this machine. Sidecars cannot reach each other, so the implementer's files are pulled into the worktree with rsync and pushed from there to each reviewer the same way the developer's own tree is synced.

A pull mirrors the implementer's files into the worktree with --delete, so the directory must be one chunk owns. It leaves every .git alone, nested ones included: the worktree keeps its own, and the implementer's git config and hooks never reach this machine, where git will run on the files.

func NewRelay

func NewRelay(client *circleci.Client, dir string, status iostream.StatusFunc) *Relay

NewRelay relays through dir, the run's worktree.

func (*Relay) Pull

func (r *Relay) Pull(ctx context.Context, sidecarID, repoPath string) error

Pull mirrors the workspace at repoPath on sidecarID into the worktree.

func (*Relay) Push

func (r *Relay) Push(ctx context.Context, entries []*sidecar.PoolEntry) error

Push mirrors the worktree to each entry's workspace, in parallel. It attempts every entry and reports all that failed.

type RemoteRun added in v0.7.212

type RemoteRun struct {
	SidecarID string `json:"sidecar_id"`
	CommandID string `json:"command_id"`
	HostRepo  string `json:"host_repo"`
}

RemoteRun is where a run that is happening on a per-run sidecar is running, and where that host's checkout of the repository is. It holds no credentials.

type Report added in v0.7.197

type Report struct {
	RunID string
	// Worktree is the run's worktree. It is kept once the implementer has
	// started, and removed, with its branch, if the run failed before that.
	Worktree Worktree
	// Started reports whether the implementer started.
	Started bool
	// Committed reports whether the work was committed on Worktree.Branch.
	Committed bool
	// Stat is the committed work's diff stat against Worktree.Baseline, "" for
	// no changes. StatErr says why it could not be worked out.
	Stat    string
	StatErr error
	// WorktreeRemoved reports that the run ended before the implementer started
	// and its worktree, holding nothing, was removed.
	WorktreeRemoved bool
	Outcome         Outcome
	// KeptSidecars are the sidecars left running with KeepSidecars.
	KeptSidecars []string
	// Log is the path of the run's log, if it kept one.
	Log string
}

Report is what a run left behind.

func Run added in v0.7.197

func Run(ctx context.Context, opts RunOptions) (rep Report, err error)

Run makes the run's worktree and sidecars, runs the loop, and commits the implementer's work on the run's branch. A failure before the loop starts says which step failed; one in the loop is returned as Loop.Run returns it, with the report so far. The work is committed either way once the implementer has started, so it is not lost with the sidecars.

type Result

type Result string

Result is why the loop stopped.

const (
	// ResultPassed means every check passed.
	ResultPassed Result = "passed"
	// ResultExhausted means checks still failed when attempts ran out.
	ResultExhausted Result = "exhausted"
	// ResultStuck means the implementer changed nothing in response to
	// feedback, so another round would review the same code again.
	ResultStuck Result = "stuck"
	// ResultNoChange means the implementer's work is empty: it changed
	// nothing, or reverted everything it had changed.
	ResultNoChange Result = "no_change"
)

Loop results.

type ReviewerTree added in v0.7.197

type ReviewerTree struct {
	Round     int
	SidecarID string
	// Fingerprint is the reviewer's change; Want is the implementer's.
	Fingerprint string
	Want        string
	// Err is why the reviewer's fingerprint could not be read.
	Err error
}

ReviewerTree compares the change one reviewer is about to review with the implementer's, by fingerprint.

func (ReviewerTree) Matches added in v0.7.197

func (t ReviewerTree) Matches() bool

Matches reports whether the reviewer has the implementer's change.

type RunOptions added in v0.7.197

type RunOptions struct {
	// Root is the developer's repository root. The run's worktree is made from
	// it, and the pool's state is kept in it, where the dashboard finds it.
	Root string
	// Prompt is what the implementer is asked to do. A continued run makes its
	// own from Continue, and ignores this.
	Prompt string
	// SpecOrigin is the path Prompt was read from, when it named a file rather
	// than being literal text. A continued run keeps the earlier run's
	// instead, and ignores this.
	SpecOrigin string
	// Continue, when set, picks up the work of an earlier run instead of
	// starting from the developer's files.
	Continue *Continuation
	// Attempts is the most rounds to check. A continued run that checks the
	// work first counts that round as one of them.
	Attempts int
	// Reviewers is how many reviewer sidecars to run; see ReviewerCount.
	Reviewers int
	Prompts   []review.Prompt
	Commands  []config.Command

	Client *circleci.Client
	OrgID  string
	Image  string
	// KeepSidecars leaves the sidecars running when the run ends.
	KeepSidecars bool

	Credential              claudecode.Credential
	BaseURL                 string
	Model                   string
	ImplementerInstructions string
	ImplementTimeout        time.Duration
	ReviewTimeout           time.Duration

	// Exec runs commands on the sidecars; sidecar.ClientExec when nil.
	Exec sidecar.Execer

	// Log is where to keep a plain-text log of the run, with its full context
	// whatever a display of it filters out: a path, LogDefault for
	// DefaultLogPath, or "" for none.
	Log string
	// Verbose adds the review prompts, the output of commands that passed,
	// and a check each round that every reviewer has the implementer's change
	// to the log. It implies a log.
	Verbose bool

	// Status reports progress, warnings included. It must be set.
	Status iostream.StatusFunc
	// The rest report what the run is doing, and may be nil. OnStart is
	// called once the run's worktree exists.
	OnStart    func(runID string, wt Worktree)
	OnEvent    func(Event)
	OnActivity func(claudecode.Activity)
	// Warm is sidecars made ahead of a continued run, which it uses instead
	// of making its own when they are for the run it continues. The run owns
	// them from then on.
	Warm             *WarmPool
	OnReviewProgress func(review.ProgressEvent)
	OnCheckStart     func(name string)
	OnCheck          func(Check)
}

RunOptions is one factory run. Everything that needs a person, such as picking an org or finding a credential, is settled before it.

type Sidecars

type Sidecars struct {
	Exec        sidecar.Execer
	Implementer *Implementer
	// Acquire and Release hand out reviewer sidecars: the pool's own, with the
	// implementer's member already checked out.
	Acquire func(context.Context) (*sidecar.PoolEntry, error)
	Release func(*sidecar.PoolEntry)
	// Reviewers are the members the implementer's tree is relayed to. When
	// WaitReviewers is set, it supplies them instead, once the first round's
	// checks need them.
	Reviewers []*sidecar.PoolEntry
	// WaitReviewers waits for the rest of the pool and returns its members
	// other than the implementer. The implementer starts as soon as its own
	// member is ready; nothing needs the reviewers until there is work to
	// check, and by then they have usually been ready a while.
	WaitReviewers func(context.Context) ([]*sidecar.PoolEntry, error)
	Relay         *Relay
	// Request is the original change the implementer was asked to make. It is
	// included in every review, including rounds where the implementer is sent
	// only feedback from the preceding checks.
	Request  string
	Prompts  []review.Prompt
	Review   review.Options
	Commands []config.Command
	// OnCheckStart is called with a validation command's name as it starts.
	OnCheckStart func(name string)
	// OnCheck is called as each validation command finishes. Reviews report
	// their progress through Review.ProgressFn.
	OnCheck func(Check)
	// BeforeValidate, when set, is waited for before the validation commands
	// run, such as commands warming up the implementer's sidecar that must
	// not overlap them.
	BeforeValidate func(context.Context) error
	// OnReviewerTree, when set, is called each round for every reviewer, in
	// Reviewers order, with whether the change it is about to review is the
	// implementer's. It is a canary for the relay; a mismatch does not stop the
	// round.
	OnReviewerTree func(ReviewerTree)
	// contains filtered or unexported fields
}

Sidecars runs the loop's steps on a pool of sidecars: the implementer writes code on the member it holds for the whole run, which also runs validation, and each review runs on another member the implementer's tree is relayed to.

func (*Sidecars) Check

func (s *Sidecars) Check(ctx context.Context, round int) ([]Check, error)

Check relays the implementer's tree to the reviewers, then runs the reviews there and validation on the implementer at the same time.

func (*Sidecars) Collect

func (s *Sidecars) Collect(ctx context.Context) (Change, error)

Collect describes the implementer's work so far.

func (*Sidecars) Implement

func (s *Sidecars) Implement(ctx context.Context, prompt string) (Turn, error)

Implement runs one implementer turn.

func (*Sidecars) Prepare

func (s *Sidecars) Prepare(ctx context.Context) error

Prepare commits the tree the pool synced to every member, the worktree's, as the baseline the implementer's work is measured against. Reviewers get theirs before the first review; see prepareReviewers.

func (*Sidecars) Pull added in v0.7.197

func (s *Sidecars) Pull(ctx context.Context) error

Pull brings the implementer's work so far into the worktree. Check does it every round; this is for the way out, after a turn that failed or a round that stopped short of checking.

type Status

type Status string

Status is how a check came out.

const (
	// StatusPassed means the check ran and found nothing to fix.
	StatusPassed Status = "passed"
	// StatusFailed means the check ran and found something the implementer
	// must fix: review findings, or a validation command exiting non-zero.
	StatusFailed Status = "failed"
	// StatusErrored means the check could not run, such as a review that timed
	// out. It says nothing about the code, so it is not fed back.
	StatusErrored Status = "errored"
)

Check statuses.

type Steps

type Steps interface {
	// Implement runs one implementer turn with prompt.
	Implement(ctx context.Context, prompt string) (Turn, error)
	// Collect describes the implementer's work so far.
	Collect(ctx context.Context) (Change, error)
	// Check reviews and validates the implementer's work so far.
	Check(ctx context.Context, round int) ([]Check, error)
}

Steps are the operations one round of the loop is made of. Sidecars implements them against real sidecars; tests implement them in memory.

type Turn

type Turn struct {
	Summary  string
	Duration time.Duration
	CostUSD  float64
}

Turn is the outcome of one implementer turn.

func FirstPass added in v0.7.217

func FirstPass(ctx context.Context, rec Record, model string, onActivity func(claudecode.Activity)) (Turn, error)

FirstPass has Claude Code make a first pass at a started run's prompt in its worktree, on the developer's machine with their own claude login, for a developer who fires the prompt from chunk rather than an agent of their own, with model, or the developer's default when it is "". Edits in the worktree are accepted; anything else is up to the developer's own Claude Code permissions, since no one is there to approve it. The work is left uncommitted, where 'chunk factory build --continue' picks it up.

type WarmPool added in v0.7.217

type WarmPool struct {
	// RunID is the started run the sidecars are for.
	RunID string
	// Reviewers, OrgID and Image are what the sidecars were made with. A run
	// that wants other ones does not use them.
	Reviewers    int
	OrgID, Image string
	// contains filtered or unexported fields
}

WarmPool is the sidecars a run continuing a started run would use, made before that run starts. Starting sidecars takes the better part of a minute; made while the work in the started run is still being done, they are ready by the time it is handed to the factory.

A continued run's sidecars start from the started run's baseline, not its work, which the run lays on the implementer's afterwards. The baseline is fixed when the run is started, so the sidecars can be made from it while the worktree is still changing: they are synced from a checkout of the baseline of their own.

func NewWarmPool added in v0.7.217

func NewWarmPool(ctx context.Context, client *circleci.Client, root string, rec Record, reviewers int, orgID, image string, status iostream.StatusFunc) (*WarmPool, error)

NewWarmPool makes the sidecars a run continuing rec would use, for reviewers reviewers, from a checkout of rec's baseline beside its record.

func (*WarmPool) Claimed added in v0.7.217

func (w *WarmPool) Claimed() bool

Claimed reports whether a run took the sidecars, which are then the run's to delete.

func (*WarmPool) Discard added in v0.7.217

func (w *WarmPool) Discard(ctx context.Context) error

Discard deletes the sidecars of a warm pool no run used, and the checkout they were made from.

func (*WarmPool) Fits added in v0.7.217

func (w *WarmPool) Fits(reviewers int, orgID, image string) bool

Fits reports whether a run with these reviewers, organization and image can use the sidecars.

func (*WarmPool) WarmUp added in v0.7.217

func (w *WarmPool) WarmUp(ctx context.Context, exec sidecar.Execer, cmds []config.Command, status iostream.StatusFunc) error

WarmUp checks out the member the run's implementer will hold and runs cmds, the run's validation commands, on it once in the background (the first alone, then the rest at once), keeping none of their results: what they leave behind (build and lint caches, installed dependencies) makes the run's own first checks quick rather than cold. The run's implementer starts alongside them, and its checks wait for them, so the checks never overlap them.

type Worktree added in v0.7.197

type Worktree struct {
	Path   string
	Branch string
	// Baseline is the commit the branch starts from: the developer's HEAD, or
	// their uncommitted work committed on top of it.
	Baseline string
	// Head is the developer's HEAD when the run started. It differs from
	// Baseline when their uncommitted work was committed as the baseline.
	Head string
}

Worktree is a run's local checkout: a git worktree of the developer's repository on a branch of its own. The implementer's work is pulled into it each round, so the developer's own checkout is never touched and they can look at the work while the run goes.

func CreateWorktree added in v0.7.197

func CreateWorktree(ctx context.Context, root, path, runID, prompt string) (Worktree, error)

CreateWorktree checks out a new worktree of the repository at root into path, on a branch named chunk/factory/<prompt slug>/<runID>. It starts from the developer's files as they are now: uncommitted work, untracked files included, is committed on the branch first, so it is the baseline and not part of the change under review.

func (Worktree) Commit added in v0.7.197

func (w Worktree) Commit(ctx context.Context, message string) (string, error)

Commit commits everything in the worktree to its branch and returns the commit, or "" when nothing changed. The worktree is left in place for the developer to carry on in. Hooks and signing are skipped: the run cannot answer a prompt, and the work has already been checked.

func (Worktree) Push added in v0.7.212

func (w Worktree) Push(ctx context.Context, remote string) error

Push publishes the worktree's branch to remote and makes it the branch's upstream. It never asks for a credential, as the daemon has no terminal to ask on: one git cannot find fails the push with git's own explanation. Hooks are skipped, as for Commit: the work has already been checked.

func (Worktree) Remove added in v0.7.197

func (w Worktree) Remove(ctx context.Context, root string) error

Remove deletes the worktree and its branch, for a run that ended before the implementer did anything. Nothing is lost: the baseline is the developer's own files, still in their checkout.

func (Worktree) Stat added in v0.7.197

func (w Worktree) Stat(ctx context.Context) (string, error)

Stat is git's one-line summary of the branch's work since the baseline, such as "3 files changed, 40 insertions(+)", or "" when there is none.

func (Worktree) Tip added in v0.7.218

func (w Worktree) Tip(ctx context.Context) (string, error)

Tip is the commit the worktree's branch is at now.

Directories

Path Synopsis
Package eval scores a directory of review prompts against a suite of changes whose problems are known, so prompts can be compared by what they catch and what they send back that they should not.
Package eval scores a directory of review prompts against a suite of changes whose problems are known, so prompts can be compared by what they catch and what they send back that they should not.

Jump to

Keyboard shortcuts

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