Documentation
¶
Overview ¶
Package zzz drives an autonomous overnight loop: clean-git-check → engine.Run → if tree changed, ONE commit; on any failure, git reset --hard back to last known good. Inspired by gnhf (github.com/kunchenguid/gnhf). Wakes you up to a branch full of individually-revertable commits and a notes.md log of every step.
Index ¶
- Constants
- func AcquireLock(workdir, runID string) (func(), error)
- func AddAll(dir string) error
- func AppendEvent(id string, ev Event) error
- func AppendNote(id string, iter int, subject, body string) error
- func CleanFD(dir string) error
- func Commit(dir, msg string, sign, noVerify bool) (string, error)
- func CommitAll(dir, msg string, sign, noVerify bool) (string, error)
- func CommitMessageFrom(finalText string, iter, inTok, outTok int) string
- func CreateBranchAndSwitch(dir, name string) error
- func CurrentBranch(dir string) (string, error)
- func DiffStat(dir, ref string) (string, error)
- func Drive(ctx context.Context, stopCh <-chan struct{}, eng Runner, cfg Config, run *Run, ...) (retErr error)
- func Fetch(dir, remote string) error
- func HasBranch(dir, name string) bool
- func HeadSHA(dir string) (string, error)
- func HomeDir() (string, error)
- func IsClean(dir string) (bool, error)
- func IsRebasing(dir string) bool
- func LoadPrompt(id string) (string, error)
- func MergeFF(dir, base, branch string) error
- func NewID() string
- func Push(dir, branch string) error
- func ReadNotes(id string) (string, error)
- func Rebase(dir, onto string) error
- func RebaseAbort(dir string) error
- func RepoRoot(dir string) (string, error)
- func ResetHard(dir, ref string) error
- func RunDir(id string) (string, error)
- func SaveBlockedPatch(id string, iter int, dir string) error
- func SaveMeta(r *Run) error
- func SavePrompt(id, objective string) error
- func TailNoteSections(notes string, n int) string
- func WorktreeAdd(repoRoot, path, branch string) error
- func WorktreeDir(id string) (string, error)
- func WorktreeRemove(repoRoot, path string, force bool) error
- type Config
- type Event
- type IterationResult
- type PruneOpts
- type PruneResult
- type Run
- type Runner
- type Status
- type Steer
- type Steerable
- type TokenStat
- type UI
Constants ¶
const ( StatusRunning = "running" StatusCompleted = "completed" StatusFailed = "failed" StatusAborted = "aborted" IterCommitted = "committed" IterReset = "reset" IterFailed = "failed" IterNoop = "noop" ModeBranch = "branch" ModeCurrent = "current" ModeWorktree = "worktree" )
const ( SteerNote = "note" // append text to next prompt SteerStop = "stop" // graceful stop after current iter SteerAbort = "abort" // hard cancel ctx mid-iter )
Variables ¶
This section is empty.
Functions ¶
func AcquireLock ¶ added in v0.1.1
AcquireLock takes an exclusive lock on workdir (a run's RepoRoot — the worktree for worktree runs, the main repo for branch/current runs). It prevents two overnight loops from racing the same git index and prevents a double-resume of the same run. Returns a release func; call it on exit.
A lock left behind by a crashed process is detected via the recorded PID and stolen. On Windows there is no portable liveness probe, so a stale lock is kept (manual removal of ~/.bee/zzz/locks/<key>.lock required) rather than risk stealing a live one.
func AppendEvent ¶
AppendEvent writes one line to events.jsonl.
func AppendNote ¶
AppendNote tacks one section onto notes.md. Used after every iteration so later prompts can see what prior iterations did.
func CleanFD ¶
CleanFD removes untracked files + dirs. Pairs with ResetHard for a full rollback after a failed iteration.
func Commit ¶
Commit creates ONE commit with msg. When sign is false (gnhf parity) the command is invoked with overrides that disable any configured signing — the run does NOT touch the user's git config. Returns the new short sha.
func CommitAll ¶
CommitAll stages every tracked + untracked change and commits in a single git invocation. The atomicity is git's own (index set then commit). Returns the new short sha.
func CommitMessageFrom ¶
CommitMessageFrom builds a conventional commit subject + body. Subject is the first non-empty line of finalText truncated to 70 chars and lowercased "fix:" / "feat:" prefix when missing. Body carries the remainder.
func CreateBranchAndSwitch ¶
CreateBranchAndSwitch creates `name` and checks it out. Errors if it exists.
func CurrentBranch ¶
CurrentBranch returns the active branch name. Detached HEAD returns "HEAD".
func DiffStat ¶
DiffStat returns the one-line `--shortstat` summary for HEAD~1..HEAD. Returns empty string when the commit didn't actually change anything.
func Drive ¶
func Drive(ctx context.Context, stopCh <-chan struct{}, eng Runner, cfg Config, run *Run, ui UI) (retErr error)
Drive is the main overnight loop. Returns nil on a clean exit (objective reached / max-iter / stop signal); error only on unrecoverable failure.
ctx cancel = hard stop (mid-iteration). stopCh closed = graceful stop after current iteration finishes. If ui also satisfies Steerable, operator nudges are drained between iterations: notes get appended to the next prompt, stop closes the local graceful-stop path.
func Fetch ¶
Fetch updates remote-tracking refs. remote defaults to "origin". Best-effort: not having a remote configured is not fatal for local-only flows.
func HomeDir ¶
HomeDir returns ~/.bee/zzz. Created on first call. BEE_HOME overrides ~/.bee (matches bgreg/agents and lets tests stay hermetic on Windows where os.UserHomeDir reads USERPROFILE, not HOME).
func IsRebasing ¶
IsRebasing returns true when a rebase is in progress in dir. Checks for .git/rebase-merge and .git/rebase-apply via git status --porcelain=v2.
func MergeFF ¶
MergeFF fast-forwards branch onto base in dir. dir should be the main repo (not the worktree). Returns error if FF is not possible.
func NewID ¶
func NewID() string
NewID returns a short timestamped id: 20260518-a1b2c3d4. Sortable, unique enough for human-facing dirs, no external deps. UUIDs exist elsewhere in bee but they read poorly in `ls` output for an overnight log dir.
func Rebase ¶
Rebase replays HEAD commits onto onto. Returns the raw error including stderr on conflict so callers can surface it.
func RebaseAbort ¶
RebaseAbort aborts an in-progress rebase. Safe to call when no rebase is active — git exits non-zero but the caller can ignore it.
func SaveBlockedPatch ¶
SaveBlockedPatch dumps the current tracked diff + porcelain status to ~/.bee/zzz/runs/<id>/blocked-<iter>.patch so the operator can inspect what the BLOCKED iteration produced before the run reset the tree. Untracked files are listed by name only (no content) to keep the patch self-explanatory.
func SavePrompt ¶
SavePrompt persists the original objective so resume keeps context. Written atomically (tmp+rename) so a crash mid-write can't leave a truncated objective that a later resume would silently run with.
func TailNoteSections ¶
TailNoteSections returns the last n "## iter " sections of notes. Used to cap prompt growth on long runs — without this, iter N's prompt embeds N prior sections, costing O(n²) tokens across the run. n<=0 returns notes unchanged.
func WorktreeAdd ¶
WorktreeAdd creates a new worktree at path tracking new branch. path MUST NOT exist; git refuses otherwise.
func WorktreeDir ¶
WorktreeDir returns ~/.bee/zzz/worktrees/<id>. NOT created — git worktree add wants a non-existent path.
func WorktreeRemove ¶
WorktreeRemove tears down a worktree. Force flag handles dirty trees.
Types ¶
type Config ¶
type Config struct {
Objective string
MaxIterations int
MaxTokens int // 0 = unlimited
StopWhen string // substring match against FinalText
Worktree bool
CurrentBranch bool // commit on current branch, no auto-create
Push bool // git push after each commit
Sign bool // default false (gnhf parity, avoids overnight prompts)
NoVerify bool // skip pre-commit hooks (opt-in)
// MaxConsecutiveFails ends the run after this many failed iters in a row.
// 0 → default (3). Noop iters do not count.
MaxConsecutiveFails int
// MaxConsecutiveNoops ends the run after this many no-change iters in a row.
// 0 → default (5). Stops a model that only ever surveys from spinning to
// MaxIterations without committing anything.
MaxConsecutiveNoops int
// HardErrorRetries bounds engine.Run retries per iter on transient errors.
// 0 → default (3).
HardErrorRetries int
// NotesTailIters caps how many prior iteration sections are echoed into
// the next prompt. 0 → default (5). Negative → unlimited (legacy).
NotesTailIters int
}
Config is the parsed flag set for one run.
type Event ¶
type Event struct {
Iter int `json:"iter"`
Phase string `json:"phase"`
Time time.Time `json:"time"`
Tokens TokenStat `json:"tokens,omitempty"`
DiffStat string `json:"diff_stat,omitempty"`
Commit string `json:"commit,omitempty"`
Err string `json:"err,omitempty"`
}
Event is one row in events.jsonl.
type IterationResult ¶
type IterationResult struct {
Iter int
Status string // "committed" | "reset" | "failed" | "noop"
Subject string
CommitSHA string
Tokens TokenStat
DiffStat string
Err error
Duration time.Duration
}
IterationResult summarises one pass through the loop.
type PruneOpts ¶
type PruneOpts struct {
MaxAge time.Duration
KeepNewest int
StaleRunningAge time.Duration // 0 → never reap running runs
// IncludeWorktree triggers `git worktree remove` per pruned worktree run.
// MainRepoRoot must be set to the main repo (not a worktree) — git refuses
// to remove a worktree from itself.
IncludeWorktree bool
MainRepoRoot string
}
PruneOpts controls run-directory garbage collection. A run is removed when it satisfies BOTH thresholds — older than MaxAge AND beyond the KeepNewest most recent. Zero values disable the matching threshold:
- MaxAge=0 → age never triggers; only excess beyond KeepNewest removed.
- KeepNewest=0 → count never triggers; only age-based removal.
Only terminal runs (completed, failed, aborted) are candidates. Active runs are always retained, except runs stuck in "running" past StaleRunningAge — those are reaped because they almost always indicate a crashed process that never persisted a terminal status.
type PruneResult ¶
type PruneResult struct {
RemovedRunIDs []string
ReapedStaleRunIDs []string
RemovedWorktreePaths []string
Errors []error
}
PruneResult lists what Prune deleted.
func Prune ¶
func Prune(opts PruneOpts) PruneResult
Prune sweeps ~/.bee/zzz/runs/ removing old terminal runs per opts. With IncludeWorktree, also removes the associated git worktree for each pruned worktree-mode run. StaleRunningAge>0 also reaps "running" runs older than that threshold (process crashed before persisting a terminal status).
type Run ¶
type Run struct {
ID string `json:"id"`
Objective string `json:"objective"`
Branch string `json:"branch"`
Worktree string `json:"worktree,omitempty"`
Mode string `json:"mode"` // "branch" | "current" | "worktree"
RepoRoot string `json:"repo_root"`
StartedAt time.Time `json:"started_at"`
EndedAt time.Time `json:"ended_at,omitempty"`
Status string `json:"status"` // "running" | "completed" | "failed" | "aborted"
IterCount int `json:"iter_count"`
Tokens TokenStat `json:"tokens"`
Commits []string `json:"commits"`
PushedCommits []string `json:"pushed_commits,omitempty"`
PushFailedIters []int `json:"push_failed_iters,omitempty"`
StopCause string `json:"stop_cause,omitempty"`
}
Run is the persisted metadata for one overnight session.
type Runner ¶
type Runner interface {
Run(ctx context.Context, prompt string) (loop.RunResult, error)
CostTotal() cost.Summary
}
Runner is the surface Drive needs from the engine. Real callers wrap *loop.Engine via NewLoopRunner; tests pass a stub.
func NewLoopRunner ¶
NewLoopRunner adapts *loop.Engine to the Runner interface so Drive isn't bound to the concrete engine type.
type Status ¶
type Status struct {
// contains filtered or unexported fields
}
Status drives the single-line live status display + final summary. No TUI — just carriage-return overwrites to stderr so piping stdout still works (the engine's text deltas already go to stdout).
func NewStatus ¶
NewStatus returns a status renderer writing to w. Pass os.Stderr in normal CLI use, io.Discard in tests.
func (*Status) Disable ¶
func (s *Status) Disable()
Disable suppresses live rendering (useful when --json or non-tty).
func (*Status) IncCommits ¶
func (s *Status) IncCommits()
func (*Status) RenderSummary ¶
RenderSummary prints the multi-line exit summary. Called once at end.
type Steer ¶
Steer is one operator command pushed from the UI into Drive between iterations. Free-text falls under SteerNote — it gets appended verbatim to the next iteration's prompt as an "operator nudge" block.
type Steerable ¶
type Steerable interface {
Steer() <-chan Steer
}
Steerable is implemented by UIs that accept mid-run operator input. When Drive holds a UI that also satisfies this interface it drains Steer between iterations: notes get appended to the prompt, stop closes the graceful stop channel.
type TokenStat ¶
type TokenStat struct {
Input int `json:"input"`
Output int `json:"output"`
USD float64 `json:"usd"`
}
TokenStat is the running tally across all iterations.
type UI ¶
type UI interface {
SetIter(n, max int)
SetPhase(p string)
SetTokens(t TokenStat)
IncCommits()
Println(msg string)
RenderSummary(r *Run)
}
UI abstracts the live status sink so Drive can be driven by either the terminal-line Status renderer or a bubbletea TUI. Methods mirror the original *Status surface 1:1 so the existing impl is automatically a UI.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package tui drives the bee-zzz live interface: animated sleeping bee at the footer, moon-phase iteration timeline, transcript pane, and a textarea for steering commands (/stop /abort /note <text>).
|
Package tui drives the bee-zzz live interface: animated sleeping bee at the footer, moon-phase iteration timeline, transcript pane, and a textarea for steering commands (/stop /abort /note <text>). |