Documentation
¶
Index ¶
- Constants
- func ApplyWorkflowCommandOverrides(cfg *AgentWorkflowConfig, overrides *CLIOverrides)
- func ApplyWorkflowInitialOverrides(chatAgent *agent.Agent, cfg *AgentWorkflowConfig, overrides *CLIOverrides) error
- func ApplyWorkflowRuntimeAllowedPaths(chatAgent *agent.Agent, paths []AllowedPath) (snapshotPaths []string, snapshotModes map[string]string, addedPaths []string, ...)
- func ApplyWorkflowRuntimeOverrides(chatAgent *agent.Agent, runtime AgentWorkflowRuntime, overrides *CLIOverrides) error
- func ApplyWorkflowSubagentOverrides(subagentTypes map[string]configuration.SubagentType, ...)
- func AttachWorkflowBudget(chatAgent *agent.Agent, cfg *AgentWorkflowConfig) (stop func())
- func EmitWorkflowOrchestrationEvent(cfg *AgentWorkflowConfig, eventType string, payload map[string]interface{}) error
- func FindSubagentTypeMapKey(subagentTypes map[string]configuration.SubagentType, normalizedID string) (string, bool)
- func IsSystemPathPrefix(p string) bool
- func IsValidWorkflowWhen(v string) bool
- func LoadLoopCheckpoint(workDir string) (int, error)
- func LoopCheckpointFilePath(workDir string) string
- func NormalizeReasoningEffort(v string) string
- func NormalizeWorkflowPaths(paths []string) []string
- func NormalizeWorkflowPersonaID(raw string) string
- func NormalizeWorkflowWhen(v string) string
- func ParseBudgetWarnList(s string) ([]float64, error)
- func PersistLoopCheckpoint(workDir string, lineNum int) error
- func PersistWorkflowCheckpoint(cfg *AgentWorkflowConfig, state *WorkflowExecutionState, ...) error
- func PersistWorkflowConversationState(chatAgent *agent.Agent, cfg *AgentWorkflowConfig) error
- func PersistWorkflowExecutionState(cfg *AgentWorkflowConfig, state *WorkflowExecutionState) error
- func PrepareWorkflowRuntimeRestorer(chatAgent *agent.Agent, cfg *AgentWorkflowConfig, overrides *CLIOverrides) (func() error, error)
- func ReadTodoStatus(todoFile string) todoStatus
- func RemoveLoopCheckpoint(workDir string)
- func ResolveStepPrompt(step AgentWorkflowStep) (string, error)
- func ResolveWorkflowInitialPrompt(cliQuery string, cfg *AgentWorkflowConfig) (string, error)
- func ResolveWorkflowTextOrFile(text, filePath, label string) (string, error)
- func RestoreWorkflowConversationState(chatAgent *agent.Agent, cfg *AgentWorkflowConfig, ...) error
- func RestoreWorkflowRuntimeAllowedPaths(chatAgent *agent.Agent, snapshotPaths []string, ...) error
- func RunAgentWorkflow(ctx context.Context, chatAgent *agent.Agent, eventBus *events.EventBus, ...) (bool, error)
- func RunAgentWorkflowLoop(ctx context.Context, chatAgent *agent.Agent, eventBus *events.EventBus, ...) (bool, error)
- func ShouldRestoreWorkflowConversationState(state *WorkflowExecutionState) bool
- func ShouldRunWorkflowStep(when string, hasError bool) bool
- func ShouldYieldBeforeWorkflowStep(cfg *AgentWorkflowConfig, state *WorkflowExecutionState, ...) bool
- func StepFileTriggersSatisfied(step AgentWorkflowStep) (bool, error)
- func WorkflowEffectiveStepProvider(chatAgent *agent.Agent, step AgentWorkflowStep) string
- func WriteFileAtomic(path string, data []byte, perm os.FileMode) error
- type AgentWorkflowBudgetConfig
- type AgentWorkflowConfig
- func (c *AgentWorkflowConfig) IsApprovalRequired() bool
- func (c *AgentWorkflowConfig) OrchestrationEnabled() bool
- func (c *AgentWorkflowConfig) OrchestrationResumeEnabled() bool
- func (c *AgentWorkflowConfig) OrchestrationYieldOnProviderHandoff() bool
- func (c *AgentWorkflowConfig) ShouldPersistRuntimeOverrides() bool
- func (c *AgentWorkflowConfig) Validate() error
- type AgentWorkflowContinuation
- type AgentWorkflowInitial
- type AgentWorkflowLoopConfig
- type AgentWorkflowOrchestrationConfig
- type AgentWorkflowProgressConfig
- type AgentWorkflowRuntime
- type AgentWorkflowStep
- type AllowedPath
- type CLIOverrides
- type ContinuationResult
- type ContinuationStopReason
- type QueryExecutor
- type WorkflowExecutionState
- type WorkflowSubagentOverride
- type WorkflowSubagentOverrides
Constants ¶
const ( WorkflowWhenAlways = "always" WorkflowWhenOnSuccess = "on_success" WorkflowWhenOnError = "on_error" DefaultWorkflowOrchestrationStateFile = ".sprout/workflow_state.json" DefaultWorkflowOrchestrationEventsFile = ".sprout/workflow_events.jsonl" DefaultWorkflowConversationSessionID = "workflow" )
const DefaultContinuationIdlePrompt = "" /* 329-byte string literal not displayed */
DefaultContinuationIdlePrompt follows a turn that made no progress: it names that state so the coordinator commits verified work or records why an item is blocked instead of re-verifying again.
const DefaultContinuationPrompt = "" /* 229-byte string literal not displayed */
DefaultContinuationPrompt is the short prompt issued on each continuation turn: it tells the coordinator to re-read the TODO file and keep processing without re-deriving its whole plan.
const DefaultContinuationTodoFile = "TODO.md"
DefaultContinuationTodoFile is used when Continuation.TodoFile is empty.
const DefaultMaxContinuations = 1000
DefaultMaxContinuations bounds continuation turns when unset.
const DefaultMaxIdleTurns = 2
DefaultMaxIdleTurns bounds consecutive no-progress turns when unset.
const PathModeReadOnly = "read_only"
PathModeReadOnly declares the declared external folder is read-only — writes against any path under it must be refused by the filesystem gate.
const PathModeReadWrite = "read_write"
PathModeReadWrite declares the declared external folder is fully readable and writable for the duration of the workflow run.
Variables ¶
This section is empty.
Functions ¶
func ApplyWorkflowCommandOverrides ¶
func ApplyWorkflowCommandOverrides(cfg *AgentWorkflowConfig, overrides *CLIOverrides)
func ApplyWorkflowInitialOverrides ¶
func ApplyWorkflowInitialOverrides(chatAgent *agent.Agent, cfg *AgentWorkflowConfig, overrides *CLIOverrides) error
func ApplyWorkflowRuntimeAllowedPaths ¶ added in v0.17.7
func ApplyWorkflowRuntimeAllowedPaths(chatAgent *agent.Agent, paths []AllowedPath) (snapshotPaths []string, snapshotModes map[string]string, addedPaths []string, err error)
ApplyWorkflowRuntimeAllowedPaths adds each path in paths (derived from AllowedPath entries in the step's runtime config) to the agent's session allowlist and records the declared mode. This lets the cd-target gate (Phase 2.1) and the filesystem gate (Phase 2.2) see the paths as approved for the duration of the step.
Snapshot semantics: the snapshot captures the state BEFORE any paths are added, so restoreWorkflowRuntimeAllowedPaths can undo only the paths this step added — not paths contributed by earlier steps. This means consecutive steps that declare overlapping paths have the documented "last restore wins" behavior: step 2's snapshot contains step 1's contribution; step 2's restore removes both step 2's new paths AND step 1's old paths. Declare overlapping paths in each step that needs them, or promote them to the workflow-level AllowedPaths, if you need per-step isolation.
Idempotent: adding a path that's already on the allowlist is a no-op; it is NOT included in addedPaths, so it will NOT be removed on restore.
func ApplyWorkflowRuntimeOverrides ¶
func ApplyWorkflowRuntimeOverrides(chatAgent *agent.Agent, runtime AgentWorkflowRuntime, overrides *CLIOverrides) error
func ApplyWorkflowSubagentOverrides ¶
func ApplyWorkflowSubagentOverrides(subagentTypes map[string]configuration.SubagentType, overrides WorkflowSubagentOverrides)
ApplyWorkflowSubagentOverrides patches the SubagentTypes map entries matching the given overrides. No error is returned for unknown personas — they are skipped. Log lines are emitted for every skip and every successful apply so that silent divergence between the workflow JSON and the actual SubagentTypes is visible.
func AttachWorkflowBudget ¶
func AttachWorkflowBudget(chatAgent *agent.Agent, cfg *AgentWorkflowConfig) (stop func())
AttachWorkflowBudget wires the workflow's USD budget and progress heartbeat onto the agent. Returns a stop function the caller MUST invoke before the agent shuts down — it unregisters callbacks and stops the heartbeat goroutine. If no budget is configured the returned stop is a no-op and no goroutines are started.
Heartbeat semantics:
- Default cadence: 600s when a budget is configured, off otherwise.
- cfg.Progress.HeartbeatSeconds > 0 overrides the cadence.
- The heartbeat prints to stdout in a single line so it composes with existing console output without clobbering it.
func EmitWorkflowOrchestrationEvent ¶
func EmitWorkflowOrchestrationEvent(cfg *AgentWorkflowConfig, eventType string, payload map[string]interface{}) error
func FindSubagentTypeMapKey ¶
func FindSubagentTypeMapKey(subagentTypes map[string]configuration.SubagentType, normalizedID string) (string, bool)
FindSubagentTypeMapKey finds the original map key in SubagentTypes matching the given normalized persona ID. It mirrors the lookup logic in config.go GetSubagentType.
func IsSystemPathPrefix ¶ added in v0.17.7
IsSystemPathPrefix reports whether the (already-cleaned, absolute) path falls under one of the OS system directories. Used by the loader to emit a warning when a workflow declares an allowed_path inside a system prefix — the user is touching platform infrastructure and deserves the louder heads-up, even though the workflow is allowed to proceed.
The list mirrors pkg/agent/path_tier.go::systemPathPrefixes; both should grow together if a new OS system directory is added. We keep the list local to the workflow package rather than importing the agent package (workflow is a leaf dependency — agent imports workflow, not the other way around).
Exported (capitalized) so pkg/automate/discovery.go::Summarize can reuse the same prefix list when rendering the WebUI/CLI summary.
func IsValidWorkflowWhen ¶
func LoadLoopCheckpoint ¶
LoadLoopCheckpoint reads the fallback checkpoint file and returns the line number. Returns (0, nil) if the file doesn't exist.
func LoopCheckpointFilePath ¶
LoopCheckpointFilePath returns the path to the lightweight fallback checkpoint file that stores just the TODO line number.
func NormalizeWorkflowPaths ¶
func NormalizeWorkflowPersonaID ¶
NormalizeWorkflowPersonaID normalizes a persona ID the same way config.go does.
func NormalizeWorkflowWhen ¶
func ParseBudgetWarnList ¶
ParseBudgetWarnList parses a comma-separated list of fractional thresholds (e.g. "0.5,0.8") into a sorted []float64. Each value must be in (0, 1].
func PersistLoopCheckpoint ¶
PersistLoopCheckpoint writes just the line number to the fallback checkpoint file using an atomic write (temp file + rename).
func PersistWorkflowCheckpoint ¶
func PersistWorkflowCheckpoint(cfg *AgentWorkflowConfig, state *WorkflowExecutionState, chatAgent *agent.Agent) error
func PersistWorkflowConversationState ¶
func PersistWorkflowConversationState(chatAgent *agent.Agent, cfg *AgentWorkflowConfig) error
func PersistWorkflowExecutionState ¶
func PersistWorkflowExecutionState(cfg *AgentWorkflowConfig, state *WorkflowExecutionState) error
func PrepareWorkflowRuntimeRestorer ¶
func PrepareWorkflowRuntimeRestorer(chatAgent *agent.Agent, cfg *AgentWorkflowConfig, overrides *CLIOverrides) (func() error, error)
func ReadTodoStatus ¶ added in v0.23.0
func ReadTodoStatus(todoFile string) todoStatus
ReadTodoStatus reads a TODO file and counts runnable and completed items. A missing or unreadable file yields a zero status (nothing runnable) with no error — the continuation gate treats that as "nothing left to do" rather than failing the run. This is one of the two gates that must agree before another turn is issued.
func RemoveLoopCheckpoint ¶
func RemoveLoopCheckpoint(workDir string)
RemoveLoopCheckpoint deletes the fallback checkpoint file, ignoring not-found errors.
func ResolveStepPrompt ¶
func ResolveStepPrompt(step AgentWorkflowStep) (string, error)
func ResolveWorkflowInitialPrompt ¶
func ResolveWorkflowInitialPrompt(cliQuery string, cfg *AgentWorkflowConfig) (string, error)
func RestoreWorkflowConversationState ¶
func RestoreWorkflowConversationState(chatAgent *agent.Agent, cfg *AgentWorkflowConfig, state *WorkflowExecutionState) error
func RestoreWorkflowRuntimeAllowedPaths ¶ added in v0.17.7
func RestoreWorkflowRuntimeAllowedPaths(chatAgent *agent.Agent, snapshotPaths []string, snapshotModes map[string]string, addedPaths []string) error
restoreWorkflowRuntimeAllowedPaths undoes the paths added by the matching ApplyWorkflowRuntimeAllowedPaths call for this step. It is called at every step exit point (success, failure, skip, shell) to ensure no step's allowed_paths leak into the next step.
Restore semantics:
- For each path in addedPaths: if it was NOT in snapshotPaths, remove it from the allowlist (it was added by this step).
- For each path in snapshotPaths: restore its mode from snapshotModes (may be different from what a prior step left behind).
This means if step 1 adds /a and step 2 adds /b then /a:
- After step 1: allowlist = [/a]
- Step 2 snapshot: [/a]
- Step 2 addedPaths: [/b] (/a was already there)
- Step 2 restore removes [/b], leaves [/a]
- After step 2: allowlist = [/a]
This is the documented "steps don't inherit paths from prior steps" behavior.
func RunAgentWorkflow ¶
func RunAgentWorkflow(ctx context.Context, chatAgent *agent.Agent, eventBus *events.EventBus, cfg *AgentWorkflowConfig, state *WorkflowExecutionState, queryExecutor QueryExecutor, overrides *CLIOverrides) (bool, error)
func RunAgentWorkflowLoop ¶
func RunAgentWorkflowLoop(ctx context.Context, chatAgent *agent.Agent, eventBus *events.EventBus, cfg *AgentWorkflowConfig, state *WorkflowExecutionState, queryExecutor QueryExecutor, overrides *CLIOverrides) (bool, error)
RunAgentWorkflowLoop iterates over unchecked TODO items, processing each with a fresh agent context. Between items, the conversation is cleared.
func ShouldRestoreWorkflowConversationState ¶
func ShouldRestoreWorkflowConversationState(state *WorkflowExecutionState) bool
func ShouldRunWorkflowStep ¶
func ShouldYieldBeforeWorkflowStep ¶
func ShouldYieldBeforeWorkflowStep(cfg *AgentWorkflowConfig, state *WorkflowExecutionState, nextStep AgentWorkflowStep, chatAgent *agent.Agent) bool
func StepFileTriggersSatisfied ¶
func StepFileTriggersSatisfied(step AgentWorkflowStep) (bool, error)
func WorkflowEffectiveStepProvider ¶
func WorkflowEffectiveStepProvider(chatAgent *agent.Agent, step AgentWorkflowStep) string
Types ¶
type AgentWorkflowBudgetConfig ¶
type AgentWorkflowBudgetConfig struct {
// USD is the hard cap on cumulative cost across the workflow.
// <= 0 means no cap.
USD float64 `json:"usd,omitempty"`
// WarnAt is a list of fractional thresholds (0.0–1.0). When the
// cumulative spend first crosses each threshold, a single warning
// is emitted to stdout and (when wired) the event bus.
// Empty defaults to [0.50, 0.80].
WarnAt []float64 `json:"warn_at,omitempty"`
// OnExceed controls what happens when USD is reached.
// "truncate" (default) sets the truncation flag so the run finishes
// the current LLM response and stops gracefully. "stop" is reserved
// for future hard-kill behavior; today it's treated like truncate.
OnExceed string `json:"on_exceed,omitempty"`
}
AgentWorkflowBudgetConfig caps the total USD spend of a workflow run (primary agent + every subagent it spawns share the same budget).
USD-denominated rather than tokens because mixed-provider workflows route different personas to different price tiers — a token cap that covers an Opus orchestrator would let a DeepSeek coder consume 50× the work for the same budget, defeating the cap.
type AgentWorkflowConfig ¶
type AgentWorkflowConfig struct {
Description string `json:"description,omitempty"`
Initial *AgentWorkflowInitial `json:"initial,omitempty"`
Steps []AgentWorkflowStep `json:"steps"`
ContinueOnError bool `json:"continue_on_error,omitempty"`
PersistRuntimeOverrides *bool `json:"persist_runtime_overrides,omitempty"`
Orchestration *AgentWorkflowOrchestrationConfig `json:"orchestration,omitempty"`
NoWebUI *bool `json:"no_web_ui,omitempty"`
WebPort *int `json:"web_port,omitempty"`
Daemon *bool `json:"daemon,omitempty"`
Budget *AgentWorkflowBudgetConfig `json:"budget,omitempty"`
Progress *AgentWorkflowProgressConfig `json:"progress,omitempty"`
// SubagentTimeoutSeconds overrides the per-run_subagent tool timeout
// (default 1800 = 30 minutes). Set higher for very large refactors.
SubagentTimeoutSeconds *int `json:"subagent_timeout_seconds,omitempty"`
// RequiresApproval controls whether the run_automate agent tool must
// surface an intent-confirmation prompt to the user before launching
// this workflow. Pointer so we can distinguish "unset" (default: true)
// from explicit false. Set to false for workflows that exist
// specifically so an agent can invoke them mid-task — e.g. a
// validation workflow referenced from AGENTS.md that the model must
// run before considering work done. Anyone with workflow-file access
// can flip this, so the security implication should be obvious to a
// reader of the JSON.
//
// Only affects the agent tool path. The CLI (`sprout automate run`)
// always prompts unless --yes is passed, because a human at the
// keyboard might still fat-finger the wrong workflow.
RequiresApproval *bool `json:"requires_approval,omitempty"`
// Loop configures the workflow to iterate over a TODO file, processing
// each unchecked item independently with a fresh agent context.
// When Loop is set, Steps are ignored — the loop IS the execution plan.
Loop *AgentWorkflowLoopConfig `json:"loop,omitempty"`
// Continuation keeps a coordinator-style initial session going after
// its final answer. Unlike Loop — which starts a fresh gate-driven
// agent context per item — continuation re-invokes the same
// coordinator turn with a short prompt, so the agent's own workflow
// is preserved. After each turn the TODO file is re-read: while
// runnable `[ ]` items remain AND the turn made progress (a new git
// commit or a newly ticked item), another turn is issued. The loop
// stops when nothing runnable is left or a turn makes no progress,
// so permanently skipped items cannot spin forever.
Continuation *AgentWorkflowContinuation `json:"continuation,omitempty"`
// AllowedPaths declares the external directories the workflow needs
// to read or write outside the workspace. Each entry is validated by
// AllowedPath.Validate and pre-seeded into the running agent's
// session allowlist (with mode) at run start so the workflow
// doesn't re-prompt for every external access. See
// `roadmap/SP-128-workflow-allowed-paths.md` for the full design.
AllowedPaths []AllowedPath `json:"allowed_paths,omitempty"`
}
AgentWorkflowConfig defines non-interactive workflow orchestration.
func LoadAgentWorkflowConfig ¶
func LoadAgentWorkflowConfig(path string) (*AgentWorkflowConfig, error)
func (*AgentWorkflowConfig) IsApprovalRequired ¶
func (c *AgentWorkflowConfig) IsApprovalRequired() bool
IsApprovalRequired reports whether the run_automate tool path should surface an intent-confirmation prompt before launching this workflow. Defaults to true when unset.
func (*AgentWorkflowConfig) OrchestrationEnabled ¶
func (c *AgentWorkflowConfig) OrchestrationEnabled() bool
func (*AgentWorkflowConfig) OrchestrationResumeEnabled ¶
func (c *AgentWorkflowConfig) OrchestrationResumeEnabled() bool
func (*AgentWorkflowConfig) OrchestrationYieldOnProviderHandoff ¶
func (c *AgentWorkflowConfig) OrchestrationYieldOnProviderHandoff() bool
func (*AgentWorkflowConfig) ShouldPersistRuntimeOverrides ¶
func (c *AgentWorkflowConfig) ShouldPersistRuntimeOverrides() bool
func (*AgentWorkflowConfig) Validate ¶
func (c *AgentWorkflowConfig) Validate() error
type AgentWorkflowContinuation ¶ added in v0.23.0
type AgentWorkflowContinuation struct {
// TodoFile is the markdown file scanned for runnable `[ ]` items.
// Default: TODO.md.
TodoFile string `json:"todo_file,omitempty"`
// ContinueUntilDone enables the continuation loop. Pointer so an
// explicit false disables it even when the block is present; nil
// means enabled (a present block is intent to continue).
ContinueUntilDone *bool `json:"continue_until_done,omitempty"`
// MaxContinuations caps the number of continuation turns issued
// after the initial turn, as a hard backstop. Default: 1000.
MaxContinuations int `json:"max_continuations,omitempty"`
// MaxIdleTurns is how many consecutive turns may end without progress
// (no new commit, no newly ticked item) before the loop stops. A turn
// can legitimately end idle, e.g. after re-verifying work a subagent
// left uncommitted; the next turn gets DefaultContinuationIdlePrompt.
// Default: DefaultMaxIdleTurns.
MaxIdleTurns int `json:"max_idle_turns,omitempty"`
// Prompt is the short prompt sent on each continuation turn.
// Empty uses DefaultContinuationPrompt.
Prompt string `json:"prompt,omitempty"`
}
AgentWorkflowContinuation keeps a coordinator-style initial session going after its final answer. It is the coordinator-loop counterpart to Loop: instead of a fresh per-item gate context, it re-invokes the same coordinator turn with a short continuation prompt once the turn's answer has come back, and re-reads the TODO file between turns.
A turn is "another turn" only if the previous turn made progress — it produced a new git commit or newly ticked a `[ ]` item. When nothing runnable remains, or a turn makes no progress, the loop stops and records why. That is what stops permanently skipped items (items left `[ ]` by design) from looping forever.
func (*AgentWorkflowContinuation) IsEnabled ¶ added in v0.23.0
func (c *AgentWorkflowContinuation) IsEnabled() bool
IsEnabled reports whether the continuation loop should run. A nil receiver or nil ContinueUntilDone means enabled; only an explicit false disables it.
type AgentWorkflowInitial ¶
type AgentWorkflowInitial struct {
Prompt string `json:"prompt,omitempty"`
PromptFile string `json:"prompt_file,omitempty"`
AllowedPaths []AllowedPath `json:"allowed_paths,omitempty"`
AgentWorkflowRuntime
}
AgentWorkflowInitial is the first run definition (can replace CLI prompt).
type AgentWorkflowLoopConfig ¶
type AgentWorkflowLoopConfig struct {
// TodoFile is the markdown file to scan for [ ] items. Default: TODO.md.
TodoFile string `json:"todo_file,omitempty"`
// GatePromptFile is the system prompt for the gate LLM call that
// parses each TODO section into a structured delegation prompt.
// Required. The gate call uses the agent's existing client.
GatePromptFile string `json:"gate_prompt_file,omitempty"`
// MaxRetries is the number of retry attempts on build failure
// before skipping an item. Default: 2.
MaxRetries int `json:"max_retries,omitempty"`
// MaxIterations caps the agent iterations per item. Default: 50.
MaxIterations int `json:"max_iterations,omitempty"`
// BuildCommand is run after each item to verify. Default: "go build ./...".
BuildCommand string `json:"build_command,omitempty"`
}
AgentWorkflowLoopConfig configures the workflow to iterate over a TODO file, processing each unchecked item independently with a fresh agent context. When Loop is set, Steps are ignored — the loop IS the execution plan.
type AgentWorkflowOrchestrationConfig ¶
type AgentWorkflowOrchestrationConfig struct {
Enabled bool `json:"enabled,omitempty"`
Resume *bool `json:"resume,omitempty"`
YieldOnProviderHandoff *bool `json:"yield_on_provider_handoff,omitempty"`
StateFile string `json:"state_file,omitempty"`
EventsFile string `json:"events_file,omitempty"`
ConversationSessionID string `json:"conversation_session_id,omitempty"`
}
AgentWorkflowOrchestrationConfig enables external orchestration integration.
type AgentWorkflowProgressConfig ¶
type AgentWorkflowProgressConfig struct {
// HeartbeatSeconds is the interval at which the workflow prints a
// progress line ([budget] $X of $Y · iter N · elapsed Tm).
// <= 0 disables the heartbeat. Default 600 (10 min) when Budget is set.
HeartbeatSeconds int `json:"heartbeat_seconds,omitempty"`
}
AgentWorkflowProgressConfig controls runtime visibility of the workflow.
type AgentWorkflowRuntime ¶
type AgentWorkflowRuntime struct {
SkipPrompt *bool `json:"skip_prompt,omitempty"`
Provider string `json:"provider,omitempty"`
Model string `json:"model,omitempty"`
Persona string `json:"persona,omitempty"`
DryRun *bool `json:"dry_run,omitempty"`
MaxIterations *int `json:"max_iterations,omitempty"`
NoStream *bool `json:"no_stream,omitempty"`
SystemPrompt string `json:"system_prompt,omitempty"`
SystemPromptFile string `json:"system_prompt_file,omitempty"`
Unsafe *bool `json:"unsafe,omitempty"`
NoSubagents *bool `json:"no_subagents,omitempty"`
ResourceDirectory string `json:"resource_directory,omitempty"`
ReasoningEffort string `json:"reasoning_effort,omitempty"`
SubagentOverrides WorkflowSubagentOverrides `json:"subagent_overrides,omitempty"`
// RiskProfile selects a named shell-command risk cascade preset
// for this step / initial run (SP-058). One of: readonly,
// cautious, default, permissive, unrestricted. Per-step values
// override the workflow-level initial setting and the global
// config. Unknown values fall through to the agent's default
// resolution chain (override > config > "default").
RiskProfile string `json:"risk_profile,omitempty"`
}
AgentWorkflowRuntime contains runtime options aligned with agent CLI flags.
func (*AgentWorkflowRuntime) Validate ¶
func (r *AgentWorkflowRuntime) Validate(prefix string) error
type AgentWorkflowStep ¶
type AgentWorkflowStep struct {
Name string `json:"name,omitempty"`
Prompt string `json:"prompt,omitempty"`
PromptFile string `json:"prompt_file,omitempty"`
Command string `json:"command,omitempty"`
CommandFile string `json:"command_file,omitempty"`
When string `json:"when,omitempty"`
FileExists []string `json:"file_exists,omitempty"`
FileNotExists []string `json:"file_not_exists,omitempty"`
AllowedPaths []AllowedPath `json:"allowed_paths,omitempty"`
AgentWorkflowRuntime
}
AgentWorkflowStep is a single step executed after the initial query.
A step is either an agent step (Prompt or PromptFile) or a shell step (Command or CommandFile). The two kinds are mutually exclusive — validation fails if both are set or neither is set.
Shell steps run the command via the user's $SHELL (or /bin/sh) with the workflow's working directory and inherit stdout/stderr. They do NOT trigger model inference; they are useful for cheap, deterministic steps like `make build`, `git status`, or invoking a custom script that prepares state for the next agent step.
func (AgentWorkflowStep) IsShellStep ¶
func (s AgentWorkflowStep) IsShellStep() bool
IsShellStep reports whether the step is configured to run a shell command instead of triggering model inference.
type AllowedPath ¶ added in v0.17.7
type AllowedPath struct {
// Path is the absolute path to the directory. Must be absolute,
// free of `..` traversal after Clean(), and must not start with
// `~` (refuse to expand; user must provide the canonical absolute
// path).
Path string `json:"path"`
// Mode is one of {read_only, read_write}. The filesystem layer
// enforces this: a write tool called against a read_only entry
// gets a security error explaining the declared mode blocked it.
Mode string `json:"mode"`
// Reason is surfaced verbatim in the launch confirmation dialog
// so the user understands why the workflow needs this path.
// Strongly recommended; loader does not require it.
Reason string `json:"reason,omitempty"`
}
AllowedPath is a single directory the workflow needs access to outside the workspace. Declared at the workflow level so the user can review every external path in one place at launch time, and the runtime can pre-seed the session allowlist so no per-tool approval dialogs fire mid-run.
Rules enforced by Validate:
- Path must be absolute (filepath.IsAbs).
- Path must not contain `..` segments after filepath.Clean.
- Path must not start with `~` (we refuse to expand — the workflow author must supply a canonical absolute path).
- Mode must be one of {read_only, read_write} (case-sensitive).
- Reason is optional; loader does not require it.
Paths that fall under a known system prefix (see isSystemPathPrefix) trigger a warning via log.Printf — the loader surfaces that warning so the user is aware the workflow touches platform infrastructure, but the path itself is allowed. Sensitive-path blocking is enforced elsewhere (filesystem tier classification / path_tier.go).
func (*AllowedPath) Validate ¶ added in v0.17.7
func (a *AllowedPath) Validate() error
Validate enforces the schema rules documented on AllowedPath. Returns nil for a valid entry; a descriptive error otherwise. The error message identifies the offending field so the loader can attribute the failure to the right entry index.
type CLIOverrides ¶
type CLIOverrides struct {
SetWebUI func(disabled bool)
SetWebPort func(port int)
SetDaemon func(enabled bool)
SetNoStream func(enabled bool)
GetNoStream func() bool
// Budget/heartbeat CLI overrides. Zero values mean "inherit JSON".
BudgetUSD float64
BudgetWarn string
HeartbeatSeconds int
}
CLIOverrides provides the callback functions that applyWorkflowCommandOverrides needs to mutate CLI-level global flags (web UI, port, daemon, streaming, budget, heartbeat). The cmd/ package constructs this with closures over its real flag variables.
type ContinuationResult ¶ added in v0.23.0
type ContinuationResult struct {
// Continuations is the number of continuation turns issued after the
// initial turn.
Continuations int `json:"continuations"`
// StopReason is the classified stop condition.
StopReason ContinuationStopReason `json:"stop_reason"`
// RunnableItems is the number of `[ ]` items observed when the loop
// stopped (0 for a clean finish).
RunnableItems int `json:"runnable_items"`
// Err is set when StopReason is turn_error or context_cancelled.
Err error `json:"-"`
}
ContinuationResult reports the outcome of a continuation run so the caller can record the stop reason in the run record.
func RunInitialContinuation ¶ added in v0.23.0
func RunInitialContinuation(ctx context.Context, chatAgent *agent.Agent, eventBus *events.EventBus, cfg *AgentWorkflowConfig, state *WorkflowExecutionState, queryExecutor QueryExecutor) (ContinuationResult, error)
RunInitialContinuation runs the coordinator continuation loop after the initial agent turn has completed. It issues continuation turns via queryExecutor until no runnable `[ ]` items remain, the session stops making progress, the budget is hit, the context is cancelled, or the configured MaxContinuations cap is reached. The returned ContinuationResult carries the stop reason for the run record.
queryExecutor is the same executor the initial turn used, so the coordinator keeps its context (continuation does NOT clear the conversation between turns — that is the whole point).
type ContinuationStopReason ¶ added in v0.23.0
type ContinuationStopReason string
ContinuationStopReason describes why the continuation loop stopped. It is surfaced in the run record and events so a post-mortem can tell a clean finish from a no-progress stop.
const ( // ContinuationStopNoRunnableItems — no `[ ]` items remain (all done, // or only non-item prose remains). ContinuationStopNoRunnableItems ContinuationStopReason = "no_runnable_items" // ContinuationStopNoProgress — runnable items remain but MaxIdleTurns // consecutive turns neither committed nor ticked an item (e.g. // permanently skipped items). ContinuationStopNoProgress ContinuationStopReason = "no_progress" // ContinuationStopContextCancelled — the run was cancelled mid-turn. ContinuationStopContextCancelled ContinuationStopReason = "context_cancelled" // ContinuationStopBudgetExceeded — the USD budget was hit. ContinuationStopBudgetExceeded ContinuationStopReason = "budget_exceeded" // ContinuationStopMaxContinuations — the hard turn cap was reached. ContinuationStopMaxContinuations ContinuationStopReason = "max_continuations" // ContinuationStopTurnError — a continuation turn returned an error. ContinuationStopTurnError ContinuationStopReason = "turn_error" )
type QueryExecutor ¶
type QueryExecutor func(ctx context.Context, chatAgent *agent.Agent, eventBus *events.EventBus, query string) error
QueryExecutor is the signature of cmd.ProcessQuery. The runner and loop accept this as a dependency so the workflow package never imports cmd/.
type WorkflowExecutionState ¶
type WorkflowExecutionState struct {
Version int `json:"version"`
InitialCompleted bool `json:"initial_completed"`
NextStepIndex int `json:"next_step_index"`
CurrentTodoLineNum int `json:"current_todo_line_num,omitempty"`
HasError bool `json:"has_error"`
FirstError string `json:"first_error,omitempty"`
LastProvider string `json:"last_provider,omitempty"`
Complete bool `json:"complete"`
UpdatedAt string `json:"updated_at,omitempty"`
}
WorkflowExecutionState tracks workflow execution progress for checkpoint/resume support.
func LoadWorkflowExecutionState ¶
func LoadWorkflowExecutionState(cfg *AgentWorkflowConfig) (*WorkflowExecutionState, error)
func NewWorkflowExecutionState ¶
func NewWorkflowExecutionState() *WorkflowExecutionState
type WorkflowSubagentOverride ¶
type WorkflowSubagentOverride struct {
Provider string `json:"provider,omitempty"`
Model string `json:"model,omitempty"`
}
WorkflowSubagentOverride defines per-persona subagent provider/model overrides.
type WorkflowSubagentOverrides ¶
type WorkflowSubagentOverrides map[string]WorkflowSubagentOverride
WorkflowSubagentOverrides maps persona IDs to their subagent routing overrides. Keys are normalized persona IDs (lowercase, hyphens→underscores). Values override provider/model for subagents with that persona.