campaign

package
v0.167.0 Latest Latest
Warning

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

Go to latest
Published: May 11, 2026 License: AGPL-3.0 Imports: 7 Imported by: 0

Documentation

Overview

Package campaign implements the PromptZero Campaigns feature (roadmap P2-19) — declarative, YAML-authored multi-step engagement specs that compose the existing agent tool surface.

A campaign file describes scope, an ordered list of steps, and a report template. The Runner executes each step against a StepExecutor (typically the agent's dispatch path) and emits a RunResult that slots cleanly into internal/report for human- readable output.

This ships the foundation. Cron scheduling, a web UI, and expression-based when-conditions beyond substring containment are explicit future work — the types are forward-compatible with those additions.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AgentExecutor

type AgentExecutor struct {
	Dispatcher ToolDispatcher
}

AgentExecutor adapts a ToolDispatcher to the campaign StepExecutor interface. Production wiring passes the agent's dispatch (see cmd/promptzero). Keeping the adapter here avoids pulling the agent package into internal/campaign.

func (AgentExecutor) Run

func (a AgentExecutor) Run(ctx context.Context, tool string, params map[string]interface{}) (string, error)

Run implements StepExecutor. Empty tool name is rejected early because a misread YAML file is more recoverable with a clean error than with a deep dispatch failure.

type Campaign

type Campaign struct {
	Name     string       `yaml:"campaign"`
	Scope    Scope        `yaml:"scope,omitempty"`
	Schedule string       `yaml:"schedule,omitempty"`
	Steps    []Step       `yaml:"steps"`
	Report   ReportConfig `yaml:"report,omitempty"`
}

Campaign is the top-level document a campaign YAML decodes into. Name, Scope, Schedule, Steps, Report all survive round-trip.

func Load

func Load(path string) (*Campaign, error)

Load parses a campaign YAML file from disk. Validates presence of the `campaign:` name and at least one step. Duplicate step IDs and unresolved depends_on references are rejected so invalid files fail at load time rather than mid-run.

func ParseYAML

func ParseYAML(data []byte) (*Campaign, error)

ParseYAML decodes a campaign YAML byte slice and validates the cross-step invariants. Exposed separately so tests can exercise the validator without filesystem I/O.

type ReportConfig

type ReportConfig struct {
	Template string `yaml:"template,omitempty"`
	Signed   bool   `yaml:"signed,omitempty"`
}

ReportConfig controls how RunResult is summarised. Template is an informational label today (the Markdown renderer is the only implementation); Signed hints whether the operator wants a cosign signature on the final report — wired when the Campaigns runner integrates with the release-style signing path.

type RunResult

type RunResult struct {
	Campaign    string
	StartedAt   time.Time
	EndedAt     time.Time
	StepResults []StepResult
	Err         error // fatal run error (validator, executor panic); per-step errors live on StepResult
}

RunResult is the outcome of one Runner.Run. Carries the per-step log, wall-clock span, and a roll-up pass/fail flag. Designed so a future /report template (or the Campaigns runner's own renderer) can format it without re-walking individual steps.

func (RunResult) Duration

func (r RunResult) Duration() time.Duration

Duration is EndedAt - StartedAt when both are set. Useful for report hands-on-time calculations.

func (RunResult) Succeeded

func (r RunResult) Succeeded() bool

Succeeded reports whether every step succeeded (or was cleanly skipped). False when any step errored.

type Runner

type Runner struct {
	// contains filtered or unexported fields
}

Runner executes a Campaign against a StepExecutor. Safe to reuse across multiple Run() calls — no cached state between invocations.

func NewRunner

func NewRunner(exec StepExecutor) *Runner

NewRunner constructs a Runner. Nil executor is acceptable at construction time but will cause Run to fail fast when invoked.

func (*Runner) Run

func (r *Runner) Run(ctx context.Context, c *Campaign) RunResult

Run executes every step in order. Steps with DependsOn wait for their predecessor to complete; a failed predecessor marks the dependent step Skipped with SkipReason="dependency <id> failed". When clauses are evaluated against the predecessor's output and default to pass when no predecessor is referenced.

Ctx cancellation aborts the run between steps — an in-flight executor call observes the same ctx and is expected to honour it.

type Scope

type Scope struct {
	AuthorizedNetworks []string `yaml:"authorized_networks,omitempty"`
	AuthorizedDevices  []string `yaml:"authorized_devices,omitempty"`
	OutOfScope         []string `yaml:"out_of_scope,omitempty"`
}

Scope captures the authorisation envelope the campaign operates under. Runner does not enforce scope — it's metadata for the report + for human review before kick-off — but the types are here so a future Runner.EnforceScope pass can grow without reshuffling YAML.

type Step

type Step struct {
	ID        string                 `yaml:"id"`
	Tool      string                 `yaml:"tool"`
	Params    map[string]interface{} `yaml:"params,omitempty"`
	DependsOn string                 `yaml:"depends_on,omitempty"`
	When      string                 `yaml:"when,omitempty"`
	// Timeout caps per-step execution. Zero means "no limit" and
	// the executor's own timeout policy governs. Example: "30s",
	// "2m".
	Timeout string `yaml:"timeout,omitempty"`
}

Step is one ordered campaign action. Tool is the agent tool name (e.g. "wifi_scan_ap"); Params is its JSON-object arguments. When a Step has DependsOn, it runs only after the predecessor completed successfully; When, if non-empty, gates execution on the predecessor's output matching the condition.

type StepExecutor

type StepExecutor interface {
	Run(ctx context.Context, tool string, params map[string]interface{}) (output string, err error)
}

StepExecutor is the interface the Runner uses to invoke an agent tool. Production wiring passes the agent's dispatch path; tests pass a stub. Keeping the interface minimal means a future Web / MCP surface can plug its own executor without touching the Runner.

type StepResult

type StepResult struct {
	StepID     string
	Tool       string
	Output     string
	Err        error
	Duration   time.Duration
	Skipped    bool
	SkipReason string
	StartedAt  time.Time
}

StepResult captures the outcome of one step in a RunResult. Skipped fires when a step's When clause evaluated false or its DependsOn predecessor failed.

func (StepResult) Succeeded

func (r StepResult) Succeeded() bool

Succeeded reports whether the step ran to completion without error.

type ToolDispatcher

type ToolDispatcher interface {
	RunTool(ctx context.Context, tool string, params map[string]interface{}) (string, error)
}

ToolDispatcher is the narrow interface Campaigns asks of an agent- backed executor — one method that runs a named tool with params and returns (output, error). Mirrors the shape of the rules engine's RunTool callback so both surfaces can share an adapter.

Jump to

Keyboard shortcuts

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