autopilot

package
v0.22.152 Latest Latest
Warning

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

Go to latest
Published: May 2, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package autopilot — self-direction backlog primitive that lets a Claude Code agent (the operator's clawtool driver) pull "what to work on next" without requiring the human to re-prompt every turn. The user calls this "devam edebilme yeteneği" — continuation ability / non-stalling.

Pattern: classic single-producer-multi-consumer task queue persisted as TOML. The operator (or the agent itself) appends items via AutopilotAdd; the agent dequeues via AutopilotNext, does the work, marks done via AutopilotDone, then loops. When Claim() returns ok=false the queue is empty and the agent ends the loop.

Why this is NOT BIAM/SendMessage: BIAM is agent-to-agent dispatch (codex / gemini / opencode). Autopilot is self-work — the SAME agent picking up its own backlog. Pre-this primitive an agent that finished a task either (a) stalled waiting for operator input, or (b) re-invented a TODO list in its scratchpad on every session.

Storage: a TOML file at $XDG_CONFIG_HOME/clawtool/autopilot/queue.toml (defaults to ~/.config/clawtool/autopilot/queue.toml). Per-host, not per-repo, so a backlog the operator wrote at lunch is still there when they reopen Claude Code in the evening. Atomic writes via internal/atomicfile so a crashed mid-rewrite never corrupts the queue.

Concurrency: Claim() takes an exclusive lock on the file (load → mutate → save under one rwmu acquisition). Two parallel "next" calls from a fanned-out agent will not return the same item — the tests pin this invariant.

Index

Constants

This section is empty.

Variables

View Source
var ErrAlreadyAccepted = errors.New("autopilot: item already accepted")

ErrAlreadyAccepted is returned by Accept when the item is already pending or in_progress — i.e. has already passed the operator gate. Callers ignore for idempotency.

View Source
var ErrAlreadyTerminal = errors.New("autopilot: item already in terminal state")

ErrAlreadyTerminal is returned by Complete / Skip / Accept when the item is already done or skipped. Callers can ignore for idempotency.

View Source
var ErrDuplicateProposal = errors.New("autopilot: duplicate proposal")

ErrDuplicateProposal is returned by Propose when an existing non-terminal item shares the supplied DedupeKey. The Ideator passes through this as a "deduped" tally rather than a real error.

View Source
var ErrNotFound = errors.New("autopilot: item not found")

ErrNotFound is returned by Complete / Skip / Accept when no item matches the given id.

Functions

func DefaultPath

func DefaultPath() string

DefaultPath returns the canonical autopilot queue file: $XDG_CONFIG_HOME/clawtool/autopilot/queue.toml.

Types

type Counts

type Counts struct {
	Proposed   int `json:"proposed"`
	Pending    int `json:"pending"`
	InProgress int `json:"in_progress"`
	Done       int `json:"done"`
	Skipped    int `json:"skipped"`
	Total      int `json:"total"`
}

Counts represents the queue's status histogram. Returned by Status.

type Item

type Item struct {
	ID         string    `toml:"id" json:"id"`
	Prompt     string    `toml:"prompt" json:"prompt"`
	Priority   int       `toml:"priority" json:"priority"`
	Status     Status    `toml:"status" json:"status"`
	CreatedAt  time.Time `toml:"created_at" json:"created_at"`
	ClaimedAt  time.Time `toml:"claimed_at,omitempty" json:"claimed_at,omitempty"`
	DoneAt     time.Time `toml:"done_at,omitempty" json:"done_at,omitempty"`
	AcceptedAt time.Time `toml:"accepted_at,omitempty" json:"accepted_at,omitempty"`
	Note       string    `toml:"note,omitempty" json:"note,omitempty"`
	Source     string    `toml:"source,omitempty" json:"source,omitempty"`
	Evidence   string    `toml:"evidence,omitempty" json:"evidence,omitempty"`
	DedupeKey  string    `toml:"dedupe_key,omitempty" json:"dedupe_key,omitempty"`
}

Item is one unit of self-work. Field names map directly to TOML keys; preserve them when adding fields so existing queues survive rolling upgrades.

Source / Evidence / DedupeKey are populated by the Ideator when the item is Proposed; operator-added items leave them empty. They stay attached through Accept so the eventual completion note can reference the originating signal (e.g. "TODO at foo.go:42").

type ProposeInput added in v0.22.119

type ProposeInput struct {
	Prompt    string
	Priority  int
	Note      string
	Source    string
	Evidence  string
	DedupeKey string
}

ProposeInput is the wire shape Ideator hands the queue. Fields mirror Item but only the ones a freshly-minted suggestion needs; status is forced to StatusProposed regardless of caller intent so the operator's Accept gate is the only path into pending.

type Queue

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

Queue is a TOML-backed self-direction backlog. Construct with Open or OpenAt. Operations are concurrency-safe via an internal mutex; multiple Queue instances pointing at the same path serialize through the file system (atomicfile rename + every mutation does a fresh load).

func Open

func Open() *Queue

Open returns a Queue rooted at the default path.

func OpenAt

func OpenAt(path string) *Queue

OpenAt returns a Queue rooted at the supplied path. Tests use this to redirect into a tmpdir.

func (*Queue) Accept added in v0.22.119

func (q *Queue) Accept(id, note string) (Item, error)

Accept flips a proposed item to pending so AutopilotNext can claim it. This is the operator's safety gate — without an explicit Accept no Ideator output ever reaches the agent's working queue.

Errors: ErrNotFound (unknown id); ErrAlreadyTerminal (item is already done/skipped); ErrAlreadyAccepted (item is already pending, in_progress, or terminal — Accept is idempotent only on proposed).

func (*Queue) Add

func (q *Queue) Add(prompt string, priority int, note string) (Item, error)

Add appends a new pending item. id is auto-generated when empty. Returns the persisted Item (with id + created_at filled).

func (*Queue) Claim

func (q *Queue) Claim() (Item, bool, error)

Claim returns the highest-priority pending item, marks it in_progress, and persists. ok=false (zero Item, nil err) when the queue has no pending items — the agent's signal to stop the loop.

Selection order: highest Priority first, then earliest CreatedAt. Ties broken by lexicographic ID for determinism in tests.

func (*Queue) Complete

func (q *Queue) Complete(id, note string) (Item, error)

Complete marks the named item done. Idempotent: completing an already-done item returns a typed error so the caller can decide whether to ignore it. Unknown id returns ErrNotFound.

func (*Queue) List

func (q *Queue) List(filter Status) ([]Item, error)

List returns every item filtered by status. Pass empty string to return all. Order: pending first (priority/created), then in_progress, then done/skipped.

func (*Queue) Path

func (q *Queue) Path() string

Path returns the queue's file path.

func (*Queue) Propose added in v0.22.119

func (q *Queue) Propose(in ProposeInput) (Item, error)

Propose appends a new proposed item — the Ideator's output. The item is NOT claimable by AutopilotNext until an operator runs Accept (CLI: `clawtool autopilot accept <id>`). Returns ErrDuplicateProposal when DedupeKey collides with an existing non-terminal proposed/pending/in_progress item — callers can ignore for idempotency.

func (*Queue) Skip

func (q *Queue) Skip(id, note string) (Item, error)

Skip marks the named item skipped. Same shape as Complete.

func (*Queue) Status

func (q *Queue) Status() (Counts, error)

Status returns the histogram of items by status.

type Status

type Status string

Status enumerates the lifecycle of one backlog Item. The set is closed: anything outside this list is a programmer error.

const (
	StatusProposed   Status = "proposed"    // Ideator-emitted suggestion; needs operator Accept before Claim picks it up
	StatusPending    Status = "pending"     // freshly added (or accepted), not yet claimed
	StatusInProgress Status = "in_progress" // returned by Claim, not yet completed
	StatusDone       Status = "done"        // Complete() called
	StatusSkipped    Status = "skipped"     // Skip() called — operator told the agent to drop it
)

Jump to

Keyboard shortcuts

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