Documentation
¶
Overview ¶
Package build orchestrates the coding agent integration.
Index ¶
- Constants
- func AdvanceStep(db *store.DB, session *SessionState) error
- func AllLeavesHaveDraftPR(prSectionContent string) bool
- func LogActivity(specID, entry string) error
- func SaveSession(db *store.DB, session *SessionState) error
- func SessionDir(specID string) string
- func SetActivityDB(db *store.DB)
- func WriteContextFile(ctx *BuildContext, outputPath string) error
- type BuildContext
- type Engine
- type Graph
- type MCPResource
- type MCPServer
- type MCPToolResult
- type NodeState
- type Options
- type PRStep
- type SessionState
- func (s *SessionState) CurrentPRStep() *PRStep
- func (s *SessionState) DoneSet() map[string]bool
- func (s *SessionState) FailedNodes() []string
- func (s *SessionState) InitNodes()
- func (s *SessionState) IsComplete() bool
- func (s *SessionState) MarkNodeComplete(id string)
- func (s *SessionState) MarkNodeFailed(id, reason string)
- func (s *SessionState) NodeStatus(id string) string
- func (s *SessionState) NodesComplete() bool
- func (s *SessionState) SetNodeStatus(id, status string)
Constants ¶
const ( NodePending = "pending" NodeInProgress = "in-progress" NodeComplete = "complete" NodeFailed = "failed" )
Node status values for the per-node ledger.
Variables ¶
This section is empty.
Functions ¶
func AdvanceStep ¶
func AdvanceStep(db *store.DB, session *SessionState) error
AdvanceStep marks the current step as complete and moves to the next. It also mirrors the change into the node ledger so the DAG source of truth stays in sync during the sequential-to-DAG transition.
func AllLeavesHaveDraftPR ¶ added in v0.16.0
AllLeavesHaveDraftPR reports whether every leaf node in a §7.3 PR stack has a recorded draft-PR URL (a `<!-- pr: <url> -->` annotation). It is the verifier behind the pr_stack_exists gate: review may not begin until each stack tip has an open draft PR. prSectionContent is the §7.3 section body.
Returns false when the plan is empty, malformed (not a DAG), has no leaves, or any leaf is missing its PR — so an unbuilt or partially-finished spec never passes the gate.
func LogActivity ¶
LogActivity appends an entry to both the SQLite activity log and the session file.
func SaveSession ¶
func SaveSession(db *store.DB, session *SessionState) error
SaveSession persists a session to the database.
func SessionDir ¶
SessionDir returns the path to the session directory.
func SetActivityDB ¶
SetActivityDB sets the database used for activity logging.
func WriteContextFile ¶
func WriteContextFile(ctx *BuildContext, outputPath string) error
WriteContextFile writes a consolidated context markdown file for non-MCP agents.
Types ¶
type BuildContext ¶
type BuildContext struct {
SpecPath string
SpecContent string
PriorDiffs []string
FailingTests string
Conventions string
CurrentStep PRStep
SystemPrompt string
// Skills holds the resolved skill bodies (Agent Skills markdown). Empty
// when no skills are present under .spec/agent/skills/ or in config.
Skills []string
// SkillPaths is the deduplicated union of skill paths across all DAG nodes,
// passed to skill-capable agents as the set the orchestrator may dispatch.
SkillPaths []string
}
BuildContext is the assembled context payload passed to an agent.
func AssembleContext ¶
func AssembleContext(specPath string, session *SessionState, conventions string) (*BuildContext, error)
AssembleContext builds the full context payload for an agent.
type Engine ¶
type Engine struct {
// contains filtered or unexported fields
}
Engine orchestrates the build handoff. spec-cli owns the DAG, the durable node ledger, and all git/worktree/GitHub mechanics; the agent (pi) conducts the traversal via MCP. One StartOrResume call = one whole-DAG invocation.
func (*Engine) StartOrResume ¶
StartOrResume begins or continues a build session for a spec. It ensures the session and DAG exist, validates the workspaces the DAG needs, assembles the context, and invokes the agent once with the DAG exposed via MCP. The agent provisions and checkpoints each node back through the spec MCP tools; on return the engine reconciles the node ledger and, if work remains, prints resume guidance. A resume re-dispatches only the surviving ready nodes — completed nodes are never re-run.
type Graph ¶ added in v0.16.0
type Graph struct {
// Nodes are stored in their original plan order.
Nodes []PRStep
// contains filtered or unexported fields
}
Graph is a validated DAG of PR-stack nodes. It is the deterministic substrate the orchestrator walks: spec-cli owns the graph, pi conducts traversal.
func BuildGraph ¶ added in v0.16.0
BuildGraph validates a PR stack and returns its DAG. It rejects edges that reference unknown steps and dependency cycles, naming the offending nodes so the author can fix the §7.3 plan.
func (*Graph) Dependencies ¶ added in v0.16.0
Dependencies returns the node IDs the given node depends on.
func (*Graph) Leaves ¶ added in v0.16.0
Leaves returns the nodes no other node depends on — the tips of the stack, which are the PRs that must exist before review.
type MCPResource ¶
type MCPResource struct {
URI string `json:"uri"`
Name string `json:"name"`
Content string `json:"content"`
}
MCPResource represents a resource served by the MCP server.
type MCPServer ¶
type MCPServer struct {
// contains filtered or unexported fields
}
MCPServer serves spec context to MCP-compatible agents. It owns the DAG, the node ledger, and every git/worktree operation: the orchestrator reads the DAG once and checkpoints each node back through the node tools, while spec-cli keeps all branch/worktree mechanics on this side of the contract.
func NewMCPServer ¶
func NewMCPServer(session *SessionState, buildCtx *BuildContext, db *store.DB, specPath string, opts Options) *MCPServer
NewMCPServer creates a new MCP server for a build session. opts carries the workspace map (source repos for worktrees) and skill routing inputs. The DAG is built from the session's steps; a malformed plan yields a nil graph and a descriptive DAG resource rather than a panic.
func (*MCPServer) CallTool ¶
func (s *MCPServer) CallTool(name string, args json.RawMessage) (*MCPToolResult, error)
CallTool executes an MCP tool.
func (*MCPServer) GetResource ¶
func (s *MCPServer) GetResource(uri string) (*MCPResource, error)
GetResource returns a specific resource by URI.
func (*MCPServer) ListResources ¶
func (s *MCPServer) ListResources() []MCPResource
ListResources returns all available resources.
func (*MCPServer) WithRepo ¶ added in v0.16.0
func (s *MCPServer) WithRepo(r adapter.RepoAdapter) *MCPServer
WithRepo injects the repo adapter used by the draft-PR tools and returns the server for chaining. Kept separate from the constructor so call sites that never open PRs need not thread an adapter through.
type MCPToolResult ¶
MCPToolResult represents the result of an MCP tool call.
type NodeState ¶ added in v0.16.0
type NodeState struct {
ID string `json:"id"`
Status string `json:"status"`
Branch string `json:"branch,omitempty"`
BaseRef string `json:"base_ref,omitempty"`
Worktree string `json:"worktree,omitempty"`
Reason string `json:"reason,omitempty"`
PRNumber int `json:"pr_number,omitempty"`
PRURL string `json:"pr_url,omitempty"`
}
NodeState is the durable per-node record in the DAG ledger. It carries everything needed to resume, diff, and stack a node: its status, the branch and worktree git placed it on, the base ref it was cut from, an optional failure reason, and any draft-PR coordinates recorded during finishing.
type Options ¶ added in v0.15.0
type Options struct {
// Headless runs the agent autonomously (e.g. `spec fix --auto`).
Headless bool
// SkillRefs are explicit skill paths from config
// (integrations.agent.settings.skill). They take precedence over
// profile.yaml refs and the .spec/agent/skills/ directory.
SkillRefs []string
// TestCommand, when set, is run to populate FailingTests (best-effort).
TestCommand string
// Workspaces maps a PR-step repo name to a local directory. It is the
// source-of-truth repo that worktrees are added to for each node.
Workspaces map[string]string
// MaxParallel bounds orchestrator fan-out across ready nodes. Surfaced to
// the agent via the DAG resource; 0 means "use the default".
MaxParallel int
}
Options configures a build engine beyond its adapters.
type PRStep ¶
type PRStep struct {
Number int `yaml:"number" json:"number"`
ID string `yaml:"id" json:"id"`
Repo string `yaml:"repo" json:"repo"`
Layer string `yaml:"layer" json:"layer,omitempty"`
Description string `yaml:"description" json:"description"`
Branch string `yaml:"branch" json:"branch"`
Status string `yaml:"status" json:"status"` // "pending", "in-progress", "complete", "failed"
// DependsOn holds the step numbers this node depends on (parsed from the
// `(after: 1,2)` edge annotation). Empty for a root node.
DependsOn []int `yaml:"depends_on" json:"depends_on,omitempty"`
// PRURL is the draft PR recorded for this node in §7.3 via a trailing
// `<!-- pr: <url> -->` annotation. Empty until the finisher opens a PR.
PRURL string `yaml:"pr_url" json:"pr_url,omitempty"`
// BaseRef is the commit the step branch was created from. Used to capture
// the step's diff for cumulative cross-step context.
BaseRef string `yaml:"base_ref" json:"base_ref,omitempty"`
}
PRStep represents one node in the §7.3 PR stack plan. A plan is a DAG: each step has a stable ID, an optional repo and layer (which drive worktree placement and skill routing), and zero or more dependencies on earlier steps.
func ParsePRStack ¶
ParsePRStack extracts PR steps from the §7.3 PR Stack Plan section.
func ParsePRStackFromFile ¶
ParsePRStackFromFile reads a spec file and extracts PR steps.
type SessionState ¶
type SessionState struct {
SpecID string `json:"spec_id"`
CurrentStep int `json:"current_step"`
Branch string `json:"branch"`
Repo string `json:"repo"`
WorkDir string `json:"work_dir"`
LastActivity time.Time `json:"last_activity"`
Steps []PRStep `json:"steps"`
// Nodes is the per-node status ledger keyed by PRStep.ID. It is the DAG
// source of truth for the orchestrated build; CurrentStep is retained only
// for the legacy sequential walk and is removed once the DAG engine lands.
Nodes map[string]*NodeState `json:"nodes,omitempty"`
}
SessionState persists the build session for `spec do` resume.
func CreateSession ¶
func CreateSession(db *store.DB, specID string, steps []PRStep, workDir string) (*SessionState, error)
CreateSession creates a new build session.
func LoadSession ¶
func LoadSession(db *store.DB, specID string) (*SessionState, error)
LoadSession loads a session from the database.
func (*SessionState) CurrentPRStep ¶
func (s *SessionState) CurrentPRStep() *PRStep
CurrentPRStep returns the current step, or nil if complete.
func (*SessionState) DoneSet ¶ added in v0.16.0
func (s *SessionState) DoneSet() map[string]bool
DoneSet returns the set of completed node IDs, the input to Graph.ReadySet.
func (*SessionState) FailedNodes ¶ added in v0.16.0
func (s *SessionState) FailedNodes() []string
FailedNodes returns the IDs of nodes recorded as failed, sorted for stable reporting.
func (*SessionState) InitNodes ¶ added in v0.16.0
func (s *SessionState) InitNodes()
InitNodes populates the ledger from the session's steps when it is empty, giving every node a pending record. Existing records are preserved so a reload never clobbers progress.
func (*SessionState) IsComplete ¶
func (s *SessionState) IsComplete() bool
IsComplete returns true if all steps are done.
func (*SessionState) MarkNodeComplete ¶ added in v0.16.0
func (s *SessionState) MarkNodeComplete(id string)
MarkNodeComplete records a node as complete and clears any failure reason. It is idempotent: completing an already-complete node is a no-op.
func (*SessionState) MarkNodeFailed ¶ added in v0.16.0
func (s *SessionState) MarkNodeFailed(id, reason string)
MarkNodeFailed records a node as failed with a reason for resume/reporting.
func (*SessionState) NodeStatus ¶ added in v0.16.0
func (s *SessionState) NodeStatus(id string) string
NodeStatus returns the status of a node, or "pending" if unknown.
func (*SessionState) NodesComplete ¶ added in v0.16.0
func (s *SessionState) NodesComplete() bool
NodesComplete reports whether every node in the ledger is complete. It returns false for an empty ledger so an uninitialised session is never mistaken for a finished one.
func (*SessionState) SetNodeStatus ¶ added in v0.16.0
func (s *SessionState) SetNodeStatus(id, status string)
SetNodeStatus updates a node's status in the ledger.