fleet

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Aug 15, 2026 License: MIT Imports: 25 Imported by: 0

Documentation

Overview

Package fleet turns an operator's plan into a working agent team.

The generating model NEVER writes files. It proposes a manifest; this package validates it and writes the tree. Two reasons that split matters:

  • `.claude/` is a protected path. Writes there are not auto-approved in default or acceptEdits mode and are denied outright in dontAsk, and `permissions.allow` does not pre-approve them. Making it work would mean granting bypassPermissions to a session that just ingested an untrusted operator plan.
  • Writing from Go makes the namespace contract mechanical: every generated file is recorded, so a later regeneration can tell its own output from something a human edited.

Index

Constants

View Source
const (
	// MaxPlanIssues caps how many issues one plan may spawn. A vague plan can
	// decompose into fifty items, which is fifty body sessions and a board
	// full of half-guessed work — a bill and a backlog nobody agreed to. The
	// cap is exported so the wizard can name it when reporting that it bit;
	// silent truncation would leave the operator believing the plan produced
	// exactly what they see.
	MaxPlanIssues = 15
)
View Source
const RosterBudget = rosterTimeout + 5*time.Minute

RosterBudget is how long a caller should allow phase 1 before concluding it hung: the session's own cap plus margin for spawn and parse.

Variables

This section is empty.

Functions

func PhaseBudget added in v0.1.1

func PhaseBudget(remaining int) time.Duration

PhaseBudget is how long a caller should allow the write phase given how many items REMAIN. It budgets remaining work, not the whole run: the wizard re-arms its watchdog with this on every completion, so a big fleet earns time by making progress while a hung one still dies within a single wave.

Types

type AgentSpec

type AgentSpec struct {
	Slug        string `json:"slug"`
	DisplayName string `json:"display_name"`
	// Description is the delegation trigger — it is what the router matches on,
	// so a vague one makes the agent unreachable.
	Description string   `json:"description"`
	Role        string   `json:"role"`  // orchestrator | builder | advisor | reviewer
	Model       string   `json:"model"` // haiku | sonnet | opus | inherit
	Areas       []string `json:"areas"`
	Tools       []string `json:"tools"`
	Skills      []string `json:"skills"`
	Persona     string   `json:"persona"` // the system prompt body, markdown
}

type AgentsService

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

func NewAgentsService

func NewAgentsService(db *sql.DB, log *slog.Logger) *AgentsService

func (*AgentsService) Routes

func (s *AgentsService) Routes(r chi.Router)

type Generator

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

Generator turns a plan into a fleet.

func NewGenerator

func NewGenerator(db *sql.DB, log *slog.Logger, root string) *Generator

func (*Generator) Generate

func (g *Generator) Generate(ctx context.Context, fleetName, plan, model string, onProgress Progress) (*Manifest, float64, error)

Generate runs both phases, writes the tree and persists the fleet.

Durability contract: the roster is persisted the moment it is decided, and every persona and skill body the moment its session returns. A run that dies at agent 20 of 27 leaves 20 personas in the database, and the next call with the same plan resumes at agent 21 — it re-runs neither the roster session (re-deciding could produce a different team than the personas already written) nor anything already on file. Pressing Generate twice is free.

func (*Generator) GenerateIssues added in v0.1.1

func (g *Generator) GenerateIssues(ctx context.Context, fleetName, plan string, onProgress Progress) (created, dropped int, spent float64, err error)

GenerateIssues breaks the plan into board issues assigned to the fleet.

Durability contract, same as Generate: the decided list is persisted as skeleton rows the moment phase 1 returns, and each body the moment its session returns. A re-run with the same plan re-buys nothing that is already on file — pressing the button twice is free, and a run that died partway resumes at the first missing body.

Every issue lands human_only = true and source = 'import': plan-derived work should be read by a person before agents spend on it, and the board must be able to say which issues a plan produced versus what a human filed. Issues whose area matches an agent's declared areas land 'ready', assigned; an area nobody owns lands in 'triage', unassigned — handing it to whoever looks nearest is how an agent ends up editing a surface it does not own.

Returns how many issues the plan produced on the board and how many the cap dropped; dropped > 0 must reach the operator, not just the log.

type Manifest

type Manifest struct {
	Summary string      `json:"summary"`
	Agents  []AgentSpec `json:"agents"`
	Skills  []SkillSpec `json:"skills"`
	Notes   []string    `json:"notes,omitempty"`
}

Manifest is what the generator returns.

func (*Manifest) Validate

func (m *Manifest) Validate() []string

Validate normalizes the manifest and reports every problem at once, so a regeneration prompt can be given the full list rather than one error per round.

func (*Manifest) Write

func (m *Manifest) Write(root string) ([]WrittenFile, error)

Write renders the manifest into `<root>/.claude/`.

Generated files land in their own namespace and are recorded in manifest.json, so a later run can distinguish its own previous output from a file a human has since edited — and never clobber the latter.

type Progress

type Progress func(stage string, done, total int, spentUSD float64)

Progress is reported back to the wizard as the phases advance, so a run that takes ten minutes does not look like a hang.

spentUSD is included because a ten-minute run showing $0.00 throughout gives the operator no way to tell a cheap run from an expensive one until it is over — by which point the money is spent.

type SkillSpec

type SkillSpec struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Body        string `json:"body"`
}

type WrittenFile

type WrittenFile struct {
	Path   string `json:"path"`
	SHA256 string `json:"sha256"`
	Owner  string `json:"owner"`
}

WrittenFile records one file the generator produced.

Jump to

Keyboard shortcuts

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