Documentation
¶
Index ¶
- Constants
- Variables
- func AddJob(plan *Plan, job *Job) (string, error)
- func AddJobsFromRecipe(plan *Plan, recipe *Recipe, externalDeps []string, templateData interface{}) (newFiles []string, err error)
- func AddSummaryToJobFile(job *Job, summary string) error
- func AppendAgentTranscript(job *Job, plan *Plan) error
- func ArchiveInteractiveSession(job *Job, plan *Plan) error
- func BuildXMLPrompt(job *Job, plan *Plan, workDir string, contextFiles []string) (promptXML string, filesToUpload []string, err error)
- func CopyProjectFilesToWorktree(worktreePath, gitRoot string) error
- func CreateLockFile(jobFilePath string, pid int) error
- func DetermineWorkingDirectory(plan *Plan, job *Job) (string, error)
- func ExtractFrontmatterString(content []byte) (string, []byte, error)
- func FindCodexPIDForPane(targetPane string) (int, error)
- func FindContextFiles(plan *Plan) []string
- func FindOpencodePIDForPane(targetPane string) (int, error)
- func FormatConversationXML(turns []*ChatTurn) string
- func GenerateGitChangesXML(workDir string) (string, error)
- func GenerateJobFilename(number int, title string) string
- func GenerateUniqueJobID(plan *Plan, title string) string
- func GetGitRootSafe(planDir string) (string, error)
- func GetJobLogPath(plan *Plan, job *Job) (string, error)
- func GetNextJobNumber(dir string) (int, error)
- func GetProjectGitRoot(planDir string) (string, error)
- func GetProjectRoot() (string, error)
- func GetProjectRootSafe(startPath string) string
- func ListJobs(dir string) ([]string, error)
- func ParseFrontmatter(content []byte) (map[string]interface{}, []byte, error)
- func ReadLockFile(jobFilePath string) (int, error)
- func RebuildMarkdownWithFrontmatter(frontmatter map[string]interface{}, body []byte) ([]byte, error)
- func RemoveLockFile(jobFilePath string) error
- func RenameJob(plan *Plan, jobToRename *Job, newTitle string) error
- func ReplaceFrontmatter(content []byte, newFrontmatter string) []byte
- func ResolveLogDirectory(plan *Plan, job *Job) string
- func ResolveProjectForSessionNaming(workDir string) (*workspace.WorkspaceNode, error)
- func ResolvePromptSource(source string, plan *Plan) (string, error)
- func ResolveTemplate(templateName string, plan *Plan) (string, error)
- func ResolveWorkingDirectory(plan *Plan) string
- func SavePlan(dir string, plan *Plan) error
- func ScopeToSubProject(workDir string, job *Job) string
- func SummarizeJobContent(ctx context.Context, job *Job, plan *Plan, cfg SummaryConfig) (string, error)
- func SyncSkillsToWorktree(worktreePath string, node *workspace.WorkspaceNode) error
- func UpdateFrontmatter(content []byte, updates map[string]interface{}) ([]byte, error)
- func UpdateFrontmatterNode(yamlData []byte, updates map[string]interface{}) ([]byte, error)
- func UpdateJobDependencies(job *Job, newDeps []string) error
- func WriteBriefingFile(plan *Plan, job *Job, content string, turnID string) (string, error)
- type AgentRunner
- type ChatDirective
- type ChatTurn
- type ClaudeAgentProvider
- type CodexAgentProvider
- type CommandLLMClient
- type ConceptInfo
- type Config
- type DependencyGraph
- func (dg *DependencyGraph) DetectCycles() ([]string, error)
- func (dg *DependencyGraph) GetExecutionPlan() (*ExecutionPlan, error)
- func (dg *DependencyGraph) GetRunnableJobs() []*Job
- func (dg *DependencyGraph) ToMermaid() string
- func (dg *DependencyGraph) UpdateJobStatus(jobID string, status JobStatus)
- func (dg *DependencyGraph) ValidateDependencies() error
- type DynamicRecipe
- type ErrNotAJob
- type ExecutionContext
- type ExecutionPlan
- type Executor
- type ExecutorConfig
- type ExecutorRegistry
- type FileLock
- type FrontmatterParser
- type GenerateRecipeExecutor
- type GitClient
- type GitClientAdapter
- func (g *GitClientAdapter) CreateBranch(name string) error
- func (g *GitClientAdapter) CurrentBranch() (string, error)
- func (g *GitClientAdapter) IsGitRepo() bool
- func (g *GitClientAdapter) WorktreeAdd(path, branch string) error
- func (g *GitClientAdapter) WorktreeList() ([]Worktree, error)
- func (g *GitClientAdapter) WorktreeRemove(name string, force bool) error
- type HeadlessAgentExecutor
- type InitAction
- type InlineCategory
- type InlineConfig
- type InteractiveAgentExecutor
- type InteractiveAgentProvider
- type Job
- type JobMetadata
- type JobOptions
- type JobStatus
- type JobTemplate
- type JobType
- type LLMClient
- type LLMOptions
- type Logger
- type MockLLMClient
- type OneShotExecutor
- type OpencodeAgentProvider
- type Orchestrator
- func (o *Orchestrator) ExecuteJobWithWriter(ctx context.Context, job *Job, output io.Writer) error
- func (o *Orchestrator) GetStatus() *PlanStatus
- func (o *Orchestrator) RunAll(ctx context.Context) error
- func (o *Orchestrator) RunJob(ctx context.Context, jobFile string) error
- func (o *Orchestrator) RunNext(ctx context.Context) error
- func (o *Orchestrator) SetLogger(logger Logger)
- func (o *Orchestrator) UpdateJobMetadata(job *Job, meta JobMetadata) error
- func (o *Orchestrator) UpdateJobStatus(job *Job, status JobStatus) error
- func (o *Orchestrator) ValidatePrerequisites() error
- type OrchestratorConfig
- type Plan
- type PlanConfig
- type PlanStatus
- type Recipe
- func GetBuiltinRecipe(name string) (*Recipe, error)
- func GetNotebookRecipe(name string) (*Recipe, error)
- func GetProjectRecipe(name string) (*Recipe, error)
- func GetRecipe(name string, getRecipeCmd string) (*Recipe, error)
- func GetUserRecipe(name string) (*Recipe, error)
- func ListAllRecipes(getRecipeCmd string) ([]*Recipe, error)
- func ListBuiltinRecipes() ([]*Recipe, error)
- func ListDynamicRecipes(getRecipeCmd string) ([]*Recipe, error)
- func ListNotebookRecipes() ([]*Recipe, error)
- func ListProjectRecipes() ([]*Recipe, error)
- func ListUserRecipes() ([]*Recipe, error)
- type ShellExecutor
- type StateManager
- type StatePersister
- func (sp *StatePersister) AppendJobOutput(job *Job, output string) error
- func (sp *StatePersister) UpdateJobMetadata(job *Job, meta JobMetadata) error
- func (sp *StatePersister) UpdateJobStatus(job *Job, newStatus JobStatus) error
- func (sp *StatePersister) UpdateJobTemplate(job *Job, newTemplate string) error
- func (sp *StatePersister) UpdateJobType(job *Job, newType JobType) error
- func (sp *StatePersister) ValidateJobStates(plan *Plan) []error
- type SummaryConfig
- type TemplateManager
- type Worktree
- type WorktreeConfig
- type WorktreeLock
- type WorktreeManager
- func (wm *WorktreeManager) CleanupJobWorktree(job *Job) error
- func (wm *WorktreeManager) CleanupStaleWorktrees(age time.Duration) error
- func (wm *WorktreeManager) CreateWorktree(name string, baseBranch string) (string, error)
- func (wm *WorktreeManager) GetOrCreateWorktree(name string) (string, error)
- func (wm *WorktreeManager) IsLocked(name string) (bool, *WorktreeLock)
- func (wm *WorktreeManager) ListWorktrees() ([]Worktree, error)
- func (wm *WorktreeManager) LockWorktree(name string, jobID string) error
- func (wm *WorktreeManager) RemoveWorktree(name string, force bool) error
- func (wm *WorktreeManager) SetConfig(config WorktreeConfig)
- func (wm *WorktreeManager) UnlockWorktree(name string) error
Constants ¶
const AgentJobTemplate = `` /* 662-byte string literal not displayed */
AgentJobTemplate is the template for agent jobs.
Variables ¶
var BuiltinTemplates map[string]*JobTemplate
BuiltinTemplates stores templates loaded from embedded files.
var DefaultWorktreeConfig = WorktreeConfig{ AutoCleanup: true, CleanupAge: 24 * time.Hour, PreserveOnError: true, CleanupPrompt: false, }
Default configuration
Functions ¶
func AddJobsFromRecipe ¶
func AddJobsFromRecipe(plan *Plan, recipe *Recipe, externalDeps []string, templateData interface{}) (newFiles []string, err error)
AddJobsFromRecipe adds jobs from a recipe into an existing plan. It handles re-numbering and dependency re-mapping in three passes: 1. In-memory creation & renaming 2. Dependency remapping 3. Writing to disk
func AddSummaryToJobFile ¶
AddSummaryToJobFile updates a job's markdown file with a summary in its frontmatter.
func AppendAgentTranscript ¶
AppendAgentTranscript finds the transcript for an agent job and appends it to the job's markdown file.
func ArchiveInteractiveSession ¶
ArchiveInteractiveSession copies session metadata and the transcript to the plan's artifacts.
func BuildXMLPrompt ¶
func BuildXMLPrompt(job *Job, plan *Plan, workDir string, contextFiles []string) (promptXML string, filesToUpload []string, err error)
BuildXMLPrompt assembles a structured XML prompt for oneshot and interactive_agent jobs. It returns the final XML string and a list of file paths that should be uploaded separately. contextFiles should include paths to .grove/context, CLAUDE.md, and other project context files.
func CopyProjectFilesToWorktree ¶
CopyProjectFilesToWorktree is a setup handler for workspace.Prepare that copies key project-level configuration files (like grove.yml and .cx) into a new worktree. This is necessary for files that are typically gitignored but are required for the Grove tooling to function correctly within the isolated worktree.
func CreateLockFile ¶
CreateLockFile creates a lock file for a job, writing the process ID to it.
func DetermineWorkingDirectory ¶
DetermineWorkingDirectory determines the working directory for a job based on its worktree and repository configuration. This is the canonical logic used by both interactive agent execution and resume operations.
func ExtractFrontmatterString ¶
ExtractFrontmatterString extracts the raw YAML string between delimiters.
func FindCodexPIDForPane ¶
FindCodexPIDForPane finds the PID of the 'codex' process running within a specific tmux pane by traversing the process tree from the pane's shell.
func FindContextFiles ¶
FindContextFiles looks for context files in multiple locations
func FindOpencodePIDForPane ¶
FindOpencodePIDForPane finds the PID of the 'opencode' process running within a specific tmux pane
func FormatConversationXML ¶
FormatConversationXML converts parsed ChatTurns to structured XML format. This is used to send a clean, structured conversation to the LLM instead of raw markdown with HTML comment markers.
Input: []*ChatTurn - parsed conversation turns Output: XML string with <conversation><turn>...</turn></conversation> structure
The template attribute appears on assistant turns (indicating what persona/template was used to generate that response). The last user turn gets special attributes: - status="awaiting_response" to indicate this is the turn needing a response - respond_as="<template>" to indicate what persona/template should be used
Example output:
<conversation>
<turn role="user">
how about add fake syrup
</turn>
<turn role="assistant" template="chef" id="595424" timestamp="2026-01-08 05:34:09">
*Sigh.* "Fake syrup"...
</turn>
<turn role="user" status="awaiting_response" respond_as="chef">
respond to this
</turn>
</conversation>
func GenerateGitChangesXML ¶
GenerateGitChangesXML creates an XML block summarizing the git status of a worktree.
func GenerateJobFilename ¶
GenerateJobFilename creates a filename from job number and title.
func GenerateUniqueJobID ¶
GenerateUniqueJobID creates a globally unique job ID from a title string. This is the single source of truth for job ID generation across grove-flow.
func GetGitRootSafe ¶
GetGitRootSafe attempts to find git root with multiple fallback strategies
func GetJobLogPath ¶
GetJobLogPath returns the path to the log file for a given job. The log files are stored in <plan.Directory>/.artifacts/<job.ID>/job.log and the directory is created if it doesn't exist.
func GetNextJobNumber ¶
GetNextJobNumber scans the directory and returns the next available job number.
func GetProjectGitRoot ¶
GetProjectGitRoot returns the git root for the project associated with a plan. If the plan is inside a notebook, it returns the associated project's path. Otherwise, it falls back to GetGitRootSafe.
func GetProjectRoot ¶
GetProjectRoot attempts to find the project root directory by searching upwards for a grove config file.
func GetProjectRootSafe ¶
GetProjectRootSafe returns the project root using the workspace model. It supports both Grove projects (with grove.yml) and non-Grove repos. Falls back to git root or current directory if workspace discovery fails.
func ParseFrontmatter ¶
ParseFrontmatter extracts YAML frontmatter from markdown content. Returns the parsed YAML as a map, the remaining content, and any error.
func ReadLockFile ¶
ReadLockFile reads the PID from a job's lock file.
func RebuildMarkdownWithFrontmatter ¶
func RebuildMarkdownWithFrontmatter(frontmatter map[string]interface{}, body []byte) ([]byte, error)
RebuildMarkdownWithFrontmatter rebuilds a markdown file with new frontmatter data
func RemoveLockFile ¶
RemoveLockFile deletes a job's lock file.
func ReplaceFrontmatter ¶
ReplaceFrontmatter replaces existing frontmatter with new YAML string.
func ResolveLogDirectory ¶
ResolveLogDirectory determines where log files should be written
func ResolveProjectForSessionNaming ¶
func ResolveProjectForSessionNaming(workDir string) (*workspace.WorkspaceNode, error)
ResolveProjectForSessionNaming resolves the appropriate project for tmux session naming. If workDir is inside a notebook, it returns the associated project. Otherwise, it returns the project at workDir.
func ResolvePromptSource ¶
ResolvePromptSource resolves a prompt source file with multiple strategies
func ResolveTemplate ¶
ResolveTemplate resolves a template file path
func ResolveWorkingDirectory ¶
ResolveWorkingDirectory determines the appropriate working directory for command execution
func ScopeToSubProject ¶
ScopeToSubProject adjusts a working directory to point to a sub-project within an ecosystem worktree when job.Repository is specified. This ensures that context generation, command execution, and agent sessions all operate in the correct sub-project directory rather than the ecosystem root.
func SummarizeJobContent ¶
func SummarizeJobContent(ctx context.Context, job *Job, plan *Plan, cfg SummaryConfig) (string, error)
SummarizeJobContent generates a summary for a completed job.
func SyncSkillsToWorktree ¶
func SyncSkillsToWorktree(worktreePath string, node *workspace.WorkspaceNode) error
SyncSkillsToWorktree copies skills from all sources to a new worktree. Skills are collected from multiple sources with the following precedence (higher wins):
- User skills from ~/.config/grove/skills
- Ecosystem skills from the notebook (if project is part of an ecosystem)
- Project skills from the notebook
This delegates to grove-skills for the actual discovery and sync logic.
func UpdateFrontmatter ¶
UpdateFrontmatter updates specific fields in the frontmatter while preserving formatting.
func UpdateFrontmatterNode ¶
UpdateFrontmatterNode updates YAML using the Node API to preserve formatting.
func UpdateJobDependencies ¶
UpdateJobDependencies updates a job's depends_on field in its frontmatter.
func WriteBriefingFile ¶
WriteBriefingFile saves the provided content to a uniquely named .xml file in the plan's .artifacts/<job.ID> directory for auditing. For chat jobs, turnID should be the unique turn identifier. For other jobs, pass empty string.
Types ¶
type AgentRunner ¶
AgentRunner defines the interface for running agents.
type ChatDirective ¶
type ChatDirective struct {
ID string `json:"id,omitempty"`
Template string `json:"template,omitempty"`
Model string `json:"model,omitempty"`
Type string `json:"type,omitempty"` // Job type override for this turn
Action string `json:"action,omitempty"`
Vars map[string]interface{} `json:"vars,omitempty"`
}
ChatDirective represents the JSON payload in the user's comment
type ChatTurn ¶
type ChatTurn struct {
Speaker string // "user" or "llm"
Content string // The markdown content of the turn
Directive *ChatDirective // Parsed from the grove HTML comment
Timestamp time.Time // When the turn was recorded
}
ChatTurn represents a single entry in the conversation
func ParseChatFile ¶
ParseChatFile parses a chat notebook file to determine the speaker of each turn. It returns a simplified list of turns for determining runnability.
type ClaudeAgentProvider ¶
type ClaudeAgentProvider struct {
// contains filtered or unexported fields
}
ClaudeAgentProvider implements InteractiveAgentProvider for Claude Code.
func NewClaudeAgentProvider ¶
func NewClaudeAgentProvider() *ClaudeAgentProvider
func (*ClaudeAgentProvider) Launch ¶
func (p *ClaudeAgentProvider) Launch(ctx context.Context, job *Job, plan *Plan, workDir string, agentArgs []string, briefingFilePath string) error
Launch implements the InteractiveAgentProvider interface for Claude. This contains the logic previously in executeHostMode.
type CodexAgentProvider ¶
type CodexAgentProvider struct {
// contains filtered or unexported fields
}
func NewCodexAgentProvider ¶
func NewCodexAgentProvider() *CodexAgentProvider
type CommandLLMClient ¶
type CommandLLMClient struct {
// contains filtered or unexported fields
}
CommandLLMClient implements LLMClient using the llm command-line tool.
func NewCommandLLMClient ¶
func NewCommandLLMClient(executor command.Executor) *CommandLLMClient
NewCommandLLMClient creates a new LLM client that executes the llm command.
type ConceptInfo ¶
ConceptInfo represents basic information about a concept
type Config ¶
type Config struct {
OneshotModel string
TargetAgentContainer string
PlansDirectory string
MaxConsecutiveSteps int
}
Config holds orchestration-specific settings, decoupled from grove-core.
type DependencyGraph ¶
type DependencyGraph struct {
// contains filtered or unexported fields
}
DependencyGraph represents the job dependency relationships.
func BuildDependencyGraph ¶
func BuildDependencyGraph(plan *Plan) (*DependencyGraph, error)
BuildDependencyGraph creates a dependency graph from all jobs in a plan.
func (*DependencyGraph) DetectCycles ¶
func (dg *DependencyGraph) DetectCycles() ([]string, error)
DetectCycles uses DFS to detect circular dependencies.
func (*DependencyGraph) GetExecutionPlan ¶
func (dg *DependencyGraph) GetExecutionPlan() (*ExecutionPlan, error)
GetExecutionPlan performs topological sort and groups jobs into parallel stages.
func (*DependencyGraph) GetRunnableJobs ¶
func (dg *DependencyGraph) GetRunnableJobs() []*Job
GetRunnableJobs finds all jobs that can be run immediately.
func (*DependencyGraph) ToMermaid ¶
func (dg *DependencyGraph) ToMermaid() string
ToMermaid generates a Mermaid diagram representation of the graph.
func (*DependencyGraph) UpdateJobStatus ¶
func (dg *DependencyGraph) UpdateJobStatus(jobID string, status JobStatus)
UpdateJobStatus updates the status of a job in the dependency graph
func (*DependencyGraph) ValidateDependencies ¶
func (dg *DependencyGraph) ValidateDependencies() error
ValidateDependencies checks for circular dependencies and missing references.
type DynamicRecipe ¶
type DynamicRecipe struct {
Description string `json:"description"`
Jobs map[string]string `json:"jobs"` // filename -> content
}
DynamicRecipe represents the structure of a recipe from a dynamic source.
type ErrNotAJob ¶
type ErrNotAJob struct {
Reason string
}
ErrNotAJob is returned when a file is not a valid job file
func (ErrNotAJob) Error ¶
func (e ErrNotAJob) Error() string
type ExecutionContext ¶
type ExecutionContext struct {
// PlanDirectory is where the plan files are stored
PlanDirectory string
// ProjectRoot is the root of the project (where grove.yml is located)
ProjectRoot string
// GitRoot is the root of the git repository
GitRoot string
// WorkingDirectory is where commands should be executed
WorkingDirectory string
// Config is the loaded grove configuration
Config *config.Config
}
ExecutionContext provides context about where jobs are being executed from This helps resolve the disconnect between plan directories and project directories
func NewExecutionContext ¶
func NewExecutionContext(planDir string, cfg *config.Config) (*ExecutionContext, error)
NewExecutionContext creates a new execution context
func (*ExecutionContext) LogDirectory ¶
func (ctx *ExecutionContext) LogDirectory() string
LogDirectory returns where logs should be written
func (*ExecutionContext) ResolveContextFile ¶
func (ctx *ExecutionContext) ResolveContextFile() []string
ResolveContextFile resolves a context file path
func (*ExecutionContext) ResolvePromptSource ¶
func (ctx *ExecutionContext) ResolvePromptSource(source string) string
ResolvePromptSource resolves a prompt source file path
func (*ExecutionContext) WorktreeBaseDirectory ¶
func (ctx *ExecutionContext) WorktreeBaseDirectory() string
WorktreeBaseDirectory returns where worktrees should be created
type ExecutionPlan ¶
type ExecutionPlan struct {
Stages [][]string // Each stage contains jobs that can run in parallel
}
ExecutionPlan contains stages of jobs that can run in parallel.
type ExecutorConfig ¶
type ExecutorConfig struct {
MaxPromptLength int
Timeout time.Duration
RetryCount int
Model string
ModelOverride string // Override model from CLI
SkipInteractive bool // Skip interactive prompts
}
ExecutorConfig holds configuration for executors.
type ExecutorRegistry ¶
type ExecutorRegistry struct {
// contains filtered or unexported fields
}
ExecutorRegistry manages available executors.
func NewExecutorRegistry ¶
func NewExecutorRegistry() *ExecutorRegistry
NewExecutorRegistry creates a new executor registry.
func (*ExecutorRegistry) ExecuteJob ¶
ExecuteJob runs a job using the appropriate executor.
func (*ExecutorRegistry) Get ¶
func (r *ExecutorRegistry) Get(jobType JobType) (Executor, error)
Get returns the executor for a given job type.
func (*ExecutorRegistry) Register ¶
func (r *ExecutorRegistry) Register(jobType JobType, executor Executor)
Register adds an executor to the registry.
type FileLock ¶
type FileLock struct {
// contains filtered or unexported fields
}
FileLock represents a lock on a file.
type FrontmatterParser ¶
type FrontmatterParser struct{}
FrontmatterParser provides methods for parsing and updating frontmatter.
func (*FrontmatterParser) ParseFrontmatter ¶
func (fp *FrontmatterParser) ParseFrontmatter(content []byte) (map[string]interface{}, []byte, error)
ParseFrontmatter parses YAML frontmatter from content.
func (*FrontmatterParser) WriteFrontmatter ¶
func (fp *FrontmatterParser) WriteFrontmatter(w io.Writer, frontmatter map[string]interface{}) error
WriteFrontmatter writes frontmatter and body to a writer.
type GenerateRecipeExecutor ¶
type GenerateRecipeExecutor struct {
// contains filtered or unexported fields
}
GenerateRecipeExecutor handles generate-recipe jobs
func NewGenerateRecipeExecutor ¶
func NewGenerateRecipeExecutor(config *ExecutorConfig) *GenerateRecipeExecutor
NewGenerateRecipeExecutor creates a new generate recipe executor
func (*GenerateRecipeExecutor) Name ¶
func (e *GenerateRecipeExecutor) Name() string
Name returns the executor name
type GitClient ¶
type GitClient interface {
WorktreeAdd(path, branch string) error
WorktreeList() ([]Worktree, error)
WorktreeRemove(name string, force bool) error
CreateBranch(name string) error
CurrentBranch() (string, error)
IsGitRepo() bool
}
GitClient interface for git operations.
type GitClientAdapter ¶
type GitClientAdapter struct {
// contains filtered or unexported fields
}
GitClientAdapter adapts the git.WorktreeManager to the GitClient interface.
func NewGitClientAdapter ¶
func NewGitClientAdapter(repoPath string) *GitClientAdapter
NewGitClientAdapter creates a new git client adapter.
func (*GitClientAdapter) CreateBranch ¶
func (g *GitClientAdapter) CreateBranch(name string) error
CreateBranch creates a new branch.
func (*GitClientAdapter) CurrentBranch ¶
func (g *GitClientAdapter) CurrentBranch() (string, error)
CurrentBranch returns the current branch name.
func (*GitClientAdapter) IsGitRepo ¶
func (g *GitClientAdapter) IsGitRepo() bool
IsGitRepo checks if the path is a git repository.
func (*GitClientAdapter) WorktreeAdd ¶
func (g *GitClientAdapter) WorktreeAdd(path, branch string) error
WorktreeAdd adds a new worktree.
func (*GitClientAdapter) WorktreeList ¶
func (g *GitClientAdapter) WorktreeList() ([]Worktree, error)
WorktreeList lists all worktrees.
func (*GitClientAdapter) WorktreeRemove ¶
func (g *GitClientAdapter) WorktreeRemove(name string, force bool) error
WorktreeRemove removes a worktree.
type HeadlessAgentExecutor ¶
type HeadlessAgentExecutor struct {
// contains filtered or unexported fields
}
HeadlessAgentExecutor executes headless agent jobs in isolated git worktrees.
func NewHeadlessAgentExecutor ¶
func NewHeadlessAgentExecutor(llmClient LLMClient, config *ExecutorConfig) *HeadlessAgentExecutor
NewHeadlessAgentExecutor creates a new headless agent executor.
func (*HeadlessAgentExecutor) Name ¶
func (e *HeadlessAgentExecutor) Name() string
Name returns the executor name.
type InitAction ¶
type InitAction struct {
Type string `yaml:"type"` // "shell" or "docker_compose"
Description string `yaml:"description,omitempty"`
Repo string `yaml:"repo,omitempty"` // Optional sub-repo for ecosystem worktrees
Command string `yaml:"command,omitempty"` // For 'shell' type
Files []string `yaml:"files,omitempty"` // For 'docker_compose': list of user's compose files
ProjectName string `yaml:"project_name,omitempty"` // For 'docker_compose' --project-name flag
Overlay map[string]interface{} `yaml:"overlay,omitempty"` // For 'docker_compose': the generic overlay
}
InitAction defines a single action to be performed during plan initialization. These are defined in a recipe's `workspace_init.yml`.
type InlineCategory ¶
type InlineCategory string
InlineCategory represents a category of files that can be inlined.
const ( InlineDependencies InlineCategory = "dependencies" // Output from upstream jobs in the pipeline InlineInclude InlineCategory = "include" // Files specified in include: frontmatter InlineContext InlineCategory = "context" // cx-generated context file (.grove/context) )
type InlineConfig ¶
type InlineConfig struct {
Categories []InlineCategory
}
InlineConfig controls which file types are embedded directly in the prompt vs uploaded as attachments. It can be specified as: - An array of categories: ["dependencies", "include", "context"] - A shorthand string: "none" (default), "all", or a single category like "dependencies"
func (InlineConfig) IsEmpty ¶
func (ic InlineConfig) IsEmpty() bool
IsEmpty returns true if no categories are configured.
func (InlineConfig) MarshalYAML ¶
func (ic InlineConfig) MarshalYAML() (interface{}, error)
MarshalYAML implements custom YAML marshaling.
func (*InlineConfig) UnmarshalYAML ¶
func (ic *InlineConfig) UnmarshalYAML(unmarshal func(interface{}) error) error
UnmarshalYAML implements custom YAML unmarshaling to support both array and string syntax.
type InteractiveAgentExecutor ¶
type InteractiveAgentExecutor struct {
// contains filtered or unexported fields
}
InteractiveAgentExecutor executes interactive agent jobs in tmux sessions.
func NewInteractiveAgentExecutor ¶
func NewInteractiveAgentExecutor(llmClient LLMClient, geminiRunner *gemini.RequestRunner, skipInteractive bool) *InteractiveAgentExecutor
NewInteractiveAgentExecutor creates a new interactive agent executor.
func (*InteractiveAgentExecutor) Execute ¶
Execute runs an interactive agent job in a tmux session and blocks until completion. The output writer is ignored for interactive agents as they run in a separate tmux session.
func (*InteractiveAgentExecutor) Name ¶
func (e *InteractiveAgentExecutor) Name() string
Name returns the executor name.
type InteractiveAgentProvider ¶
type InteractiveAgentProvider interface {
Launch(ctx context.Context, job *Job, plan *Plan, workDir string, agentArgs []string, briefingFilePath string) error
}
InteractiveAgentProvider defines the interface for launching an interactive agent.
type Job ¶
type Job struct {
// From frontmatter
ID string `yaml:"id" json:"id"`
Title string `yaml:"title" json:"title"`
Status JobStatus `yaml:"status" json:"status"`
Type JobType `yaml:"type" json:"type"`
Model string `yaml:"model,omitempty" json:"model,omitempty"`
DependsOn []string `yaml:"depends_on,omitempty" json:"depends_on,omitempty"`
Include []string `yaml:"include,omitempty" json:"include,omitempty"`
SourceBlock string `yaml:"source_block,omitempty" json:"source_block,omitempty"`
Template string `yaml:"template,omitempty" json:"template,omitempty"`
Repository string `yaml:"repository,omitempty" json:"repository,omitempty"`
Branch string `yaml:"branch,omitempty" json:"branch,omitempty"`
Worktree string `yaml:"worktree" json:"worktree,omitempty"`
TargetAgentContainer string `yaml:"target_agent_container,omitempty" json:"target_agent_container,omitempty"`
Inline InlineConfig `yaml:"inline,omitempty" json:"inline,omitempty"` // New field: controls which file types are inlined vs uploaded
PrependDependencies bool `yaml:"prepend_dependencies,omitempty" json:"prepend_dependencies,omitempty"` // Deprecated: use inline: [dependencies] instead
OnCompleteStatus string `yaml:"on_complete_status,omitempty" json:"on_complete_status,omitempty"`
CreatedAt time.Time `yaml:"created_at,omitempty" json:"created_at,omitempty"`
UpdatedAt time.Time `yaml:"updated_at,omitempty" json:"updated_at,omitempty"`
CompletedAt time.Time `yaml:"completed_at,omitempty" json:"completed_at,omitempty"`
Duration time.Duration `yaml:"duration,omitempty" json:"duration,omitempty"`
Summary string `yaml:"summary,omitempty" json:"summary,omitempty"`
SourcePlan string `yaml:"source_plan,omitempty" json:"source_plan,omitempty"`
RecipeName string `yaml:"recipe_name,omitempty" json:"recipe_name,omitempty"`
GeneratePlanFrom bool `yaml:"generate_plan_from,omitempty" json:"generate_plan_from,omitempty"`
GitChanges bool `yaml:"git_changes,omitempty" json:"git_changes,omitempty"`
GatherConceptNotes bool `yaml:"gather_concept_notes,omitempty" json:"gather_concept_notes,omitempty"`
GatherConceptPlans bool `yaml:"gather_concept_plans,omitempty" json:"gather_concept_plans,omitempty"`
RulesFile string `yaml:"rules_file,omitempty" json:"rules_file,omitempty"`
NoteRef string `yaml:"note_ref,omitempty" json:"note_ref,omitempty"`
SourceFile string `yaml:"source_file,omitempty" json:"source_file,omitempty"` // Origin file path (e.g., Claude plan file)
// Derived fields
Filename string `json:"filename,omitempty"` // The markdown filename
FilePath string `json:"file_path,omitempty"` // Full path to the file
PromptBody string `json:"-"` // Content after frontmatter
Dependencies []*Job `json:"-"` // Resolved job references
StartTime time.Time `json:"start_time,omitempty"` // When job started
EndTime time.Time `json:"end_time,omitempty"` // When job completed
Metadata JobMetadata `json:"metadata,omitempty"`
}
Job represents a single orchestration job.
func CreateJobFromTemplate ¶
func CreateJobFromTemplate(jobType JobType, title string, opts JobOptions) *Job
CreateJobFromTemplate creates a new job with default values.
func (*Job) AppendOutput ¶
func (j *Job) AppendOutput(sp *StatePersister, output string) error
AppendOutput appends output to the job file.
func (*Job) CanBeRetried ¶
CanBeRetried checks if a failed job can be manually retried. This is used when a user explicitly targets a failed job for re-execution.
func (*Job) IsRunnable ¶
IsRunnable checks if a job can be executed.
func (*Job) ShouldInline ¶
func (j *Job) ShouldInline(category InlineCategory) bool
ShouldInline checks if a specific category should be inlined in the prompt. It first checks the new Inline field, then falls back to PrependDependencies for backwards compatibility.
func (*Job) UpdateStatus ¶
func (j *Job) UpdateStatus(sp *StatePersister, newStatus JobStatus) error
UpdateStatus updates the job status using the state persister.
type JobMetadata ¶
type JobMetadata struct {
ExecutionTime time.Duration `yaml:"execution_time"`
RetryCount int `yaml:"retry_count"`
LastError string `yaml:"last_error"`
}
JobMetadata holds additional job metadata.
type JobOptions ¶
type JobOptions struct {
DependsOn []string
Include []string
Worktree string
Prompt string
Inline InlineConfig // New field: controls which file types are inlined
PrependDependencies bool // Deprecated: use Inline instead
}
JobOptions contains options for creating a new job.
type JobStatus ¶
type JobStatus string
JobStatus represents the current state of a job.
const ( JobStatusPending JobStatus = "pending" JobStatusRunning JobStatus = "running" JobStatusCompleted JobStatus = "completed" JobStatusFailed JobStatus = "failed" JobStatusBlocked JobStatus = "blocked" JobStatusNeedsReview JobStatus = "needs_review" JobStatusPendingUser JobStatus = "pending_user" JobStatusPendingLLM JobStatus = "pending_llm" JobStatusHold JobStatus = "hold" JobStatusTodo JobStatus = "todo" JobStatusAbandoned JobStatus = "abandoned" JobStatusIdle JobStatus = "idle" // Agent finished responding, waiting for next input )
type JobTemplate ¶
type JobTemplate struct {
Name string `json:"name"`
Path string `json:"path"`
Source string `json:"source"` // "project", "user", "builtin"
Domain string `json:"domain,omitempty"` // "generic" or "grove"
Type string `json:"type,omitempty"` // "agent" or "oneshot"
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Frontmatter map[string]interface{} `json:"frontmatter,omitempty"`
Prompt string `json:"prompt,omitempty"`
}
JobTemplate represents a predefined job structure.
func (*JobTemplate) Render ¶
func (t *JobTemplate) Render(data interface{}) (string, error)
Render applies data to a template's prompt.
type JobType ¶
type JobType string
JobType represents the type of job execution.
const ( JobTypeOneshot JobType = "oneshot" JobTypeAgent JobType = "agent" JobTypeHeadlessAgent JobType = "headless_agent" JobTypeShell JobType = "shell" JobTypeChat JobType = "chat" JobTypeInteractiveAgent JobType = "interactive_agent" JobTypeGenerateRecipe JobType = "generate-recipe" JobTypeFile JobType = "file" // Non-executable job for storing context/reference content )
type LLMClient ¶
type LLMClient interface {
Complete(ctx context.Context, job *Job, plan *Plan, prompt string, opts LLMOptions, output io.Writer) (string, error)
}
LLMClient defines the interface for LLM interactions.
func NewMockLLMClient ¶
func NewMockLLMClient() LLMClient
NewMockLLMClient creates a new mock LLM client.
type LLMOptions ¶
type LLMOptions struct {
Model string
SchemaPath string // Path to JSON schema file for structured output
WorkingDir string // Working directory for the LLM command
ContextFiles []string // Paths to context files (.grove/context, CLAUDE.md)
IncludeFiles []string // Paths to include files from job configuration
}
LLMOptions defines configuration for an LLM completion request.
type Logger ¶
type Logger interface {
Info(msg string, keysAndValues ...interface{})
Error(msg string, keysAndValues ...interface{})
Debug(msg string, keysAndValues ...interface{})
}
Logger defines the logging interface.
func NewDefaultLogger ¶
func NewDefaultLogger() Logger
type MockLLMClient ¶
type MockLLMClient struct {
// contains filtered or unexported fields
}
MockLLMClient implements a mock LLM client for testing.
type OneShotExecutor ¶
type OneShotExecutor struct {
// contains filtered or unexported fields
}
OneShotExecutor executes oneshot jobs.
func NewOneShotExecutor ¶
func NewOneShotExecutor(llmClient LLMClient, config *ExecutorConfig) *OneShotExecutor
NewOneShotExecutor creates a new oneshot executor.
func (*OneShotExecutor) Name ¶
func (e *OneShotExecutor) Name() string
Name returns the executor name.
type OpencodeAgentProvider ¶
type OpencodeAgentProvider struct {
// contains filtered or unexported fields
}
OpencodeAgentProvider implements InteractiveAgentProvider for the opencode agent.
func NewOpencodeAgentProvider ¶
func NewOpencodeAgentProvider() *OpencodeAgentProvider
type Orchestrator ¶
type Orchestrator struct {
Plan *Plan
// contains filtered or unexported fields
}
Orchestrator coordinates job execution and manages state.
func NewOrchestrator ¶
func NewOrchestrator(plan *Plan, config *OrchestratorConfig) (*Orchestrator, error)
NewOrchestrator creates a new orchestrator instance.
func (*Orchestrator) ExecuteJobWithWriter ¶
ExecuteJobWithWriter runs a single job and streams its output to the provided writer. This is primarily for TUI integration where output needs to be captured and displayed.
func (*Orchestrator) GetStatus ¶
func (o *Orchestrator) GetStatus() *PlanStatus
GetStatus returns the current plan status.
func (*Orchestrator) RunAll ¶
func (o *Orchestrator) RunAll(ctx context.Context) error
RunAll executes all jobs in the plan.
func (*Orchestrator) RunJob ¶
func (o *Orchestrator) RunJob(ctx context.Context, jobFile string) error
RunJob executes a specific job by filename.
func (*Orchestrator) RunNext ¶
func (o *Orchestrator) RunNext(ctx context.Context) error
RunNext executes all currently runnable jobs.
func (*Orchestrator) SetLogger ¶
func (o *Orchestrator) SetLogger(logger Logger)
SetLogger sets a custom logger.
func (*Orchestrator) UpdateJobMetadata ¶
func (o *Orchestrator) UpdateJobMetadata(job *Job, meta JobMetadata) error
UpdateJobMetadata updates a job's metadata.
func (*Orchestrator) UpdateJobStatus ¶
func (o *Orchestrator) UpdateJobStatus(job *Job, status JobStatus) error
UpdateJobStatus updates a job's status with proper synchronization.
func (*Orchestrator) ValidatePrerequisites ¶
func (o *Orchestrator) ValidatePrerequisites() error
ValidatePrerequisites ensures all requirements are met before running jobs.
type OrchestratorConfig ¶
type OrchestratorConfig struct {
MaxParallelJobs int
CheckInterval time.Duration
StateFile string
ModelOverride string // Override model for all jobs
MaxConsecutiveSteps int // Maximum consecutive steps before halting
SkipInteractive bool // Skip interactive agent jobs
SummaryConfig *SummaryConfig // Configuration for job summarization
CommandExecutor command.Executor // For dependency injection
}
OrchestratorConfig holds configuration for the orchestrator.
type Plan ¶
type Plan struct {
Name string // Name of the plan (directory name)
Directory string // Root directory of the plan
Jobs []*Job // List of all jobs
JobsByID map[string]*Job // Keyed by job ID
SpecFile string // Path to spec.md if exists
Orchestration *Config // Orchestration configuration
Context *ExecutionContext // Execution context for the plan
Config *PlanConfig // Plan-specific configuration from .grove-plan.yml
}
Plan represents a collection of orchestration jobs.
func (*Plan) GetJobByFilename ¶
GetJobByFilename returns a job by its filename.
func (*Plan) GetJobByID ¶
GetJobByID returns a job by its ID.
func (*Plan) GetJobsSortedByFilename ¶
GetJobsSortedByFilename returns all jobs sorted by their filename.
func (*Plan) GetRunnableJobs ¶
GetRunnableJobs returns all jobs that can currently be executed.
func (*Plan) ResolveDependencies ¶
ResolveDependencies converts dependency IDs to Job pointers and checks for cycles.
type PlanConfig ¶
type PlanConfig struct {
Model string `yaml:"model,omitempty"`
Worktree string `yaml:"worktree,omitempty"`
TargetAgentContainer string `yaml:"target_agent_container,omitempty"`
Status string `yaml:"status,omitempty"`
Repos []string `yaml:"repos,omitempty"` // List of repos to include in ecosystem worktree
Notes string `yaml:"notes,omitempty"` // User notes/description for the plan
Inline InlineConfig `yaml:"inline,omitempty"` // New field: controls which file types are inlined by default
PrependDependencies bool `yaml:"prepend_dependencies,omitempty"` // Deprecated: use inline instead
Hooks map[string]string `yaml:"hooks,omitempty"`
Recipe string `yaml:"recipe,omitempty"` // Recipe used to create this plan
}
PlanConfig holds plan-specific default settings from .grove-plan.yml.
func (*PlanConfig) ShouldInline ¶
func (pc *PlanConfig) ShouldInline(category InlineCategory) bool
ShouldInline checks if a specific category should be inlined by default for jobs in this plan. It first checks the new Inline field, then falls back to PrependDependencies for backwards compatibility.
type PlanStatus ¶
type PlanStatus struct {
Total int
Pending int
Running int
Completed int
Failed int
Blocked int
Progress float64
}
PlanStatus provides comprehensive status information.
type Recipe ¶
type Recipe struct {
Name string `json:"name"`
Description string `json:"description"`
Source string `json:"source,omitempty"` // [Built-in], [User], [Dynamic], or [Project]
Domain string `json:"domain,omitempty"` // "generic" or "grove"
DefaultNoteTarget string `json:"-"` // This will be populated from recipe.yml
Jobs map[string][]byte `json:"-"` // Filename -> Content
InitActions []InitAction `yaml:"init,omitempty"` // Actions that run with --init flag
NamedActions map[string][]InitAction `yaml:"actions,omitempty"` // Named, on-demand action groups
}
func GetBuiltinRecipe ¶
GetBuiltinRecipe finds and returns a built-in recipe.
func GetNotebookRecipe ¶
GetNotebookRecipe finds and returns a recipe from the current notebook context.
func GetProjectRecipe ¶
GetProjectRecipe finds and returns a project-local recipe by searching upwards.
func GetRecipe ¶
GetRecipe finds and returns a recipe by name with precedence: Project > Notebook > User > Dynamic > Built-in.
func GetUserRecipe ¶
GetUserRecipe finds and returns a user-defined recipe.
func ListAllRecipes ¶
ListAllRecipes lists all available recipes with precedence: Project > User > Dynamic > Built-in.
func ListBuiltinRecipes ¶
ListBuiltinRecipes lists all available built-in recipes.
func ListDynamicRecipes ¶
ListDynamicRecipes loads recipes by executing an external command.
func ListNotebookRecipes ¶
ListNotebookRecipes lists all recipes from the current notebook context.
func ListProjectRecipes ¶
ListProjectRecipes lists all project-local recipes from .grove/recipes, searching upwards.
func ListUserRecipes ¶
ListUserRecipes lists all user-defined recipes from ~/.config/grove/recipes.
type ShellExecutor ¶
type ShellExecutor struct {
// contains filtered or unexported fields
}
ShellExecutor executes shell commands as orchestration jobs.
func NewShellExecutor ¶
func NewShellExecutor(config *ExecutorConfig) *ShellExecutor
NewShellExecutor creates a new shell executor.
type StateManager ¶
type StateManager struct {
// contains filtered or unexported fields
}
StateManager handles persistence of job states.
func NewStateManager ¶
func NewStateManager(planDir string) *StateManager
func (*StateManager) UpdateJobMetadata ¶
func (sm *StateManager) UpdateJobMetadata(job *Job, meta JobMetadata) error
func (*StateManager) UpdateJobStatus ¶
func (sm *StateManager) UpdateJobStatus(job *Job, status JobStatus) error
type StatePersister ¶
type StatePersister struct {
// contains filtered or unexported fields
}
StatePersister handles persistent state updates for jobs.
func NewStatePersister ¶
func NewStatePersister() *StatePersister
NewStatePersister creates a new state persister.
func (*StatePersister) AppendJobOutput ¶
func (sp *StatePersister) AppendJobOutput(job *Job, output string) error
AppendJobOutput appends output to a job's markdown file.
func (*StatePersister) UpdateJobMetadata ¶
func (sp *StatePersister) UpdateJobMetadata(job *Job, meta JobMetadata) error
UpdateJobMetadata updates metadata fields for a job.
func (*StatePersister) UpdateJobStatus ¶
func (sp *StatePersister) UpdateJobStatus(job *Job, newStatus JobStatus) error
UpdateJobStatus updates the status of a job in its markdown file.
func (*StatePersister) UpdateJobTemplate ¶
func (sp *StatePersister) UpdateJobTemplate(job *Job, newTemplate string) error
UpdateJobTemplate updates the template of a job in its markdown file.
func (*StatePersister) UpdateJobType ¶
func (sp *StatePersister) UpdateJobType(job *Job, newType JobType) error
UpdateJobType updates the type of a job in its markdown file.
func (*StatePersister) ValidateJobStates ¶
func (sp *StatePersister) ValidateJobStates(plan *Plan) []error
ValidateJobStates validates all job states in a plan.
type SummaryConfig ¶
SummaryConfig holds configuration for job summarization.
type TemplateManager ¶
type TemplateManager struct {
}
TemplateManager finds and loads job templates.
func NewTemplateManager ¶
func NewTemplateManager() *TemplateManager
func (*TemplateManager) FindTemplate ¶
func (tm *TemplateManager) FindTemplate(name string) (*JobTemplate, error)
FindTemplate searches for a template by name, traversing upwards to find it.
func (*TemplateManager) ListTemplates ¶
func (tm *TemplateManager) ListTemplates() ([]*JobTemplate, error)
ListTemplates lists all discoverable templates by searching upwards.
func (*TemplateManager) LoadTemplate ¶
func (tm *TemplateManager) LoadTemplate(path, name, source string) (*JobTemplate, error)
LoadTemplate loads a template from a given path.
type Worktree ¶
type Worktree struct {
Name string
Path string
Branch string
HEAD string
IsLocked bool
CreatedAt time.Time
}
Worktree represents a git worktree.
type WorktreeConfig ¶
type WorktreeConfig struct {
AutoCleanup bool // Whether to auto-remove worktrees after job completion
CleanupAge time.Duration // Age after which stale worktrees are cleaned
PreserveOnError bool // Keep worktree if job fails
CleanupPrompt bool // Ask user before cleanup
}
WorktreeConfig defines worktree management behavior.
type WorktreeLock ¶
WorktreeLock represents a lock on a worktree.
type WorktreeManager ¶
type WorktreeManager struct {
// contains filtered or unexported fields
}
WorktreeManager handles git worktree lifecycle for job execution.
func NewWorktreeManager ¶
func NewWorktreeManager(baseDir string, gitClient GitClient, logger Logger) (*WorktreeManager, error)
NewWorktreeManager creates a new worktree manager.
func (*WorktreeManager) CleanupJobWorktree ¶
func (wm *WorktreeManager) CleanupJobWorktree(job *Job) error
CleanupJobWorktree cleans up a worktree after job completion.
func (*WorktreeManager) CleanupStaleWorktrees ¶
func (wm *WorktreeManager) CleanupStaleWorktrees(age time.Duration) error
CleanupStaleWorktrees removes worktrees older than the specified age.
func (*WorktreeManager) CreateWorktree ¶
func (wm *WorktreeManager) CreateWorktree(name string, baseBranch string) (string, error)
CreateWorktree creates a new worktree.
func (*WorktreeManager) GetOrCreateWorktree ¶
func (wm *WorktreeManager) GetOrCreateWorktree(name string) (string, error)
GetOrCreateWorktree gets an existing worktree or creates a new one.
func (*WorktreeManager) IsLocked ¶
func (wm *WorktreeManager) IsLocked(name string) (bool, *WorktreeLock)
IsLocked checks if a worktree is locked.
func (*WorktreeManager) ListWorktrees ¶
func (wm *WorktreeManager) ListWorktrees() ([]Worktree, error)
ListWorktrees returns all worktrees managed by this manager.
func (*WorktreeManager) LockWorktree ¶
func (wm *WorktreeManager) LockWorktree(name string, jobID string) error
LockWorktree locks a worktree for exclusive use.
func (*WorktreeManager) RemoveWorktree ¶
func (wm *WorktreeManager) RemoveWorktree(name string, force bool) error
RemoveWorktree removes a worktree.
func (*WorktreeManager) SetConfig ¶
func (wm *WorktreeManager) SetConfig(config WorktreeConfig)
SetConfig updates the worktree configuration.
func (*WorktreeManager) UnlockWorktree ¶
func (wm *WorktreeManager) UnlockWorktree(name string) error
UnlockWorktree removes the lock from a worktree.
Source Files
¶
- archive.go
- briefing.go
- builtin_templates.go
- chat.go
- chat_formatter.go
- chat_parser.go
- codex_agent_provider.go
- concept_gatherer.go
- config.go
- context_utils.go
- dependency_graph.go
- directory.go
- execution_context.go
- executor.go
- executor_generate_recipe.go
- frontmatter.go
- git_client_adapter.go
- git_summary.go
- headless_agent_executor.go
- interactive_agent_executor.go
- job.go
- job_actions.go
- job_summary.go
- job_templates.go
- llm_client.go
- loader.go
- lockfile.go
- log_path.go
- oneshot_executor.go
- opencode_agent_provider.go
- orchestrator.go
- plan.go
- recipes.go
- shell_executor.go
- state.go
- templates.go
- worktree_manager.go
- worktree_setup.go