workflow

package
v0.13.0 Latest Latest
Warning

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

Go to latest
Published: May 19, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package workflow is the domain for AI-orchestrated multi-step automations stored at `<BaseDir>/workflows/<id>/`. A workflow is a directed acyclic graph of typed nodes (classify/agent/connector/ shell/http/branch/parallel/merge/dataset_*/transform/end) with one or more triggers (cron, channel, webhook, manual, schedule_at, error). The engine walks the graph node-by-node, persists state per run, and reuses existing wick infra (channels, connectors, providers, pool).

See `internal/docs/workflow-design.md` for the full contract.

Index

Constants

View Source
const (
	OverflowDropOldest = "drop_oldest"
	OverflowDropNew    = "drop_new"
	OverflowReject     = "reject"
)

Overflow policy values.

View Source
const (
	FailHalt     = "halt"
	FailSkip     = "skip"
	FailFallback = "fallback"
)

OnFailure values.

View Source
const (
	MergeObject = "object"
	MergeArray  = "array"
	MergeFirst  = "first"
	MergeLast   = "last"
)

MergeStrategy values.

View Source
const (
	SessionNew        = "new"
	SessionRoot       = "root"
	SessionPersistent = "persistent"
)

Session modes for agent/classify nodes.

Legacy values "root" and "persistent" predate the pool-integration design; they remain in the constant list so loaders that touch old YAML round-trip cleanly, but the engine treats them as equivalent to the per-run default (no override). New workflows should use the `session_init` node instead — see internal/docs/workflow/pool.md.

View Source
const (
	SessionPresetWorkflowRun    = "workflow_run"
	SessionPresetWorkflowGlobal = "workflow_global"
	SessionPresetNew            = "new"
)

Session preset values for the `session_init` node. `preset:` and `id:` are mutually exclusive — when `id:` is set the executor renders it as a template; otherwise it falls back to the preset pattern.

View Source
const (
	StatusQueued  = "queued"
	StatusRunning = "running"
	StatusPaused  = "paused"
	StatusSuccess = "success"
	StatusFailed  = "failed"
)

RunStatus values.

View Source
const (
	EventNodeStarted       = "node_started"
	EventNodeCompleted     = "node_completed"
	EventNodeFailed        = "node_failed"
	EventNodeSkipped       = "node_skipped"
	EventEdgeTraversed     = "edge_traversed"
	EventWorkflowStarted   = "workflow_started"
	EventWorkflowCompleted = "workflow_completed"
	EventWorkflowFailed    = "workflow_failed"
)

Event types emitted to events.jsonl.

Variables

This section is empty.

Functions

This section is empty.

Types

type ClassifyExample

type ClassifyExample struct {
	Input  string `yaml:"input"`
	Output string `yaml:"output"`
}

ClassifyExample is a few-shot prompt example.

type DatasetBinding

type DatasetBinding struct {
	Name            string `yaml:"name"`
	Ref             string `yaml:"ref"`
	Mode            string `yaml:"mode,omitempty"`
	ExpectedVersion int    `yaml:"expected_version,omitempty"`
}

DatasetBinding wires a dataset alias to a dataset slug.

type DatasetOrder

type DatasetOrder struct {
	Column    string `yaml:"column"`
	Direction string `yaml:"direction,omitempty"`
}

DatasetOrder is one order-by clause.

type Edge

type Edge struct {
	From  string `yaml:"from"`
	To    string `yaml:"to"`
	Case  string `yaml:"case,omitempty"`
	Label string `yaml:"label,omitempty"`
}

Edge is a directed connection from one node to another. Case is only meaningful when From is a classify or branch node.

type EnvField

type EnvField struct {
	Name        string            `yaml:"name"`
	Widget      string            `yaml:"widget,omitempty"`
	Desc        string            `yaml:"desc,omitempty"`
	Default     string            `yaml:"default,omitempty"`
	Required    bool              `yaml:"required,omitempty"`
	Locked      bool              `yaml:"locked,omitempty"`
	Hidden      bool              `yaml:"hidden,omitempty"`
	Options     []EnvOption       `yaml:"options,omitempty"`
	VisibleWhen map[string]string `yaml:"visible_when,omitempty"`
}

EnvField is one entry of the workflow's env schema.

func (EnvField) IsSecret

func (f EnvField) IsSecret() bool

IsSecret reports whether this field is the encrypted variant.

type EnvOption

type EnvOption struct {
	ID   string `yaml:"id"`
	Name string `yaml:"name"`
}

EnvOption is one choice for dropdown/picker widgets.

type Event

type Event struct {
	Type    string         `json:"type"`
	Subtype string         `json:"subtype,omitempty"`
	Channel string         `json:"channel,omitempty"`
	At      time.Time      `json:"at"`
	Payload map[string]any `json:"payload,omitempty"`
	// TriggerID is the workflow.Trigger.ID of the entry that matched
	// this dispatch. Populated by the router immediately before
	// enqueue; empty for manual / RunNow paths where no specific
	// trigger fired. workflow_watch(trigger_id=...) reads this to
	// filter runs back to the originating trigger.
	TriggerID string `json:"trigger_id,omitempty"`
}

Event is the trigger payload passed to a run. Minimal envelope — channel/transport-specific keys (user, text, thread, chat_id, callback_id, path, …) live in Payload so each integration owns its own shape. Workflow templates reference them as `{{.Event.Payload.<key>}}`.

Type identifies the trigger family ("channel" | "webhook" | "cron" | "manual" | "error" | "schedule_at"). Subtype is the within-family discriminator: for channel events it's the event name ("message", "block_action", …); for webhooks empty; for cron the schedule expression label; for error the source workflow.

Channel is the module name when Type=="channel" ("slack", "telegram", …). Empty for non-channel triggers.

type ExecError

type ExecError struct {
	Node    string
	Type    NodeType
	Wrapped error
}

ExecError wraps an executor failure with node identity. Engine promotes this to state.Error.

func (*ExecError) Error

func (e *ExecError) Error() string

func (*ExecError) Unwrap

func (e *ExecError) Unwrap() error

type Executor

type Executor interface {
	Execute(ctx context.Context, node Node, rctx *RunContext) (NodeOutput, error)
}

Executor runs one node body. Engine resolves the executor by node.Type and dispatches with the rendered context.

type Graph

type Graph struct {
	Entry string `yaml:"entry"`
	Nodes []Node `yaml:"nodes"`
	Edges []Edge `yaml:"edges"`
}

Graph is the DAG body: flat node list + separate edge list.

type Node

type Node struct {
	// Common
	ID           string         `yaml:"id"`
	Type         NodeType       `yaml:"type"`
	Label        string         `yaml:"label,omitempty"`
	Description  string         `yaml:"description,omitempty"`
	TimeoutSec   int            `yaml:"timeout_sec,omitempty"`
	Retry        *RetryPolicy   `yaml:"retry,omitempty"`
	OnFailure    string         `yaml:"on_failure,omitempty"`
	Fallback     string         `yaml:"fallback,omitempty"`
	OutputSchema map[string]any `yaml:"output_schema,omitempty"`

	// parallel
	Branches []string `yaml:"branches,omitempty"`

	// merge
	Inputs   []string `yaml:"inputs,omitempty"`
	Strategy string   `yaml:"strategy,omitempty"`

	// classify + agent
	Provider   string `yaml:"provider,omitempty"`
	Preset     string `yaml:"preset,omitempty"`
	Prompt     string `yaml:"prompt,omitempty"`
	PromptFile string `yaml:"prompt_file,omitempty"`
	Session    string `yaml:"session,omitempty"` // agent: "new" → fresh UUID; "" → inherit rc.DefaultAgentSessionID. Also used by session_init for legacy aliasing.

	// agent override — copy resolved sessionID from another node in
	// this run. Must reference an upstream agent or session_init node.
	SessionFrom string `yaml:"session_from,omitempty"`

	// session_init — preset shortcut OR rendered template id. Mutually
	// exclusive; SessionID wins when both set. `Preset` reuses the
	// classify/agent Preset field above for YAML brevity.
	SessionID string `yaml:"session_id,omitempty"`

	// classify
	OutputCases         []string          `yaml:"output_cases,omitempty"`
	StructuredOutput    *bool             `yaml:"structured_output,omitempty"`
	Normalize           *bool             `yaml:"normalize,omitempty"`
	FuzzyMatch          bool              `yaml:"fuzzy_match,omitempty"`
	RetryOnMismatch     int               `yaml:"retry_on_mismatch,omitempty"`
	ConfidenceThreshold float64           `yaml:"confidence_threshold,omitempty"`
	Examples            []ClassifyExample `yaml:"examples,omitempty"`

	// agent
	Workspace string   `yaml:"workspace,omitempty"`
	Skills    []string `yaml:"skills,omitempty"`
	Tools     []string `yaml:"tools,omitempty"`
	MaxTurns  int      `yaml:"max_turns,omitempty"`

	// channel (action) — Channel field name avoided clash with Event.Channel
	ChannelName string         `yaml:"channel,omitempty"`
	Op          string         `yaml:"op,omitempty"`
	Args        map[string]any `yaml:"args,omitempty"`
	// ArgModes records each arg's editor mode: "fixed" = literal value
	// (executor skips template render), "expression" = Go template (the
	// default behaviour kept for backward compat when ArgModes has no
	// entry for a key). Persisted so the inspector restores the toggle
	// state and so safer-by-default semantics survive a publish round
	// trip. Defaults to template render when an arg key is missing
	// here, matching pre-ArgModes workflows.
	ArgModes map[string]string `yaml:"arg_modes,omitempty"`

	// connector — uses row_id for instance (dataset_* nodes own `row:`)
	Module string `yaml:"module,omitempty"`
	Row    string `yaml:"row_id,omitempty"`

	// shell
	Command     []string          `yaml:"command,omitempty"`
	ShellEnv    map[string]string `yaml:"env,omitempty"`
	Cwd         string            `yaml:"cwd,omitempty"`
	ParseOutput string            `yaml:"parse_output,omitempty"`

	// http
	Method        string            `yaml:"method,omitempty"`
	URL           string            `yaml:"url,omitempty"`
	Headers       map[string]string `yaml:"headers,omitempty"`
	Query         map[string]string `yaml:"query,omitempty"`
	Body          string            `yaml:"body,omitempty"`
	ParseResponse string            `yaml:"parse_response,omitempty"`

	// db_query — uses `sql:` key (HTTP node already owns `query:` for query params)
	Database string   `yaml:"database,omitempty"`
	SQL      string   `yaml:"sql,omitempty"`
	SQLArgs  []string `yaml:"sql_args,omitempty"`

	// transform
	Engine     string `yaml:"engine,omitempty"`
	Input      string `yaml:"input,omitempty"`
	Expression string `yaml:"expression,omitempty"`

	// go_script — full Go program. Engine pipes RenderCtx JSON to
	// stdin, parses stdout as JSON for the result.
	Code string `yaml:"code,omitempty"`

	// branch
	Expr string `yaml:"expr,omitempty"`

	// switch — first-match-wins rule list. Each rule's `when` is a Go
	// template that renders to a bool (supports the same binary ops as
	// `branch`: ==, !=, <, <=, >, >=) or any non-empty string (truthy).
	// First rule whose `when` evaluates true wins; engine emits
	// Verdict=<rule.case> so the edge `case: <label>` filter routes
	// downstream. DefaultCase fires when no rule matches.
	Cases       []SwitchCase `yaml:"cases,omitempty"`
	DefaultCase string       `yaml:"default_case,omitempty"`

	// dataset_*
	Dataset   string         `yaml:"dataset,omitempty"`
	Where     map[string]any `yaml:"where,omitempty"`
	Key       map[string]any `yaml:"key,omitempty"`
	RowValues map[string]any `yaml:"row,omitempty"`
	OrderBy   []DatasetOrder `yaml:"order_by,omitempty"`
	Limit     int            `yaml:"limit,omitempty"`
	Offset    int            `yaml:"offset,omitempty"`

	// end
	Result string `yaml:"result,omitempty"`
}

Node is a single step in the graph. Fields are a flat union — only the subset relevant to Type is read by the executor. Validator rejects nodes that set fields outside their type.

type NodeError

type NodeError struct {
	Node    string `json:"node"`
	Type    string `json:"type"`
	Message string `json:"message"`
	Stack   string `json:"stack,omitempty"`
}

NodeError captures a failed node's diagnostic.

type NodeOutput

type NodeOutput struct {
	Verdict    string         `json:"verdict,omitempty"`
	Confidence float64        `json:"confidence,omitempty"`
	Reasoning  string         `json:"reasoning,omitempty"`
	Result     any            `json:"result,omitempty"`
	Fields     map[string]any `json:"-"` // merged into top-level when serialized
}

NodeOutput is what an executor returns. It is stored in state.Outputs[node.ID] and surfaced via `{{.Node.<id>.X}}`. The `Verdict` field is the routing key for classify/branch nodes.

type NodeSession

type NodeSession struct {
	From string `yaml:"from,omitempty"`
	Mode string `yaml:"mode,omitempty"`
}

NodeSession is the per-agent-node session override. Empty struct means "use rc.DefaultAgentSessionID (or the engine fallback)".

  • From — copy the resolved sessionID from another node in this run (must be an upstream agent/session_init node, validator rejects forward refs + cycles)
  • Mode — "new" forces a fresh UUID per call; empty inherits

type NodeType

type NodeType string

NodeType is the discriminator for the polymorphic Node body.

const (
	NodeClassify      NodeType = "classify"
	NodeAgent         NodeType = "agent"
	NodeChannel       NodeType = "channel"
	NodeConnector     NodeType = "connector"
	NodeShell         NodeType = "shell"
	NodeSwitch        NodeType = "switch"
	NodeGoScript      NodeType = "go_script"
	NodePython        NodeType = "python"
	NodeHTTP          NodeType = "http"
	NodeDBQuery       NodeType = "db_query"
	NodeTransform     NodeType = "transform"
	NodeBranch        NodeType = "branch"
	NodeParallel      NodeType = "parallel"
	NodeMerge         NodeType = "merge"
	NodeEnd           NodeType = "end"
	NodeDatasetGet    NodeType = "dataset_get"
	NodeDatasetExists NodeType = "dataset_exists"
	NodeDatasetQuery  NodeType = "dataset_query"
	NodeDatasetInsert NodeType = "dataset_insert"
	NodeDatasetUpsert NodeType = "dataset_upsert"
	NodeDatasetDelete NodeType = "dataset_delete"
	NodeDatasetCount  NodeType = "dataset_count"
	NodeSessionInit   NodeType = "session_init"
)

func (NodeType) IsBranchSource

func (t NodeType) IsBranchSource() bool

IsBranchSource reports whether nodes of this type produce a verdict that filters outgoing edges by `case:`.

func (NodeType) IsDatasetNode

func (t NodeType) IsDatasetNode() bool

IsDatasetNode reports whether t is one of the dataset_* variants.

type OnErrorBinding

type OnErrorBinding struct {
	TriggerWorkflow   string `yaml:"trigger_workflow"`
	Severity          string `yaml:"severity,omitempty"`
	IncludeState      bool   `yaml:"include_state,omitempty"`
	IncludeNodeOutput bool   `yaml:"include_node_output,omitempty"`
}

OnErrorBinding declares which error-handler workflow to fire on failure.

type Override

type Override struct {
	Reason string
	User   string
}

Override carries an optional human override when approving past a guard failure.

type QueuePolicy

type QueuePolicy struct {
	MaxSize    int    `yaml:"max_size,omitempty"`
	OnOverflow string `yaml:"on_overflow,omitempty"` // drop_oldest | drop_new | reject
}

QueuePolicy controls per-workflow concurrency.

type RenderCtx

type RenderCtx struct {
	Event    Event
	Node     map[string]any
	Env      map[string]string
	Secret   map[string]string
	Workflow WorkflowRef
	Run      RunRef
	Dataset  map[string]any
}

RenderCtx is the root object exposed to Go templates inside node bodies. Fields map 1:1 to the design refs:

{{.Event.X}}        — trigger event payload
{{.Node.<id>.X}}    — output of completed node X
{{.Env.X}}          — non-secret workflow env value
{{.Secret.X}}       — encrypted secret, decrypted on lookup
{{.Workflow.X}}     — workflow metadata
{{.Run.X}}          — runtime metadata
{{.Dataset.<alias>}} — dataset binding from datasets: list

type RetryPolicy

type RetryPolicy struct {
	Max        int `yaml:"max"`
	BackoffSec int `yaml:"backoff_sec,omitempty"`
}

RetryPolicy on a node.

type RunContext

type RunContext struct {
	Workflow    Workflow
	Event       Event
	Outputs     map[string]any
	EnvValues   map[string]string
	Secrets     map[string]string
	RunID       string
	NodeOutputs map[string]NodeOutput

	// TriggerNodeID is the canvas/yaml node id under which the run's
	// firing trigger surfaces in {{.Node.<id>.…}}. Set by the engine
	// when pickEntry resolves a trigger row (uses Trigger.ID when set,
	// else falls back to the entry node id). Empty for legacy runs
	// (graph.entry fallback) — those still expose data via .Event.
	TriggerNodeID string

	// DefaultAgentSessionID is set by an upstream `session_init` node
	// and consumed by downstream `agent` nodes that don't override
	// session: themselves. Empty = engine falls back to the per-run
	// pattern "wf:<id>:run:<runID>". See pool.md for the resolver
	// order.
	DefaultAgentSessionID string

	// AgentSessionIDs maps node ID → resolved sessionID for every
	// agent / session_init node that has run. Lets downstream agent
	// nodes opt into "reuse this upstream's subprocess" via
	// `session_from: <node-id>` without re-resolving the template.
	AgentSessionIDs map[string]string
}

RunContext carries per-run state into executors. It's a thin pointer-receiver wrapper so executors can read outputs from upstream nodes + read env/secrets without taking the entire engine.

func (*RunContext) RenderCtx

func (r *RunContext) RenderCtx() RenderCtx

RenderCtx materializes a RenderCtx from the RunContext for template rendering inside an executor.

type RunEvent

type RunEvent struct {
	TS    time.Time      `json:"ts"`
	Event string         `json:"event"`
	Node  string         `json:"node,omitempty"`
	Case  string         `json:"case,omitempty"`
	Data  map[string]any `json:"data,omitempty"`
}

RunEvent is one line in events.jsonl.

type RunRef

type RunRef struct {
	ID        string
	StartedAt string
}

RunRef carries runtime metadata for templates.

type RunState

type RunState struct {
	RunID      string                `json:"run_id"`
	WorkflowID string                `json:"workflow_id"`
	Version    int                   `json:"version"`
	Status     string                `json:"status"`
	Entry      string                `json:"entry"`
	Current    []string              `json:"current"`
	Completed  []string              `json:"completed"`
	Failed     []string              `json:"failed,omitempty"`
	Skipped    []string              `json:"skipped,omitempty"`
	Outputs    map[string]any        `json:"outputs"`
	Event      Event                 `json:"event"`
	Error      *NodeError            `json:"error,omitempty"`
	Sessions   map[string]SessionRec `json:"sessions,omitempty"`
	StartedAt  time.Time             `json:"started_at"`
	UpdatedAt  time.Time             `json:"updated_at"`
	EndedAt    *time.Time            `json:"ended_at,omitempty"`
}

RunState is the persisted execution snapshot.

type SessionRec

type SessionRec struct {
	PID            int       `json:"pid"`
	StartedAt      time.Time `json:"started_at"`
	LastHeartbeat  time.Time `json:"last_heartbeat"`
	TranscriptPath string    `json:"transcript_path,omitempty"`
}

SessionRec tracks a long-lived agent subprocess across nodes.

type SwitchCase

type SwitchCase struct {
	When string `yaml:"when"`
	Case string `yaml:"case"`
}

SwitchCase is one rule row for `switch` nodes. `When` is a Go template expression (e.g. `{{.Event.Payload.action}} == "approve"`) rendered against the run context; `Case` is the verdict label the engine emits when the rule wins, matched against outgoing edge `case:` filters.

type Trigger

type Trigger struct {
	ID        string      `yaml:"id,omitempty"`
	Type      TriggerType `yaml:"type"`
	EntryNode string      `yaml:"entry_node,omitempty"`

	// cron
	Schedule string `yaml:"schedule,omitempty"`
	Timezone string `yaml:"timezone,omitempty"`

	// channel
	ChannelName string         `yaml:"channel,omitempty"`
	Event       string         `yaml:"event,omitempty"`
	Target      string         `yaml:"target,omitempty"`
	Match       map[string]any `yaml:"match,omitempty"`
	// MatchEnabled gates whether the router applies Match at dispatch
	// time. false (default) = dump-all (every event of this type fires
	// the workflow); true = router skips runs where Match values don't
	// pair with the event payload. Backward compat for workflows that
	// stored match: without an explicit toggle is to treat a populated
	// Match map as enabled — see router.go for the resolution rule.
	MatchEnabled bool              `yaml:"match_enabled,omitempty"`
	MatchModes   map[string]string `yaml:"match_modes,omitempty"`
	Whitelist    *Whitelist        `yaml:"whitelist,omitempty"`
	DedupTTLSec  int               `yaml:"dedup_ttl_sec,omitempty"`
	ReplySource  *bool             `yaml:"reply_source,omitempty"`

	// webhook
	Path      string `yaml:"path,omitempty"`
	Method    string `yaml:"method,omitempty"`
	SecretRef string `yaml:"secret_ref,omitempty"`
	ParseBody string `yaml:"parse_body,omitempty"`
	BodyToVar string `yaml:"body_to_var,omitempty"`

	// manual
	Label       string `yaml:"label,omitempty"`
	RequireRole string `yaml:"require_role,omitempty"`

	// schedule_at
	At          time.Time `yaml:"at,omitempty"`
	DeleteAfter bool      `yaml:"delete_after,omitempty"`

	// error
	SourceWorkflow string   `yaml:"source_workflow,omitempty"`
	Severity       []string `yaml:"severity,omitempty"`
	NodeTypes      []string `yaml:"node_types,omitempty"`
}

Trigger is one polymorphic trigger entry. Fields are a flat union like Node — the validator gates each field to its Type.

ID is the stable canvas identifier (e.g. "trigger_manual", "trigger-cron-2"). The codec uses it to merge per-trigger metadata (channel name, schedule, …) across save cycles so the canvas can re-wire EntryNode without losing the config the user typed in the inspector. Optional in YAML — workflows hand-edited without canvas can omit it.

func (Trigger) MarshalYAML

func (tr Trigger) MarshalYAML() (any, error)

MarshalYAML normalizes Match before serialization — picker values stored as JSON strings (`[{"id":"C1","name":"#ch"}]`) are expanded to native YAML slices so the workflow.yaml is human-readable and AI-writable without JSON escaping.

type TriggerType

type TriggerType string

TriggerType discriminator for the polymorphic Trigger body.

const (
	TriggerCron       TriggerType = "cron"
	TriggerChannel    TriggerType = "channel"
	TriggerWebhook    TriggerType = "webhook"
	TriggerManual     TriggerType = "manual"
	TriggerScheduleAt TriggerType = "schedule_at"
	TriggerError      TriggerType = "error"
)

type Whitelist

type Whitelist struct {
	Users  []string `yaml:"users,omitempty"`
	Groups []string `yaml:"groups,omitempty"`
	IPs    []string `yaml:"ips,omitempty"`
}

Whitelist filters who can fire a trigger.

type Workflow

type Workflow struct {
	ID             string           `yaml:"id"`
	Version        int              `yaml:"version"`
	Name           string           `yaml:"name"`
	Description    string           `yaml:"description,omitempty"`
	Enabled        bool             `yaml:"enabled"`
	MaxDurationSec int              `yaml:"max_duration_sec,omitempty"`
	Triggers       []Trigger        `yaml:"triggers"`
	Queue          QueuePolicy      `yaml:"queue,omitempty"`
	Env            []EnvField       `yaml:"env,omitempty"`
	Datasets       []DatasetBinding `yaml:"datasets,omitempty"`
	Graph          Graph            `yaml:"graph"`
	OnError        *OnErrorBinding  `yaml:"on_error,omitempty"`
	CreatedBy      string           `yaml:"created_by,omitempty"`
	CreatedAt      time.Time        `yaml:"created_at,omitempty"`
	Canvas         map[string]any   `yaml:"_canvas,omitempty"`
}

Workflow is the root document parsed from `workflow.yaml`.

ID is the stable folder name (UUID for canvas-created workflows, arbitrary id for legacy hand-edited ones). Display title lives in Name and is freely renameable — the folder/URL/log paths stay anchored to ID so run history survives a rename.

type WorkflowRef

type WorkflowRef struct {
	ID      string
	Version int
	Name    string
}

WorkflowRef is the small subset of Workflow accessible to templates.

type WorkflowState

type WorkflowState struct {
	Approved        bool       `json:"approved"`
	ApprovedBy      string     `json:"approved_by,omitempty"`
	ApprovedAt      *time.Time `json:"approved_at,omitempty"`
	ApprovedVersion int        `json:"approved_version,omitempty"`
	ContentHash     string     `json:"content_hash,omitempty"`
	GovernanceMode  string     `json:"governance_mode,omitempty"`
	OverrideReason  string     `json:"override_reason,omitempty"`
}

WorkflowState is the persisted approval/governance snapshot.

Directories

Path Synopsis
Package canvas mutates a Workflow's graph atomically.
Package canvas mutates a Workflow's graph atomically.
Package channel is a thin adapter over internal/agents/channels.
Package channel is a thin adapter over internal/agents/channels.
Package connector is the workflow-facing index of connector modules.
Package connector is the workflow-facing index of connector modules.
Package cost aggregates per-node + per-workflow LLM usage.
Package cost aggregates per-node + per-workflow LLM usage.
Package dataset is the workflow-facing data store.
Package dataset is the workflow-facing data store.
Package engine — multi-subscriber event broker.
Package engine — multi-subscriber event broker.
Package env validates and resolves the workflow's env schema + values.
Package env validates and resolves the workflow's env schema + values.
Package guard reviews a workflow body for safety violations before publish.
Package guard reviews a workflow body for safety violations before publish.
Package integration is the workflow-side surface for per-event + per-action node descriptors.
Package integration is the workflow-side surface for per-event + per-action node descriptors.
Package mcp — workflow_describe implementation.
Package mcp — workflow_describe implementation.
Package nodes contains the concrete Executor impls for every Node type.
Package nodes contains the concrete Executor impls for every Node type.
Package parse decodes and validates workflow.yaml bodies.
Package parse decodes and validates workflow.yaml bodies.
Package provider is the abstraction the workflow engine talks to for classify + agent nodes.
Package provider is the abstraction the workflow engine talks to for classify + agent nodes.
Package scaffold provides workflow starter templates used by `workflow_create` MCP op + UI "New workflow" form.
Package scaffold provides workflow starter templates used by `workflow_create` MCP op + UI "New workflow" form.
Package service is the CRUD facade over `<BaseDir>/workflows/`.
Package service is the CRUD facade over `<BaseDir>/workflows/`.
Package setup wires every workflow subpkg together.
Package setup wires every workflow subpkg together.
Package state persists per-run state.json + events.jsonl under `<BaseDir>/workflows/<id>/runs/<run-id>/`.
Package state persists per-run state.json + events.jsonl under `<BaseDir>/workflows/<id>/runs/<run-id>/`.
Package template renders Go text/template strings against a workflow.RenderCtx.
Package template renders Go text/template strings against a workflow.RenderCtx.
Package trigger is the dispatch + queue + dedup layer between trigger sources (cron, channel adapter, webhook, manual, error) and the engine.
Package trigger is the dispatch + queue + dedup layer between trigger sources (cron, channel adapter, webhook, manual, error) and the engine.
Package wftest runs workflow test cases loaded from `__tests__/` fixtures.
Package wftest runs workflow test cases loaded from `__tests__/` fixtures.

Jump to

Keyboard shortcuts

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