workflow

package
v0.29.1 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2026 License: Apache-2.0 Imports: 22 Imported by: 0

Documentation

Index

Constants

View Source
const (
	WorkflowWhenAlways    = "always"
	WorkflowWhenOnSuccess = "on_success"
	WorkflowWhenOnError   = "on_error"

	DefaultWorkflowOrchestrationStateFile  = ".sprout/workflow_state.json"
	DefaultWorkflowOrchestrationEventsFile = ".sprout/workflow_events.jsonl"
	DefaultWorkflowConversationSessionID   = "workflow"
)
View Source
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.

View Source
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.

View Source
const DefaultContinuationTodoFile = "TODO.md"

DefaultContinuationTodoFile is used when Continuation.TodoFile is empty.

View Source
const DefaultMaxContinuations = 1000

DefaultMaxContinuations bounds continuation turns when unset.

View Source
const DefaultMaxIdleTurns = 2

DefaultMaxIdleTurns bounds consecutive no-progress turns when unset.

View Source
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.

View Source
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

func IsSystemPathPrefix(p string) bool

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 IsValidWorkflowWhen(v string) bool

func LoadLoopCheckpoint

func LoadLoopCheckpoint(workDir string) (int, error)

LoadLoopCheckpoint reads the fallback checkpoint file and returns the line number. Returns (0, nil) if the file doesn't exist.

func LoopCheckpointFilePath

func LoopCheckpointFilePath(workDir string) string

LoopCheckpointFilePath returns the path to the lightweight fallback checkpoint file that stores just the TODO line number.

func NormalizeReasoningEffort

func NormalizeReasoningEffort(v string) string

func NormalizeWorkflowPaths

func NormalizeWorkflowPaths(paths []string) []string

func NormalizeWorkflowPersonaID

func NormalizeWorkflowPersonaID(raw string) string

NormalizeWorkflowPersonaID normalizes a persona ID the same way config.go does.

func NormalizeWorkflowWhen

func NormalizeWorkflowWhen(v string) string

func ParseBudgetWarnList

func ParseBudgetWarnList(s string) ([]float64, error)

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

func PersistLoopCheckpoint(workDir string, lineNum int) error

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 ResolveWorkflowTextOrFile

func ResolveWorkflowTextOrFile(text, filePath, label string) (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 ShouldRunWorkflowStep(when string, hasError bool) bool

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

func WriteFileAtomic

func WriteFileAtomic(path string, data []byte, perm os.FileMode) error

WriteFileAtomic writes data to path atomically by writing to a temp file in the same directory and then renaming. This prevents partial/corrupt state files if the process crashes mid-write.

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.

Jump to

Keyboard shortcuts

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