worktree

package
v0.36.0 Latest Latest
Warning

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

Go to latest
Published: Jun 7, 2026 License: MIT Imports: 10 Imported by: 0

README

runtime/worktree/

Per-session git worktree provisioning + teardown for the agent runner.

What it does

m, _ := worktree.NewManager(worktree.Options{
    ParentDir:       "/var/lib/rensei/wt",
    OwnershipProber: afclient.GetSessionOwnership,
})
path, err := m.Provision(ctx, worktree.ProvisionSpec{
    SessionID: "sess-123",
    RepoURL:   "git@github.com:org/repo.git",
    Branch:    "main",
    Strategy:  worktree.StrategyClone,
})
// ... agent runs in `path` ...
m.Teardown(ctx, "sess-123")

Strategies

  • StrategyClonegit clone --branch <b> <repo> <dst>. Fully isolated session; one full repo per session.
  • StrategyWorktreeAddgit worktree add -B <b> <dst> origin/<b> off an existing parent clone. Cheaper for many concurrent sessions.

Retry contract (verbatim port from legacy TS)

  • MaxSpawnRetries = 3
  • SpawnRetryDelay = 15s
  • Retriable errors: already checked out, Agent already running, Agent is still running, already exists. Anything else fails fast.
  • Before each retry: OwnershipProber is consulted. If the platform reports another worker now owns this session, Provision returns ErrLostOwnership immediately — no further retries, no further git work.

Tests

  • manager_test.go — unit tests with stub CommandRunner (no real git). Covers happy path, retry-then-succeed, lost-ownership, non-retriable, exhausted retries, ctx-cancel, both strategies.
  • integration_test.go (build tag runtime_integration) — bare-repo fixture exercises real git clone against a temp repo.

Failure modes

Scenario Behavior
Branch already checked out Cleanup conflict + retry up to MaxSpawnRetries.
Ownership lost mid-retry ErrLostOwnership; runner halts.
Repo URL invalid Non-retriable; fail-fast on first attempt.
ctx cancelled during retry wait ctx.Err() propagated.
Teardown on unknown session No-op (idempotent).

Source

  • manager.goManager, Provision, Teardown, Path.
  • Legacy reference: ../../../agentfactory/packages/core/src/workarea/git-worktree.ts + ../../../agentfactory/packages/cli/src/lib/worker-runner.ts:884-1000.

Documentation

Overview

Package worktree provisions and tears down per-session git worktrees for the agent runner.

Per F.1.1 §1, the runner clones a parent repository under a daemon- configured directory and then either (a) clones a fresh sibling for each session or (b) creates a `git worktree add` off the parent. Both strategies are supported via CloneStrategy. The retry contract mirrors the legacy TS git-worktree.ts:

  • MaxSpawnRetries = 3
  • SpawnRetryDelay = 15s
  • Before each retry, the platform-side session ownership is probed; if another worker has claimed the session, Provision returns ErrLostOwnership without burning further retries.

The package does not own the platform API contract — it accepts an OwnershipProber callback so unit tests can stub the probe and production code can wire the real afclient.GetSession lookup.

Index

Constants

View Source
const MaxSpawnRetries = 3

MaxSpawnRetries is the maximum number of attempts Provision will make before failing. Mirrors MAX_SPAWN_RETRIES in the legacy TS worker-runner.ts.

View Source
const SpawnRetryDelay = 15 * time.Second

SpawnRetryDelay is the wait between Provision attempts. Mirrors SPAWN_RETRY_DELAY_MS in the legacy TS.

Variables

View Source
var (
	// ErrLostOwnership is returned by Provision when the OwnershipProber
	// reports that another worker has claimed this session between
	// retry attempts. The runner halts work without further retries.
	ErrLostOwnership = errors.New("runtime/worktree: ownership lost during retry")

	// ErrUnknownSession is returned by Path when the session id has
	// no recorded worktree.
	ErrUnknownSession = errors.New("runtime/worktree: unknown session id")

	// ErrNoParentDir is returned by Provision when the manager has no
	// ParentDir configured and the strategy needs one.
	ErrNoParentDir = errors.New("runtime/worktree: no parent directory configured")
)

Sentinel errors callers may type-check via errors.Is.

Functions

This section is empty.

Types

type CloneStrategy

type CloneStrategy int

CloneStrategy selects the underlying git operation Provision uses to materialize a worktree directory.

const (
	// StrategyClone runs `git clone` into a fresh directory. Used when
	// no parent worktree exists yet, or when the daemon is configured
	// to keep sessions fully isolated.
	StrategyClone CloneStrategy = iota
	// StrategyWorktreeAdd runs `git worktree add` off an existing
	// parent clone. Cheap and ideal when many sessions share a
	// long-lived parent under the daemon's clone directory.
	StrategyWorktreeAdd
)

func (CloneStrategy) String

func (s CloneStrategy) String() string

String returns a stable name for the strategy — used in log lines and error messages.

type CommandRunner

type CommandRunner func(ctx context.Context, name string, args ...string) ([]byte, error)

CommandRunner abstracts process execution for tests. The default implementation is exec.CommandContext + cmd.CombinedOutput().

type Manager

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

Manager owns the lifecycle of per-session worktrees. The zero value is unusable; build via NewManager.

Concurrency: the Manager serializes Provision/Teardown for the same session id but allows different sessions to run in parallel.

func NewManager

func NewManager(opts Options) (*Manager, error)

NewManager returns a Manager configured by opts.

func (*Manager) ParentDir

func (m *Manager) ParentDir() string

ParentDir returns the absolute path of the manager's parent directory.

func (*Manager) Path

func (m *Manager) Path(sessionID string) (string, error)

Path returns the worktree path for a previously-provisioned session. Returns ErrUnknownSession when the session id is not tracked.

func (*Manager) Provision

func (m *Manager) Provision(ctx context.Context, spec ProvisionSpec) (string, error)

Provision creates a worktree for the session, retrying up to MaxSpawnRetries times with SpawnRetryDelay between attempts. Before each retry, OwnershipProber (if set) is consulted; ownership lost short-circuits with ErrLostOwnership.

Returns the worktree path on success.

func (*Manager) Teardown

func (m *Manager) Teardown(ctx context.Context, sessionID string) error

Teardown removes the session's worktree. Idempotent when the session is unknown — returns nil.

type Options

type Options struct {
	// ParentDir is the daemon-controlled directory under which
	// per-session worktrees are created. Required.
	ParentDir string
	// Logger overrides slog.Default().
	Logger *slog.Logger
	// OwnershipProber is invoked between retries; nil disables the
	// ownership check (useful for unit tests with no platform).
	OwnershipProber OwnershipProber
	// CommandRunner overrides the default exec.CommandContext runner.
	CommandRunner CommandRunner
	// RetryDelay overrides SpawnRetryDelay. Useful for tests.
	RetryDelay time.Duration
}

Options configures NewManager. ParentDir is required.

type OwnershipProber

type OwnershipProber func(ctx context.Context, sessionID string) (owned bool, err error)

OwnershipProber is the runner-supplied callback Provision uses to confirm session ownership before each retry. Implementations typically call afclient.GetSession and compare OwnerWorkerID to the daemon's local id. Returning (false, nil) means "lost"; an error is treated as "transient — keep retrying".

type ProvisionResult

type ProvisionResult struct {
	// Path is the absolute worktree path on disk.
	Path string
	// Strategy is the strategy that succeeded.
	Strategy CloneStrategy
	// Attempts is the number of attempts taken (1 on success first try).
	Attempts int
}

ProvisionResult is the per-session bookkeeping the manager records. Returned alongside the worktree path for callers that need both.

type ProvisionSpec

type ProvisionSpec struct {
	// SessionID is the platform session UUID — also the
	// worktree-directory leaf name.
	SessionID string
	// RepoURL is the git URL (or local path) to clone from. Required
	// for StrategyClone; may be empty for StrategyWorktreeAdd when
	// ParentRepoPath is set.
	RepoURL string
	// Branch is the branch to check out. Empty falls back to the
	// remote default branch.
	Branch string
	// Strategy selects clone vs worktree-add.
	Strategy CloneStrategy
	// ParentRepoPath is the existing parent clone for
	// StrategyWorktreeAdd. Empty defaults to ParentDir/<repo-leaf>.
	ParentRepoPath string
	// LeafName overrides the directory name under ParentDir. Empty
	// defaults to SessionID.
	LeafName string
}

ProvisionSpec is one Provision call's input.

Jump to

Keyboard shortcuts

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