evo

package module
v0.2.12 Latest Latest
Warning

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

Go to latest
Published: Jul 29, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

README

Evident Output

Go presentation library for CLI state, progress, evidence, changes, plans, and conclusions.

Application code owns execution. Package evo owns presentation only.

Quick start

import (
    "os"
    evo "github.com/zachbornheimer/evident-output"
)

func main() {
    out := evo.New(evo.Config{Title: "bpp-csharp"})
    os.Exit(evo.Main(out, run))
}

func run(out *evo.Output) error {
    // Start as casually as fmt — then promote to structure when useful.
    out.Println("Reading configuration")
    out.Printf("Found %d packages\n", 18)
    out.Verbose().Printf("Cache: %s\n", "/var/cache")

    out.Item("working tree").OK()
    out.Item("branches").Block(
        "local-only branch",
        evo.Detail("commit or stash before continuing"),
    )
    return nil // Block is a presentation outcome, not a Go error
}
go get github.com/zachbornheimer/evident-output@v0.2.12

Requires Go 1.25+. License: Apache-2.0.

Design philosophy and polish-phase basis: docs/roadmap/implementation-basis.md, docs/philosophy/.

Construction: evo.New() / evo.New(Config{…}) / DefaultConfig() — TTY, NO_COLOR, stdout/stderr defaults included. Advanced: NewWithOptions(Title(...), …).
Config honesty: VisibilityDelay: evo.Delay(0) is immediate (nil = default 150ms). Debug.Level: LevelTrace selectable (LevelUnset → Info).
Lifecycle: os.Exit(evo.Main(out, run)) seals Finish + Close + exit code; a non-nil run error is recorded as Fail only when nothing already failed.
Messages: one human instrument — Print / Printf / Println + Verbose(). Infrastructure logs: slog.New(out.SlogHandler()) (level from Config.Debug.Level only). Semantic state: Item/Task.
Capture: Task.Capture (work) or Item.Capture (tool-backed gate); silent by default; pending fragments in DetailTail; Config.Redactor before retention.
Platform: evo.ID + narrow Scope (Item/Task/Tasks only — not a sandbox); ResultWriter() under FormatData.

Pick the entity

Shape Use when
Item Check / gate / verdict unit (pass–fail)
Task Work with phases or progress
Tasks Collection of independent tasks (state is derived)
Changes Past-tense durable effects that happened
Plan Dry-run would-happen effects

When both Item and Task fit: prefer Item for pass/fail gates, Task for progress. Multi-gate: resolve every Item, then if out.AnyBlocked() { return nil } before mutation; Main maps ExitCode.

Severity dialect

Outcome Meaning
Warn Soft concern or optional tool missing; command may continue
Block Policy / precondition failed; stop before mutation (evaluation succeeded)
Fail Evaluation failed or required tool/IO failed

Block ≠ Go error. After Block, return nil from run and let Main exit 1.

Child processes / tool-backed gates

Capture belongs to the entity (Task or Item), not the whole session — and not context:

upgrade := out.Task("brew packages")
output := upgrade.Capture() // always retains a bounded ring; debug only controls display

if err := run.Run(ctx, "brew", []string{"upgrade", "--formula"}, output); err != nil {
    upgrade.Fail("brew upgrade failed", evo.Cause(err), output.DetailTail())
    return nil
}
upgrade.Done()

Tool-backed condition (still an Item):

docker := out.Item("docker daemon").Start()
cap := docker.Capture()
if err := runDockerInfo(cap); err != nil {
    docker.Fail("could not inspect the daemon", evo.Cause(err), cap.DetailTail())
} else {
    docker.OK()
}
  • Ownership: Task.Capture / Item.Capture associate evidence with that entity.
  • Silent by default: ring always retains; no Diagnostics/Debug mirror unless MirrorToDiagnostics() / MirrorToDebug().
  • Redaction: Config.Redactor (or evo.Redact) applies before ring retention.
  • Detail: DetailTail() is a ProblemOption; separate Stdout()/Stderr() buffers.
  • Defaults: last 200 lines / 256KiB via KeepLastLines / MaxCaptureBytes.
  • Session out.Capture: advanced only — prefer entity-owned capture.

Platform adapters (contracts, not sugar)

Keep the core vocabulary small. Scale via Config, schema keys, and stream contracts:

Need Contract
Stable machine identity out.Item("label", evo.ID("gate.tree")) — keys appear in Snapshot/JSON
Plugin / subsystem namespace out.Scope("registry").Task("pull", evo.ID("image")) → key registry.image (IDs only; not isolation)
Domain payload purity Format: FormatData + json.NewEncoder(out.ResultWriter()) (stdout); human on stderr
Secret scrubbing Config.Redactor or evo.Redact(r) — Debug fields + Capture ring
Host-owned rendering FormatExternal + snapshots (no inline stream)

Avoid inventing parallel APIs (RunAll, framework-specific facades in core). Prefer one Config field or EntityOption over a new top-level type.

Status

Release: v0.2.12 — pin maintenance class closed: PublishedRelease + auto-walk drift gate + sync-release-pins (no ad-hoc skill/README pin edits). Portable install forbids @latest and personal clone paths.
Architecture spec: v0.5 (design candidate).
Implemented surface: ordinary ladder through Plan/Changes/Capture/slog/ResultWriter; interactive VT; hardened MCP; polish-phase docs under docs/. External/manual items remain waived (Windows ConPTY / tmux / SSH RC, a11y contrast / screen-reader, host RC matrices and a11y manual reviews).

Ready now External / manual only
Items, Task, Tasks, Changes, Plan, Print Windows ConPTY RC (PORT-003)
Conclusion + exit codes + Cancel cleanup tmux RC (PORT-004)
Plain, JSON (§25.1), JSONL (§25.2) SSH RC (PORT-005)
Interactive live region (testkit.Screen) Light/dark contrast review (A11Y-006)
SlogHandler, DebugWriter, Suspend, Snapshots(), MaxEntities, MaxEvents, AlsoWrite Screen-reader review (A11Y-007)
Appendix H.1–H.22 + agent harness + multi-file GoPackage review
ANSI driver + width/CJK + OSC strip + s390x cross-compile
CLI: review / preview / explain (real JSON)
MCP: lifecycle, protocol negotiate, unknown-field reject, panic contain, token budget, remote-path reject, catalog checksum
Framework adapter examples (urfave/Kong shapes, no core deps)

Vocabulary

Type Meaning
Item Named condition that stays in the final report
Task One operation (phase / progress / done)
Tasks Collection of independent tasks (state is derived)
Problem Structured evidence for warn / block / fail
Changes / Plan Effects that happened vs would happen
Conclusion Headline + Changed / Partial / Cancelled + exit code
Main Finish + Close + process exit code for CLI entrypoints

Do not put schedulers, RunAll, retries, or shell execution in this library. Review rule API-026 flags those helpers only on evo receivers (AST), not strings.Map.

Develop

mise run setup    # go mod download
mise run test     # unit + roast
mise run test-race
mise run conformance
mise run traceability   # all §31 IDs present
mise run ci             # lint + test + scan + conformance + traceability

Trunk is configured daemonless (--monitor=false). Prefer mise over raw tools.

Conformance (roast)

conformance/ is the executable specification (Raku/roast model):

  • TRACEABILITY.md — all 272 §31 IDs dispositioned (267 pass, 5 waived with reason + owner for external/manual only; 0 untested)
  • schema/scenario.v1.json — declarative scenario dialect
  • scenarios/*.json + Go Appendix H tests (appendix_h_test.go)

Architecture source (current design candidate): docs/architecture/EVIDENT_OUTPUT_ARCHITECTURE_SPEC_v0.5.md.
Prior implemented baseline: docs/architecture/EVIDENT_OUTPUT_ARCHITECTURE_SPEC_v0.3.md.

Completeness vs §31 (v0.3 matrix): docs/architecture/COMPLETENESS_MATRIX.md (267 pass / 5 waived).

Examples (adoption ladder)
examples/print/              Print, Printf, Println
examples/verbose/            visibility gating (--verbose)
examples/repo-status/        Items, Problems, actions
examples/install-pipeline/   Tasks + Capture
examples/migrate/            Plan versus Changes
examples/doctor/             severity dialect + WriteJSON
examples/data-command/       machine stdout / human stderr (ResultWriter)
examples/scope-plugin/       Scope + ID for plugin namespaces
examples/live-progress/      ordinary multi-progress
examples/debug-history/      slog durable debug
examples/debug-pane/         rolling slog viewport
examples/terminal-driver/    advanced custom TerminalDriver
mise run examples          # non-interactive batch
go run ./examples/print/
go run ./examples/verbose/ --verbose
CLI
go run ./cmd/evident-output review path/to/file.go   # JSON findings (exit 1 if recheck_required)
go run ./cmd/evident-output preview --item=status --state=ok
go run ./cmd/evident-output explain API-006
go run ./cmd/evident-output version
MCP (stdio)

The companion server evident-output-mcp is a local stdio MCP process (no hosted URL). Stdin/stdout are JSON-RPC only; logs go to stderr. Transport supports NDJSON (MCP spec) and Content-Length framing (some client SDKs).

Advertised tool names use underscores (Grok rejects dotted tool names and then registers tool_count: 0). Dotted aliases still work on tools/call.

Tool name (tools/list) Grok use_tool id Purpose
evident_output_list_guides evident-output__evident_output_list_guides Guidance catalog
evident_output_get_guidance evident-output__evident_output_get_guidance Sections by id
evident_output_review evident-output__evident_output_review Go / transcript / JSON review
evident_output_preview evident-output__evident_output_preview Plain profile previews
evident_output_explain evident-output__evident_output_explain Rule id (rule_id)

explain arguments: { "rule_id": "DOM-011" } (not id).

Install the binary (pinned)
mkdir -p "$HOME/.local/bin"

# Module install (network + sumdb) — pin a release tag, never @latest:
GOBIN="$HOME/.local/bin" go install \
  github.com/zachbornheimer/evident-output/cmd/evident-output-mcp@v0.2.12

# Or from a local clone of this repo:
#   git clone https://github.com/zachbornheimer/evident-output.git
#   cd evident-output && go build -o "$HOME/.local/bin/evident-output-mcp" ./cmd/evident-output-mcp

"$HOME/.local/bin/evident-output-mcp" --version

Host configs must use an absolute command (or ${HOME}/… where the host expands it). Bare evident-output-mcp fails when the agent process PATH omits ~/.local/bin.

Verify without restarting an existing TUI session
# Process-level handshake
grok mcp doctor evident-output --json
# expect: healthy=true, "5 tools discovered", protocol 2025-06-18

# Fresh agent process (same attach path as the TUI); use any trusted cwd:
grok -p 'Call use_tool on evident-output__evident_output_list_guides with {}. Reply CONNECTED and the text field, or FAILED.' \
  --output-format plain \
  --max-turns 5 \
  --always-approve
# expect: CONNECTED / "5 guides"

If doctor is green but headless says FAILED, check session events.jsonl for mcp_server_connected with "tool_count":0 (tool names/schemas rejected) vs mcp_server_failed (spawn/handshake).

NDJSON smoke (no Grok required):

printf '%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"manual","version":"0"}}}' \
  '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \
  | "$HOME/.local/bin/evident-output-mcp" 2>/dev/null
Host config snippets (print-only)
"$HOME/.local/bin/evident-output-mcp" config --client grok
# also: claude-code|codex|gemini|opencode  — uses ${HOME}/.local/bin/…

Integrations: integrations/ · skill: skills/cli-output/SKILL.md

Grok (xAI TUI / Build)
# $HOME/.grok/config.toml  (${HOME} expanded by Grok)
[mcp_servers.evident-output]
command = "${HOME}/.local/bin/evident-output-mcp"
enabled = true
startup_timeout_sec = 30
grok mcp add evident-output -- "$HOME/.local/bin/evident-output-mcp"
grok mcp list
grok mcp doctor evident-output --json

Project scope only starts when the folder is trusted. Prefer user scope for always-on tools.

See integrations/grok/README.md.

Claude Code / Cursor / Codex
"$HOME/.local/bin/evident-output-mcp" config --client claude-code
"$HOME/.local/bin/evident-output-mcp" config --client codex

Review kinds for evident_output_review: go (default), transcript, json / structured.

Examples

Small real programs (flags, help, exit codes) — not snippets. Copy a whole folder as a starting shape.

Example Pattern
repo-status Parallel Items (OK / blocked / warn), conclusion exit code
install-pipeline Tasks collection with Progress/Bytes/Fail (final report)
migrate Plan dry-run vs Changes apply (--apply)
doctor Mixed doctor items; --json snapshot on stdout
data-command Data command: JSON stdout, human report stderr
live-progress Live multi-progress: bars + indeterminate phases (ANSI on stderr)
debug-history DebugHistory: durable HH:MM:SS [DEBUG] … above live/items
debug-pane DebugPane: rolling slog pane; --fail keeps diagnostics tail
mise run examples                          # all, back-to-back with headers
go run ./examples/repo-status/ --name my-app
go run ./examples/install-pipeline/
go run ./examples/migrate/                 # dry-run plan
go run ./examples/migrate/ --apply
go run ./examples/doctor/ --json | jq .conclusion
go run ./examples/data-command/ 2>/dev/null | jq .
go run ./examples/live-progress/              # in-place ANSI live region (real TTY)
go run ./examples/live-progress/ --frames     # numbered frames you can scroll
go run ./examples/debug-history/              # history-mode debug interleave
go run ./examples/debug-pane/                 # pane removed on success
go run ./examples/debug-pane/ --fail          # failure preserves diagnostics tail

# mise run examples: uses live ANSI when stderr is a TTY; --frames otherwise.
# EVO_EXAMPLES_FRAMES=1 mise run examples   # force scrubable frames in the batch
Machine output
snap := out.Snapshot()
plain, _ := evo.RenderPlain(snap, evo.PlainOptions{Width: 80})
jsonBytes, _ := evo.EncodeJSON(snap)
jsonl, _ := evo.EncodeJSONL(out.Events())

Schemas: schema/output.v1.json, schema/event.v1.json.

Production ANSI driver
import "github.com/zachbornheimer/evident-output/terminal"

drv := terminal.NewANSI(os.Stderr, terminal.WithInteractive(true), terminal.WithSize(80, 24))
out := evo.New(evo.Terminal(drv))
Interactive (testkit / virtual terminal)
screen := testkit.NewScreen(testkit.Interactive(), testkit.Width(80), testkit.NoColor())
clock := testkit.NewClock()
out := evo.New(
    evo.Terminal(screen),
    evo.Clock(clock),
    evo.VisibilityDelay(150*time.Millisecond),
    evo.MaxFrameRate(20),
)
// Phase/Progress draw a live region; instant Done before the threshold does not flash.
// DebugHistory (default): out.Debug → durable above live (timestamp + [DEBUG]).
// DebugPane(...): rolling slog viewport in the live region; optional failure tail.

Contributing

See CONTRIBUTING.md (DCO sign-off). Red test → green → refactor. Small conventional commits.

Documentation

Overview

Package evo is Evident Output: a presentation library for CLI state, progress, evidence, changes, plans, messages, actions, and conclusions.

Application code owns execution. Evo owns presentation.

func main() {
    out := evo.New(evo.Config{Title: "repo"})
    os.Exit(evo.Main(out, run))
}

func run(out *evo.Output) error {
    out.Println("Reading configuration")
    out.Item("working tree").OK()
    t := out.Task("fetch")
    output := t.Capture()
    // run.Run(ctx, "git", args, output); t.Fail(..., output.DetailTail()) on error
    return nil
}

Adoption ladder: Print → Verbose → Item/Task → Capture → slog diagnostics.

Ordinary surface: New(Config), Print*, Item/Task (+ ID), Task.Capture / Item.Capture, Changes/Plan, slog via SlogHandler (level from Config.Debug.Level). Advanced: NewWithOptions, Terminal, session Capture, Progress64, Advance.

Index

Constants

View Source
const (
	ExitOK        = 0
	ExitBlocked   = 1
	ExitFailed    = 2
	ExitCancelled = 130
)

Default exit codes from architecture §26.

View Source
const Debug = LevelDebug

Debug is the debug log level (Appendix H). Alias of LevelDebug.

View Source
const EventSchemaVersion = "0.2"

EventSchemaVersion is the durable event schema version. Tracks the 0.2 contract series (pre-1.0 wire format may still evolve).

View Source
const JSONSchemaVersion = "0.2"

JSONSchemaVersion is the final JSON document schema version. Tracks the 0.2 contract series (pre-1.0 wire format may still evolve).

View Source
const PublishedRelease = "v0.2.12"

PublishedRelease is the single source of truth for the current published module and MCP pin used in install guidance.

Maintenance class this protects (v0.2.10 hygiene, generalized):

  • skills / integrations / README disagree on which tag to install
  • MCP config generator falls back to a stale hardcoded tag
  • portable docs recommend @latest or a personal-machine clone path
  • signed tags ship with stale README pins (next patch, never rewrite history)

When cutting a release:

  1. Set PublishedRelease to the new tag (e.g. "v0.2.11").
  2. Run: go run ./scripts/sync-release-pins
  3. Run: go test . -run VersionDrift
  4. Tag that commit; do not move prior tags.

version_drift_test.go enforces the portable surface stays synchronized.

Variables

View Source
var (
	ErrClosed             = errors.New("evo: output is closed")
	ErrAlreadyResolved    = errors.New("evo: entity is already resolved")
	ErrNoProblems         = errors.New("evo: structured resolution requires problems")
	ErrUnresolvedItem     = errors.New("evo: item has no final state")
	ErrUnresolvedTask     = errors.New("evo: task has no final state")
	ErrInvalidProgress    = errors.New("evo: invalid progress")
	ErrProgressRegression = errors.New("evo: progress moved backward")
	ErrDuplicateKey       = errors.New("evo: duplicate entity key")
	ErrInvalidConfig      = errors.New("evo: invalid configuration")
	ErrRenderer           = errors.New("evo: renderer failure")
	ErrFinishing          = errors.New("evo: output is finishing")
	ErrLimitExceeded      = errors.New("evo: resource limit exceeded")
)

Sentinel misuse and lifecycle errors recorded by the output aggregate.

Functions

func Delay added in v0.2.7

func Delay(d time.Duration) *time.Duration

Delay returns a non-nil *time.Duration for Config fields where zero is meaningful.

cfg.VisibilityDelay = evo.Delay(0)                      // immediate
cfg.VisibilityDelay = evo.Delay(150 * time.Millisecond) // explicit default

func EncodeJSON

func EncodeJSON(s Snapshot, _ ...JSONOptions) ([]byte, error)

EncodeJSON encodes a snapshot as final JSON (§25.1 / §25.4).

func EncodeJSONL

func EncodeJSONL(events []Event, _ ...JSONLOptions) ([]byte, error)

EncodeJSONL encodes durable events as JSON Lines (§25.2 / §25.4).

func IsCharDevice

func IsCharDevice(w io.Writer) bool

IsCharDevice reports whether w is an *os.File backed by a character device (typical interactive TTY). Pipes, files, and non-file writers return false.

Prefer Config{Stdout, Stderr} for ordinary dual-stream construction. This helper remains for hosts that choose Plain/NoColor from a concrete writer.

func Main

func Main(out *Output, run func(*Output) error) int

Main runs a CLI presentation lifecycle and returns the process exit code.

Typical entrypoint:

func main() {
    out := evo.New(evo.Config{Title: "tool"})
    os.Exit(evo.Main(out, run))
}

Lifecycle: run → (reconcile run error into model) → Finish → Close.

Exit codes:

  • nil out → ExitFailed (2)
  • Finish or Close error → ExitFailed (2) when conclusion was OK/blocked
  • otherwise Conclusion.ExitCode after reconciling run errors into Fail

Config.FailedExitCode (when non-zero) overrides ExitFailed for a failed conclusion so CLIs that contract on exit 1 can set FailedExitCode: 1.

A non-nil application error is recorded as an output-level Fail before Finish so the human conclusion cannot show [ready] while the process fails.

func RenderPlain

func RenderPlain(s Snapshot, opts PlainOptions) ([]byte, error)

RenderPlain projects a snapshot to plain text without terminal ownership.

func WriteJSON added in v0.2.0

func WriteJSON(w io.Writer, snapshot Snapshot) error

WriteJSON encodes the snapshot as indented JSON with a trailing newline.

func WriteJSONL added in v0.2.0

func WriteJSONL(w io.Writer, events []Event) error

WriteJSONL encodes events as JSON Lines with a trailing newline per event.

Types

type Action

type Action struct {
	Label                string
	Command              *CommandSpec
	URL                  string
	File                 string
	Explanation          string
	RequiresConfirmation bool
	Destructive          bool
}

Action is a recommended next step for the user.

func Command

func Command(executable string, args ...string) Action

Command builds an action with an executable and arguments. Display-bound strings are sanitized at construction.

type CapabilityProfile

type CapabilityProfile struct {
	Interactive bool
	Color       ColorLevel
	Unicode     bool
	Width       int
	Height      int
	NoColor     bool
}

CapabilityProfile holds terminal capability facts (§22).

func DetectCapabilities

func DetectCapabilities(opts ...Option) CapabilityProfile

DetectCapabilities builds a profile from options and environment-like hints. It does not read the real environment in the core package without injection; callers pass NoColor/Width/NonInteractive options instead.

type Capture added in v0.1.1

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

Capture is a process-output sink owned by a Task (preferred) or Output.

upgrade := out.Task("brew packages")
output := upgrade.Capture() // silent retention by default
if err := run.Run(ctx, "brew", args, output); err != nil {
    upgrade.Fail("brew upgrade failed", evo.Cause(err), output.DetailTail())
    return nil
}
upgrade.Done()

Combined streams by default (P1): Write (merged), Stdout(), and Stderr() all feed the same bounded ring used by Text/Tail/DetailTail. Linters and most subprocess tools write diagnostics on stderr — route both streams into the Capture (or write the combined pipe into Capture itself) so failure evidence cannot escape the owning Task.

Semantics:

  • Always retains a bounded ring of sanitized lines (evidence exists even when debug presentation is disabled).
  • Default is silent: no Diagnostics/Debug mirror on success.
  • Opt in with MirrorToDiagnostics / MirrorToDebug.
  • Stdout/Stderr have independent pending buffers (no partial-line merge).
  • DetailTail is user-visible failure evidence; Cause is structured diagnostic.
  • DetailTail prefers stderr when separate streams were used, else combined.

func (*Capture) Close added in v0.1.1

func (c *Capture) Close() error

Close flushes trailing partial lines.

On the root Capture (task.Capture()), every stream pending buffer is flushed so Stdout/Stderr partial lines are retained. On a side writer (Stdout/Stderr), only that stream is flushed.

func (*Capture) DetailTail added in v0.1.2

func (c *Capture) DetailTail() ProblemOption

DetailTail returns a ProblemOption attaching a user-visible presentation of the capture tail. Prefers stderr when separate streams were used.

func (*Capture) Empty added in v0.1.1

func (c *Capture) Empty() bool

Empty reports whether no completed lines and no pending fragments exist.

func (*Capture) Lines added in v0.1.2

func (c *Capture) Lines() []string

Lines returns retained combined line texts (oldest first).

func (*Capture) Stderr added in v0.1.2

func (c *Capture) Stderr() io.Writer

Stderr returns a writer that records lines as stderr with its own pending buffer.

func (*Capture) Stdout added in v0.1.2

func (c *Capture) Stdout() io.Writer

Stdout returns a writer that records lines as stdout with its own pending buffer.

func (*Capture) Tail added in v0.1.1

func (c *Capture) Tail(n ...int) string

Tail returns the last n retained combined lines.

func (*Capture) TaskName added in v0.1.2

func (c *Capture) TaskName() string

TaskName returns the owning task name when created via Task.Capture.

func (*Capture) Text added in v0.1.2

func (c *Capture) Text() string

Text returns all retained combined lines joined by newlines.

func (*Capture) Write added in v0.1.1

func (c *Capture) Write(p []byte) (int, error)

Write implements io.Writer. Safe for concurrent use with Tail/DetailTail.

type CaptureOption added in v0.1.1

type CaptureOption interface {
	// contains filtered or unexported methods
}

CaptureOption configures Capture.

func KeepLastLines added in v0.1.2

func KeepLastLines(n int) CaptureOption

KeepLastLines sets how many trailing lines are retained (default 200).

func MaxCaptureBytes added in v0.1.2

func MaxCaptureBytes(n int) CaptureOption

MaxCaptureBytes sets an approximate byte budget for retained lines (default 256KiB).

func MirrorToDebug added in v0.2.2

func MirrorToDebug() CaptureOption

MirrorToDebug journals each completed line via Debug when DebugLevel allows. Default is off.

func MirrorToDiagnostics added in v0.2.2

func MirrorToDiagnostics() CaptureOption

MirrorToDiagnostics copies each completed line to the Diagnostics writer. Default is off — Capture retains evidence without displaying on success.

type CaptureStream added in v0.2.2

type CaptureStream uint8

CaptureStream identifies which process stream a line came from.

const (
	// CaptureStreamCombined is Write() on the Capture itself (merged by the runner).
	CaptureStreamCombined CaptureStream = iota
	// CaptureStreamStdout is output.Stdout().
	CaptureStreamStdout
	// CaptureStreamStderr is output.Stderr().
	CaptureStreamStderr
)

type Changes

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

Changes is a handle for durable effects that already occurred.

func (*Changes) Added

func (c *Changes) Added(quantity int64, object string) *Changes

Added records an added quantity.

func (*Changes) Created

func (c *Changes) Created(object string) *Changes

Created records a created object.

func (*Changes) Moved

func (c *Changes) Moved(source, destination string) *Changes

Moved records a move.

func (*Changes) Record

func (c *Changes) Record(verb string, quantity int64, object string) *Changes

Record records a verb/quantity/object effect.

func (*Changes) Removed

func (c *Changes) Removed(quantity int64, object string) *Changes

Removed records a removed quantity.

func (*Changes) Reused

func (c *Changes) Reused(quantity int64, object string) *Changes

Reused records a reused quantity.

func (*Changes) Updated

func (c *Changes) Updated(quantity int64, object string) *Changes

Updated records an updated quantity.

func (*Changes) Wrote

func (c *Changes) Wrote(object string) *Changes

Wrote records a written object.

type ChangesSnapshot

type ChangesSnapshot struct {
	ID      string
	Subject string
	Records []EffectRecord
}

ChangesSnapshot is an immutable changes section.

type ColorLevel

type ColorLevel int

ColorLevel describes terminal color support.

const (
	ColorNone ColorLevel = iota
	ColorBasic
	Color256
	ColorTrue
)

type ColorMode added in v0.2.0

type ColorMode int

ColorMode selects color policy. The zero value is automatic.

const (
	// ColorAuto uses TTY detection and honors NO_COLOR.
	ColorAuto ColorMode = iota
	// ColorAlways forces semantic color even off a TTY.
	ColorAlways
	// ColorNever disables color.
	ColorNever
)

func ParseColorMode added in v0.2.0

func ParseColorMode(s string) (ColorMode, error)

ParseColorMode maps always|never|auto (and common synonyms) to ColorMode.

type CommandSpec

type CommandSpec struct {
	Executable string
	Args       []string
	WorkingDir string
}

CommandSpec is an executable plus argv (never a shell string).

type Conclusion

type Conclusion struct {
	State       ConclusionState
	Subject     string
	Changed     bool
	Partial     bool
	Cancelled   bool
	Explanation string
	Items       []ItemSnapshot
	Tasks       []TaskSnapshot
	Collections []TasksSnapshot
	Changes     []ChangesSnapshot
	Plans       []PlanSnapshot
	Actions     []Action
	ExitCode    int
}

Conclusion is the multidimensional meaning of a finished command.

func (Conclusion) AnyBlocked

func (c Conclusion) AnyBlocked() bool

AnyBlocked reports whether the finished conclusion is blocked, or any item snapshot is.

type ConclusionJSON

type ConclusionJSON struct {
	State       ConclusionState `json:"state"`
	Changed     bool            `json:"changed"`
	Partial     bool            `json:"partial"`
	Cancelled   bool            `json:"cancelled"`
	ExitCode    int             `json:"exit_code"`
	Explanation string          `json:"explanation,omitempty"`
}

ConclusionJSON is JSON-friendly conclusion.

type ConclusionState

type ConclusionState string

ConclusionState is the human headline for a finished output.

const (
	StateReady     ConclusionState = "ready"
	StateChanged   ConclusionState = "changed"
	StateUnchanged ConclusionState = "unchanged"
	StateWarning   ConclusionState = "warning"
	StateBlocked   ConclusionState = "blocked"
	StateFailed    ConclusionState = "failed"
	StateCancelled ConclusionState = "cancelled"
	StatePlanned   ConclusionState = "planned"
	StatePartial   ConclusionState = "partial"
)

type Config

type Config struct {
	// Title is the subject shown in the conclusion (formerly For's argument).
	Title string

	// Stdout is the ordinary human stream (default os.Stdout).
	// In FormatData mode, Stdout is reserved for domain payload via ResultWriter;
	// human presentation moves to Stderr.
	Stdout io.Writer
	// Stderr owns diagnostics by default (default os.Stderr).
	Stderr io.Writer
	// Result is an optional domain-payload writer. When nil and Format is
	// FormatData, ResultWriter returns Stdout. Presentation never writes here.
	Result io.Writer

	// Verbosity gates Verbose() print messages (default VerbosityNormal).
	Verbosity Verbosity
	// Color policy (default ColorAuto).
	Color ColorMode
	// Format projection mode (default FormatHuman).
	Format Format

	// Debug configures the debug journal.
	Debug DebugConfig

	// Advanced (optional) — zero values inherit safe defaults.
	Clock    TimeSource
	Redactor Redactor
	Terminal TerminalDriver
	Strict   bool
	Width    int
	// VisibilityDelay is the wait before the first live paint.
	// nil means default (150ms). Non-nil is exact, including 0 for immediate.
	// Use evo.Delay(d) to set a value from a duration literal.
	VisibilityDelay *time.Duration
	MaxFrameRate    int
	MaxEntities     int
	MaxEvents       int
	// ForcePlain disables live interactive frames even on a TTY.
	ForcePlain bool
	// NonInteractive disables live frames.
	NonInteractive bool

	// FailedExitCode is the process exit code when the conclusion is failed.
	// Zero means use ExitFailed (2). Set to 1 for conventional CLI tools that
	// treat any non-zero failure as exit 1 (e.g. quality gates / git hooks).
	FailedExitCode int
}

Config is the ordinary application-facing construction surface.

Zero values mean automatic/default behavior. Use DefaultConfig() when you need a mutable baseline for advanced fields.

out := evo.New()
out := evo.New(evo.Config{Title: "bpp-csharp"})
cfg := evo.DefaultConfig(); cfg.Title = "x"; out := evo.New(cfg)

func DefaultConfig added in v0.2.0

func DefaultConfig() Config

DefaultConfig returns a fresh ordinary CLI configuration. Mutating the result does not affect later DefaultConfig() calls.

type DebugConfig added in v0.2.0

type DebugConfig struct {
	// Level is the minimum debug journal level. Zero (LevelUnset) resolves to
	// LevelInfo. Use LevelTrace or LevelDebug to surface Debug/Capture mirrors.
	Level LogLevel
	// View selects history vs pane presentation (default History).
	View DebugPresentation
	// PaneHeight is used when View is DebugPresentationPane (default 5).
	PaneHeight int
	// NewestFirst orders the pane (default true when zero-config pane).
	NewestFirst *bool
	// PreserveAlways forces a diagnostic tail on every Finish in pane mode.
	PreserveAlways bool
}

DebugConfig configures the debug journal presentation.

type DebugPaneOption

type DebugPaneOption interface {
	// contains filtered or unexported methods
}

DebugPaneOption configures DebugPane presentation.

func NewestFirst

func NewestFirst() DebugPaneOption

NewestFirst orders the pane with the most recent record first (default).

func OldestFirst

func OldestFirst() DebugPaneOption

OldestFirst orders the pane chronologically (oldest visible first).

func PaneHeight

func PaneHeight(lines int) DebugPaneOption

PaneHeight sets how many debug records are visible in the pane (not including heading).

func PreserveDebugTail

func PreserveDebugTail() DebugPaneOption

PreserveDebugTail always emits a bounded diagnostic tail under the final report. Without this, pane mode still preserves a tail on failed/blocked/cancelled conclusions.

type DebugPresentation

type DebugPresentation int

DebugPresentation selects how structured debug records project to a TTY (§4.6 / §21.3).

const (
	// DebugPresentationHistory appends durable scrollback above the live region (default).
	DebugPresentationHistory DebugPresentation = iota
	// DebugPresentationPane keeps a bounded rolling viewport inside the live region.
	DebugPresentationPane
)

type EffectRecord

type EffectRecord struct {
	Verb     string
	Quantity int64
	HasQty   bool
	Object   string
}

EffectRecord is one semantic change or plan row.

type EntityOption added in v0.2.3

type EntityOption interface {
	// contains filtered or unexported methods
}

EntityOption configures Item or Task declaration (stable keys). The common path remains Item("label") / Task("label"); options are platform-scale.

func ID added in v0.2.3

func ID(id string) EntityOption

ID sets a stable machine key independent of the human label. Labels may be localized or reworded; IDs should not.

out.Task("download base image", evo.ID("build.base-image.download"))

type EntityState

type EntityState string

EntityState is the lifecycle state of an item or task.

const (
	Pending    EntityState = "pending"
	Running    EntityState = "running"
	OK         EntityState = "ok"
	Done       EntityState = "done"
	Warning    EntityState = "warning"
	Blocked    EntityState = "blocked"
	Failed     EntityState = "failed"
	Unknown    EntityState = "unknown"
	Skipped    EntityState = "skipped"
	Cancelled  EntityState = "cancelled"
	Empty      EntityState = "empty"
	Incomplete EntityState = "incomplete"
)

type Event

type Event struct {
	SchemaVersion string
	Sequence      uint64
	Timestamp     time.Time
	Type          string
	OutputID      string
	EntityID      string
	Name          string
	State         string
	Completed     *int64
	Total         *int64
	Activation    string
	Payload       map[string]any
}

Event is an immutable journal record.

type EventJSON

type EventJSON struct {
	SchemaVersion string    `json:"schema_version"`
	Sequence      uint64    `json:"sequence"`
	Type          string    `json:"type"`
	OutputID      string    `json:"output_id,omitempty"`
	EntityID      string    `json:"entity_id,omitempty"`
	Name          string    `json:"name,omitempty"`
	State         string    `json:"state,omitempty"`
	Completed     *int64    `json:"completed,omitempty"`
	Total         *int64    `json:"total,omitempty"`
	Activation    string    `json:"activation,omitempty"`
	Timestamp     time.Time `json:"timestamp,omitempty"`
}

EventJSON is a JSON Lines event record (§25.2).

type Evidence

type Evidence struct {
	Label string
	Value string
}

Evidence is an additional problem attachment.

type Field

type Field struct {
	Key       string
	Value     any
	Sensitive bool
}

Field is a structured diagnostic or log field.

func Duration

func Duration(key string, value interface{ String() string }) Field

Duration builds a duration diagnostic field.

func Int

func Int(key string, value int) Field

Int builds an integer diagnostic field.

func String

func String(key, value string) Field

String builds a string diagnostic field.

type FixedClock

type FixedClock struct {
	T time.Time
}

FixedClock always returns the same instant.

func (FixedClock) Now

func (c FixedClock) Now() time.Time

Now returns the fixed instant.

type Format added in v0.2.0

type Format int

Format selects the overall projection mode. Zero is ordinary human output.

const (
	// FormatHuman is ordinary human (and optional interactive) presentation.
	FormatHuman Format = iota
	// FormatData reserves stdout for the application's domain payload; Evo
	// human presentation goes to stderr (data-command mode).
	FormatData
	// FormatExternal disables inline rendering (snapshots only).
	FormatExternal
)

type Item

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

Item is a handle for one named final-report condition.

func (*Item) Because

func (i *Item) Because(text string) *Item

Because annotates an explanation after resolution.

func (*Item) Block

func (i *Item) Block(summary string, options ...ProblemOption) *Item

Block marks the item blocked with a simple problem.

func (*Item) BlockedBy

func (i *Item) BlockedBy(problems ...Problem) *Item

BlockedBy marks the item blocked with structured problems.

func (*Item) Capture added in v0.2.7

func (i *Item) Capture(opts ...CaptureOption) *Capture

Capture returns a process-output sink bound to this Item (tool-backed gate). Presentation only — does not run the tool. Use when a condition is evaluated by an external command (git status, docker info, brew doctor, …).

docker := out.Item("docker daemon").Start()
cap := docker.Capture()
if err := runDockerInfo(cap); err != nil {
    docker.Fail("could not inspect the daemon", evo.Cause(err), cap.DetailTail())
} else {
    docker.OK()
}

func (*Item) Fail

func (i *Item) Fail(summary string, options ...ProblemOption) *Item

Fail marks the item failed with a simple problem.

func (*Item) FailedBy

func (i *Item) FailedBy(problems ...Problem) *Item

FailedBy marks the item failed with structured problems.

func (*Item) Next

func (i *Item) Next(actions ...Action) *Item

Next attaches actions.

func (*Item) NextCommand

func (i *Item) NextCommand(executable string, args ...string) *Item

NextCommand attaches a command action.

func (*Item) OK

func (i *Item) OK() *Item

OK marks the item satisfactory.

func (*Item) Skip

func (i *Item) Skip(reason string) *Item

Skip marks the item skipped.

func (*Item) Snapshot

func (i *Item) Snapshot() ItemSnapshot

Snapshot returns the item's current snapshot.

func (*Item) Start

func (i *Item) Start() *Item

Start marks the item running so it becomes visible in the live region (indeterminate) while the application evaluates it. Optional: OK/Block/… may resolve pending items directly without Start (no transient frame when resolution is instant — §7.4 rule 5).

func (*Item) Unknown

func (i *Item) Unknown(summary string, options ...ProblemOption) *Item

Unknown marks the item undetermined.

func (*Item) Warn

func (i *Item) Warn(summary string, options ...ProblemOption) *Item

Warn marks the item with a simple warning problem.

func (*Item) WarnedBy

func (i *Item) WarnedBy(problems ...Problem) *Item

WarnedBy marks the item warning with structured problems.

type ItemSnapshot

type ItemSnapshot struct {
	ID          string
	Key         string // optional stable machine key (evo.ID); empty when unset
	Name        string
	State       EntityState
	Problems    []Problem
	Because     string
	Actions     []Action
	Declaration int
}

ItemSnapshot is an immutable item view.

type JSONAction

type JSONAction struct {
	Label   string       `json:"label,omitempty"`
	Command *JSONCommand `json:"command,omitempty"`
	URL     string       `json:"url,omitempty"`
}

JSONAction is a wire-format action.

type JSONChanges

type JSONChanges struct {
	ID      string             `json:"id"`
	Subject string             `json:"subject"`
	Records []JSONEffectRecord `json:"records"`
}

JSONChanges is wire-format changes.

type JSONCollection

type JSONCollection struct {
	ID       string      `json:"id"`
	Name     string      `json:"name"`
	State    EntityState `json:"state"`
	Summary  string      `json:"summary,omitempty"`
	Children []string    `json:"children"`
}

JSONCollection is a wire-format task collection with child IDs (§25.1).

type JSONCommand

type JSONCommand struct {
	Executable string   `json:"executable"`
	Args       []string `json:"args,omitempty"`
}

JSONCommand is argv for display.

type JSONDocument

type JSONDocument struct {
	SchemaVersion   string           `json:"schema_version"`
	Output          JSONOutputMeta   `json:"output"`
	Conclusion      ConclusionJSON   `json:"conclusion"`
	Items           []JSONItem       `json:"items"`
	TaskCollections []JSONCollection `json:"task_collections"`
	Tasks           []JSONTask       `json:"tasks"`
	Changes         []JSONChanges    `json:"changes"`
	Plans           []JSONPlan       `json:"plans"`
	Messages        []JSONMessage    `json:"messages,omitempty"`
	Actions         []JSONAction     `json:"actions"`
}

JSONDocument is the final machine projection (§25.1).

type JSONEffectRecord

type JSONEffectRecord struct {
	Verb     string `json:"verb"`
	Quantity *int64 `json:"quantity,omitempty"`
	Object   string `json:"object"`
}

JSONEffectRecord is a change/plan row.

type JSONItem

type JSONItem struct {
	ID       string        `json:"id"`
	Key      string        `json:"key,omitempty"`
	Name     string        `json:"name"`
	State    EntityState   `json:"state"`
	Problems []JSONProblem `json:"problems"`
	Because  string        `json:"because,omitempty"`
}

JSONItem is a wire-format item.

type JSONLOptions

type JSONLOptions struct{}

JSONLOptions reserves future encode knobs.

type JSONMessage added in v0.2.0

type JSONMessage struct {
	ID         string `json:"id"`
	Visibility string `json:"visibility"`
	Text       string `json:"text"`
}

JSONMessage is a wire-format user-facing message.

type JSONOptions

type JSONOptions struct{}

JSONOptions reserves future encode knobs.

type JSONOutputMeta

type JSONOutputMeta struct {
	ID      string `json:"id"`
	Subject string `json:"subject,omitempty"`
}

JSONOutputMeta identifies the output instance.

type JSONPlan

type JSONPlan struct {
	ID      string             `json:"id"`
	Subject string             `json:"subject"`
	Records []JSONEffectRecord `json:"records"`
}

JSONPlan is wire-format plan.

type JSONProblem

type JSONProblem struct {
	Subject string `json:"subject,omitempty"`
	Summary string `json:"summary,omitempty"`
	Detail  string `json:"detail,omitempty"`
	Count   int64  `json:"count,omitempty"`
	Unit    string `json:"unit,omitempty"`
	Code    string `json:"code,omitempty"`
}

JSONProblem is a wire-format problem (no raw Cause by default).

type JSONProgress

type JSONProgress struct {
	Kind      ProgressKind `json:"kind"`
	Completed int64        `json:"completed"`
	Total     int64        `json:"total"`
}

JSONProgress is wire-format progress.

type JSONTask

type JSONTask struct {
	ID       string        `json:"id"`
	Key      string        `json:"key,omitempty"`
	Name     string        `json:"name"`
	State    EntityState   `json:"state"`
	Phase    string        `json:"phase,omitempty"`
	Summary  string        `json:"summary,omitempty"`
	Progress *JSONProgress `json:"progress,omitempty"`
	Problems []JSONProblem `json:"problems,omitempty"`
}

JSONTask is a wire-format task.

type LiveSurface

type LiveSurface interface {
	TerminalDriver
	Columns() int
	Rows() int
	IsInteractive() bool
	WriteLive(text string)
	ClearLive()
	WriteDurable(line string)
	WriteFinal(text string)
}

LiveSurface is an interactive terminal sink for live-region rendering. testkit.Screen implements this; production drivers can as well.

type Location

type Location struct {
	Path   string
	Line   int
	Column int
}

Location is a path-based source position.

type LogLevel

type LogLevel int

LogLevel is a diagnostic severity.

The zero value is LevelUnset (Config resolves it to LevelInfo). Named levels start at LevelTrace so ordinary Config{Debug: DebugConfig{Level: LevelTrace}} is expressible without falling through the default path.

const (
	// LevelUnset is the zero value. Config resolve maps it to LevelInfo.
	LevelUnset LogLevel = iota
	// LevelTrace is the most verbose journal level selectable via Config.
	LevelTrace
	// LevelDebug enables Debug journal lines (and Capture MirrorToDebug).
	LevelDebug
	// LevelInfo is the ordinary default (Debug journal suppressed).
	LevelInfo
	// LevelWarn is reserved for future warn-threshold filtering.
	LevelWarn
	// LevelError is reserved for future error-threshold filtering.
	LevelError
)

type LogRecord added in v0.2.4

type LogRecord struct {
	Time    time.Time
	Level   slog.Level
	Message string
	Attrs   []slog.Attr
	PC      uintptr
}

LogRecord is a complete internal log entry preserved from slog (or peer bridges). History and pane projectors read Time/Level/Message/Attrs without lossy remapping beyond the usual Field redaction path.

type MessageSnapshot added in v0.2.0

type MessageSnapshot struct {
	ID         string
	Text       string
	Visibility Visibility
}

MessageSnapshot is one logical user-facing message in the canonical model.

type NoopRedactor

type NoopRedactor struct{}

NoopRedactor leaves strings unchanged.

func (NoopRedactor) RedactString

func (NoopRedactor) RedactString(s string) string

RedactString implements Redactor.

type Option

type Option interface {
	// contains filtered or unexported methods
}

Option configures an Output.

func AlsoWrite

func AlsoWrite(w io.Writer) Option

AlsoWrite adds an additional human projection writer. On Finish, each writer receives the plain projection; failures on one do not skip the others (CON-009).

func Clock

func Clock(ts TimeSource) Option

Clock injects a time source facade.

func DataProjection

func DataProjection() Option

DataProjection selects data-command mode (UI/progress on diagnostic stream).

func DebugHistory

func DebugHistory() Option

DebugHistory selects durable append-above-and-redraw presentation (v0.4 default).

func DebugLevel

func DebugLevel(level LogLevel) Option

DebugLevel sets the minimum debug emission level. Pass LevelTrace or LevelDebug to surface Debug journal lines.

func DebugPane

func DebugPane(opts ...DebugPaneOption) Option

DebugPane selects a rolling TTY debug viewport at the bottom of the live region.

func Diagnostics

func Diagnostics(w io.Writer) Option

Diagnostics sets the diagnostic writer for Debug history and Capture mirrors. When set and distinct from the primary writer (To), Debug lines are not also written to the human primary stream — use dual-stream for LaunchAgent / data-command layouts (human on stdout, diagnostics on stderr).

func ExternalProjection

func ExternalProjection() Option

ExternalProjection selects snapshot-only host rendering.

func MaxEntities

func MaxEntities(n int) Option

MaxEntities caps total items and tasks for one Output (0 uses default).

func MaxEvents

func MaxEvents(n int) Option

MaxEvents caps durable journal events; when exceeded, oldest non-critical events are dropped so critical terminal events are retained (CON-008).

func MaxFrameRate

func MaxFrameRate(framesPerSecond int) Option

MaxFrameRate caps interactive redraws per second.

func NoColor

func NoColor() Option

NoColor disables color.

func NonInteractive

func NonInteractive() Option

NonInteractive disables live interactive frames.

func Plain

func Plain() Option

Plain forces final-report projection (no live spinner region). Semantic color is still emitted unless NoColor is set.

func Redact

func Redact(r Redactor) Option

Redact injects a redactor (Debug fields, Capture lines, problem detail paths).

func ResultStream added in v0.2.3

func ResultStream(w io.Writer) Option

ResultStream sets the domain-payload writer (see Output.ResultWriter). Presentation never writes here. FormatData defaults this to Config.Stdout.

func Strict

func Strict() Option

Strict enables panic-on-misuse for tests.

func Terminal

func Terminal(driver TerminalDriver) Option

Terminal injects a terminal driver (interactive projection; v0.2).

func Title added in v0.2.7

func Title(subject string) Option

Title sets the conclusion subject for NewWithOptions.

func To

func To(w io.Writer) Option

To sets the primary human writer.

func VisibilityDelay

func VisibilityDelay(delay time.Duration) Option

VisibilityDelay sets how long live activity must persist before the first interactive paint (default 150ms). Zero paints immediately. Prevents Phase→fast Done spinner flash (H.2). Domain TimeSource is used for the threshold.

func Width

func Width(columns int) Option

Width sets the terminal width in columns.

type Output

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

Output is the aggregate root for one command's presentation lifecycle.

func New

func New(config ...Config) *Output

New creates an Output from zero or one Config.

out := evo.New()
out := evo.New(evo.Config{Title: "repo"})

More than one Config panics (programmer error). For advanced Option plumbing use NewWithOptions.

func NewWithOptions added in v0.2.0

func NewWithOptions(options ...Option) *Output

NewWithOptions is the advanced Option-based constructor for tests and specialized embedding (custom Terminal, Clock, etc.). Prefer New(Config) in application code.

Set the conclusion title with Title(...):

out := evo.NewWithOptions(evo.Title("install"), evo.To(&buf), evo.Plain())

func (*Output) AnyBlocked

func (o *Output) AnyBlocked() bool

AnyBlocked reports whether any Item is currently in the Blocked state.

func (*Output) AnyFailed

func (o *Output) AnyFailed() bool

AnyFailed reports whether any Item or Task is currently Failed.

func (*Output) At added in v0.2.0

func (o *Output) At(visibility Visibility) *Printer

At returns a printer for the given visibility.

func (*Output) Cancel

func (o *Output) Cancel(reason string)

Cancel records output-level cancellation via a synthetic cancelled task.

func (*Output) Capture added in v0.1.1

func (o *Output) Capture(opts ...CaptureOption) *Capture

Capture returns a session-level process sink with no owning Item/Task. Prefer Task.Capture or Item.Capture so failure evidence attaches to an entity. Session capture is advanced; ordinary call sites should not use it.

func (*Output) Changes

func (o *Output) Changes(subject string) *Changes

Changes starts a durable-effects section.

func (*Output) Changesf added in v0.2.0

func (o *Output) Changesf(format string, args ...any) *Changes

Changesf formats a subject and declares a Changes section.

func (*Output) Close

func (o *Output) Close() error

Close is idempotent cleanup; best-effort Finish when needed.

func (*Output) Conclusion

func (o *Output) Conclusion() Conclusion

Conclusion returns the computed conclusion after Finish.

func (*Output) Debug

func (o *Output) Debug(message string, fields ...Field)

Debug records a structured diagnostic (§4.6 / §21.3).

History mode (default): durable scrollback above the live region (or plain stream). Pane mode: record is journaled and shown in the rolling live pane; not durable scrollback unless a diagnostic tail is preserved at Finish.

When Diagnostics is configured and is a different writer than the primary stream, debug lines go to Diagnostics only (not the human Items/Tasks stream). Use Capture for child-process evidence instead of DebugWriter when you need Fail Detail.

func (*Output) DebugWriter

func (o *Output) DebugWriter() io.WriteCloser

DebugWriter returns a line-oriented writer that emits Debug lines on newline. Partial UTF-8 sequences are buffered; control bytes are sanitized.

Prefer Capture for external process stdout/stderr: DebugWriter is filtered by DebugLevel (default LevelInfo drops all lines) and is the wrong dialect for child-command evidence used in Fail Detail. Use DebugWriter only when you intentionally want DEBUG-level journal lines (and set DebugLevel(Debug)).

func (*Output) Err

func (o *Output) Err() error

Err returns the first recorded misuse error, if any.

func (*Output) Events

func (o *Output) Events() []Event

Events returns a copy of durable events (v0.1 journal).

func (*Output) Explain

func (o *Output) Explain(text string)

Explain sets an explicit conclusion explanation (applied at Finish).

func (*Output) Fail

func (o *Output) Fail(summary string, options ...ProblemOption)

Fail records an output-level failure.

func (*Output) FinalPlain

func (o *Output) FinalPlain() string

FinalPlain returns the last rendered plain text after Finish.

func (*Output) Finish

func (o *Output) Finish() error

Finish validates, computes conclusion, emits final projections. Projection I/O runs outside the domain lock (§17.1).

func (*Output) Item

func (o *Output) Item(name string, opts ...EntityOption) *Item

Item declares a named final-report condition. Optional evo.ID sets a stable machine key.

func (*Output) Itemf added in v0.2.0

func (o *Output) Itemf(format string, args ...any) *Item

Itemf formats a name and declares an Item. Prefer Item + plain labels for stable presentation; use Itemf only when the label must embed a value and evo.ID is set for machine identity when needed.

func (*Output) Next

func (o *Output) Next(actions ...Action)

Next attaches output-level actions.

func (*Output) NextCommand

func (o *Output) NextCommand(executable string, args ...string)

NextCommand attaches an output-level command action.

func (*Output) Plan

func (o *Output) Plan(subject string) *Plan

Plan starts a would-occur effects section.

func (*Output) Planf added in v0.2.0

func (o *Output) Planf(format string, args ...any) *Plan

Planf formats a subject and declares a Plan section.

func (*Output) Print added in v0.2.0

func (o *Output) Print(args ...any)

Print formats like fmt.Sprint and enqueues human-facing text (line-buffered). Errors are recorded on the Output and returned by Finish/Main — not ignored mid-stream.

func (*Output) Printf added in v0.2.0

func (o *Output) Printf(format string, args ...any)

Printf formats like fmt.Sprintf and enqueues human-facing text (line-buffered).

func (*Output) Println added in v0.2.0

func (o *Output) Println(args ...any)

Println formats like fmt.Sprintln and enqueues a complete human-facing line.

func (*Output) ResultWriter added in v0.2.3

func (o *Output) ResultWriter() io.Writer

ResultWriter returns the domain-payload stream. Presentation never writes here.

In FormatData mode this is Config.Result if set, otherwise Config.Stdout — so machine JSON stays pure while Items/Tasks render on stderr. When no result stream is configured, returns io.Discard.

out := evo.New(evo.Config{Title: "build", Format: evo.FormatData})
// after work succeeds:
_ = json.NewEncoder(out.ResultWriter()).Encode(payload)

func (*Output) Scope added in v0.2.3

func (o *Output) Scope(name string) *Scope

Scope returns a namespaced handle. It does not render a visible section.

func (*Output) SlogHandler

func (o *Output) SlogHandler() slog.Handler

SlogHandler returns a slog.Handler that journals every accepted record as structured diagnostics (history or pane), without mutating Output configuration.

Level policy is Config.Debug.Level (one conductor):

out := evo.New(evo.Config{
    Debug: evo.DebugConfig{Level: evo.LevelDebug},
})
logger := slog.New(out.SlogHandler())

Application human prose uses Print/Printf/Println or Item/Task outcomes — not slog. Infrastructure diagnostics use slog through this handler.

func (*Output) Snapshot

func (o *Output) Snapshot() Snapshot

Snapshot returns an immutable copy of current state.

func (*Output) Snapshots

func (o *Output) Snapshots() <-chan Snapshot

Snapshots returns a buffered channel of immutable snapshots. The channel is closed when the output is closed or finished. Callers should not block the library; buffer absorbs bursts.

func (*Output) Suspend

func (o *Output) Suspend(fn func() error) error

Suspend temporarily pauses interactive presentation for host-owned output. In v0.3 plain/non-interactive mode this is a no-op around fn. With a live surface it clears the live region, runs fn, then resumes.

func (*Output) Task

func (o *Output) Task(name string, opts ...EntityOption) *Task

Task declares a single operation. Optional evo.ID sets a stable machine key.

func (*Output) Taskf added in v0.2.0

func (o *Output) Taskf(format string, args ...any) *Task

Taskf formats a name and declares a root Task. Prefer Task(name, evo.ID(...)) when identity must outlive label wording.

func (*Output) Tasks

func (o *Output) Tasks(name string) *Tasks

Tasks declares a collection of independent child tasks.

func (*Output) Tasksf added in v0.2.0

func (o *Output) Tasksf(format string, args ...any) *Tasks

Tasksf formats a name and declares a Tasks collection.

func (*Output) Verbose added in v0.2.0

func (o *Output) Verbose() *Printer

Verbose is sugar for At(Verbose).

func (*Output) Writer added in v0.2.0

func (o *Output) Writer() io.Writer

Writer returns an io.Writer that feeds this printer's line buffer (human stream).

type PlainOptions

type PlainOptions struct {
	Width          int
	NoColor        bool
	NonInteractive bool
}

PlainOptions configures pure plain projection (§25.4).

type Plan

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

Plan is a handle for effects that would occur but have not.

func (*Plan) Add

func (p *Plan) Add(quantity int64, object string) *Plan

Add records a planned addition.

func (*Plan) Create

func (p *Plan) Create(object string) *Plan

Create records a planned create.

func (*Plan) Delete

func (p *Plan) Delete(quantity int64, object string) *Plan

Delete records a planned deletion.

func (*Plan) Move

func (p *Plan) Move(source, destination string) *Plan

Move records a planned move.

func (*Plan) Record

func (p *Plan) Record(verb string, quantity int64, object string) *Plan

Record records a planned verb/quantity/object.

func (*Plan) Remove

func (p *Plan) Remove(quantity int64, object string) *Plan

Remove records a planned removal.

func (*Plan) Retain

func (p *Plan) Retain(description string) *Plan

Retain records a planned retention note.

func (*Plan) Revoke

func (p *Plan) Revoke(quantity int64, object string) *Plan

Revoke records a planned revocation.

func (*Plan) Update

func (p *Plan) Update(quantity int64, object string) *Plan

Update records a planned update.

func (*Plan) Write

func (p *Plan) Write(object string) *Plan

Write records a planned write.

type PlanSnapshot

type PlanSnapshot struct {
	ID      string
	Subject string
	Records []EffectRecord
}

PlanSnapshot is an immutable plan section.

type Printer added in v0.2.0

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

Printer is a visibility-scoped view of Output for Print/Printf/Println.

func (*Printer) Print added in v0.2.0

func (p *Printer) Print(args ...any)

Print implements Printer.

func (*Printer) Printf added in v0.2.0

func (p *Printer) Printf(format string, args ...any)

Printf implements Printer.

func (*Printer) Println added in v0.2.0

func (p *Printer) Println(args ...any)

Println implements Printer.

func (*Printer) Writer added in v0.2.0

func (p *Printer) Writer() io.Writer

Writer returns an io.Writer that feeds this printer's line buffer.

type Problem

type Problem struct {
	Code      string
	Subject   string
	Summary   string
	Detail    string
	Severity  string
	Count     int64
	Unit      string
	Location  *Location
	Evidence  []Evidence
	Actions   []Action
	Fields    []Field
	Cause     error
	Sensitive bool
}

Problem is structured evidence explaining a negative item or task outcome.

type ProblemOption

type ProblemOption interface {
	// contains filtered or unexported methods
}

ProblemOption configures a problem constructed by Block/Warn/Fail helpers.

func At

func At(path string, line, column int) ProblemOption

At sets a source location.

func Cause

func Cause(err error) ProblemOption

Cause attaches a diagnostic error (not shown by default in human output).

func Code

func Code(value string) ProblemOption

Code sets a stable problem code.

func Count

func Count(value int64, unit ...string) ProblemOption

Count sets a quantity and optional unit.

func Detail

func Detail(text string) ProblemOption

Detail sets user-visible detail text (strings only).

func DetailTail added in v0.1.1

func DetailTail(c *Capture) ProblemOption

DetailTail free-function form (prefer method on Capture).

func Next

func Next(action Action) ProblemOption

Next attaches actions to a problem.

func NextCommand

func NextCommand(executable string, args ...string) ProblemOption

NextCommand attaches a recommended command action.

func On

func On(subject string) ProblemOption

On sets the problem subject.

type Progress

type Progress struct {
	Kind      ProgressKind
	Completed int64
	Total     int64
}

Progress is absolute measurement for a task.

type ProgressKind

type ProgressKind string

ProgressKind classifies task measurement.

const (
	Indeterminate ProgressKind = "indeterminate"
	Determinate   ProgressKind = "determinate"
	BytesKind     ProgressKind = "bytes"
)

type ProjectionPolicy

type ProjectionPolicy int

ProjectionPolicy selects how output is emitted.

const (
	// ProjectionAuto chooses based on options/TTY hints.
	ProjectionAuto ProjectionPolicy = iota
	// ProjectionHuman is interactive or plain human output.
	ProjectionHuman
	// ProjectionData keeps machine data on the primary writer; UI on diagnostic.
	ProjectionData
	// ProjectionExternal disables inline rendering; snapshots only.
	ProjectionExternal
)

type Redactor

type Redactor interface {
	// RedactString returns a display-safe form of s.
	RedactString(s string) string
}

Redactor redacts sensitive values before journal, Capture retention, and human rendering.

type Scope added in v0.2.3

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

Scope is a namespaced declaration handle for plugins and subsystems.

Contract (honest limits):

  • Qualifies evo.ID keys as "scope.key" for stable machine identity.

  • Exposes only Item, Task, and Tasks — operations that actually take the namespace.

  • Is NOT a security sandbox: plugins holding *Output bypass Scope entirely.

  • Session Capture, Writer, and SlogHandler stay on *Output (shared session).

    registry := out.Scope("registry") registry.Item("credentials", evo.ID("auth")).OK() // key → "registry.auth"

func (*Scope) Item added in v0.2.3

func (s *Scope) Item(name string, opts ...EntityOption) *Item

Item declares an item; optional evo.ID is prefixed with the scope name.

func (*Scope) Name added in v0.2.3

func (s *Scope) Name() string

Name returns the scope path segment.

func (*Scope) Task added in v0.2.3

func (s *Scope) Task(name string, opts ...EntityOption) *Task

Task declares a task; optional evo.ID is prefixed with the scope name.

func (*Scope) Tasks added in v0.2.7

func (s *Scope) Tasks(name string) *Tasks

Tasks declares a task collection under this scope's naming (human name only; child tasks still take evo.ID with scope qualification via Scope.Task).

type Snapshot

type Snapshot struct {
	Version     uint64
	OutputID    string
	Subject     string
	Items       []ItemSnapshot
	Tasks       []TaskSnapshot
	Collections []TasksSnapshot
	Changes     []ChangesSnapshot
	Plans       []PlanSnapshot
	Messages    []MessageSnapshot
	// Lines is a derived compatibility projection of projected message texts
	// (and legacy debug history lines). Prefer Messages for structured consumers.
	Lines      []string
	Actions    []Action
	Conclusion *Conclusion
	Timestamp  time.Time
}

Snapshot is an immutable complete presentation state at a version.

type SystemClock

type SystemClock struct{}

SystemClock uses the real wall clock.

func (SystemClock) Now

func (SystemClock) Now() time.Time

Now returns the system time.

type Task

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

Task is a handle for one operation with phases or progress.

func (*Task) Advance

func (t *Task) Advance(delta int64) *Task

Advance increments completed progress by delta. Advanced relative helper — prefer absolute Progress in ordinary code.

func (*Task) Bytes

func (t *Task) Bytes(completed, total int64) *Task

Bytes sets absolute byte progress (units and rate formatting).

func (*Task) Cancel

func (t *Task) Cancel(reason string) *Task

Cancel resolves the task as cancelled.

func (*Task) Capture added in v0.1.2

func (t *Task) Capture(opts ...CaptureOption) *Capture

Capture returns a process-output sink bound to this Task.

func (*Task) Done

func (t *Task) Done(summary ...string) *Task

Done resolves the task successfully. Optional one summary: Done("modules cached"). More than one summary panics.

func (*Task) Donef

func (t *Task) Donef(format string, args ...any) *Task

Donef resolves the task with a formatted summary. Prefer Done("text") when there are no format directives.

func (*Task) Fail

func (t *Task) Fail(summary string, options ...ProblemOption) *Task

Fail resolves the task as failed.

func (*Task) Next

func (t *Task) Next(actions ...Action) *Task

Next attaches actions.

func (*Task) NextCommand

func (t *Task) NextCommand(executable string, args ...string) *Task

NextCommand attaches a command action.

func (*Task) Phase

func (t *Task) Phase(text string) *Task

Phase sets the active phase text and starts the task if pending.

func (*Task) Progress

func (t *Task) Progress(completed, total int) *Task

Progress sets absolute completed/total count progress. Counts use int (collection lengths, indices). For byte quantities use Bytes. Prefer absolute Progress over Advance so retries cannot double-count.

func (*Task) Progress64 added in v0.2.0

func (t *Task) Progress64(completed, total int64) *Task

Progress64 is an advanced absolute count API for quantities outside the int range. Ordinary call sites should use Progress(int, int) or Bytes for byte totals.

func (*Task) Skip

func (t *Task) Skip(reason string) *Task

Skip resolves the task as skipped.

func (*Task) Snapshot

func (t *Task) Snapshot() TaskSnapshot

Snapshot returns the task snapshot.

func (*Task) Warn

func (t *Task) Warn(summary string, options ...ProblemOption) *Task

Warn resolves the task with a warning.

type TaskSnapshot

type TaskSnapshot struct {
	ID          string
	Key         string // optional stable machine key (evo.ID); empty when unset
	Name        string
	State       EntityState
	Phase       string
	Progress    Progress
	Summary     string
	Problems    []Problem
	Actions     []Action
	Collection  string
	Declaration int
}

TaskSnapshot is an immutable task view.

type Tasks

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

Tasks is a handle for a collection of independent child tasks. State is always derived from children; no Done/Fail/Progress methods.

func (*Tasks) Snapshot

func (g *Tasks) Snapshot() TasksSnapshot

Snapshot returns the collection snapshot with derived state.

func (*Tasks) Summary

func (g *Tasks) Summary(text string) *Tasks

Summary sets a success-oriented collection summary.

func (*Tasks) Summaryf

func (g *Tasks) Summaryf(format string, args ...any) *Tasks

Summaryf sets a formatted success-oriented collection summary.

func (*Tasks) Task

func (g *Tasks) Task(name string, opts ...EntityOption) *Task

Task declares a child task in declaration order. Optional evo.ID sets a stable machine key.

func (*Tasks) Taskf added in v0.2.0

func (g *Tasks) Taskf(format string, args ...any) *Task

Taskf formats a child task name under this collection.

type TasksSnapshot

type TasksSnapshot struct {
	ID          string
	Name        string
	State       EntityState
	Summary     string
	Tasks       []TaskSnapshot
	Declaration int
}

TasksSnapshot is an immutable collection view.

type TerminalDriver

type TerminalDriver interface {
	ID() string
}

TerminalDriver is the exclusive owner of terminal control sequences. Interactive implementation arrives in v0.2; the interface is defined early so options and tests compile.

type TimeSource

type TimeSource interface {
	Now() time.Time
}

TimeSource provides the current time for deterministic tests. Option constructor is Clock(TimeSource) to match the public API examples.

type UsageError added in v0.2.0

type UsageError struct {
	Op  string
	Msg string
}

UsageError is a programmer/user configuration error.

func (*UsageError) Error added in v0.2.0

func (e *UsageError) Error() string

type Verbosity added in v0.2.0

type Verbosity int

Verbosity selects which message visibilities are projected to the human stream. Zero is normal (non-verbose) human detail.

const (
	// VerbosityNormal projects Normal-visibility messages only.
	VerbosityNormal Verbosity = iota
	// VerbosityVerbose also projects Verbose-visibility messages.
	VerbosityVerbose
)

type Visibility added in v0.2.0

type Visibility uint8

Visibility selects whether a message is ordinary or verbose user detail. Zero is Normal.

const (
	// Normal messages always project at VerbosityNormal.
	Normal Visibility = iota
	// Verbose messages project only when Config.Verbosity is VerbosityVerbose.
	Verbose
)

Directories

Path Synopsis
agent
catalog
Package catalog is the task-oriented guidance catalog for agent assistance.
Package catalog is the task-oriented guidance catalog for agent assistance.
harness
Package harness evaluates agent-assistance scenarios (§30.9, MCP-022/049).
Package harness evaluates agent-assistance scenarios (§30.9, MCP-022/049).
preview
Package preview generates multi-profile plain previews from snapshots.
Package preview generates multi-profile plain previews from snapshots.
review
Package review provides deterministic static review of Evident Output usage.
Package review provides deterministic static review of Evident Output usage.
rules
Package rules is the stable review-rule registry (Appendix C namespaces).
Package rules is the stable review-rule registry (Appendix C namespaces).
cmd
evident-output command
Command evident-output provides review/preview/explain CLI parity with MCP tools.
Command evident-output provides review/preview/explain CLI parity with MCP tools.
evident-output-mcp command
Command evident-output-mcp is the stdio MCP server.
Command evident-output-mcp is the stdio MCP server.
examples
data-command command
Command data-command: domain JSON on stdout, human presentation on stderr.
Command data-command: domain JSON on stdout, human presentation on stderr.
debug-history command
Command debug-history demos durable debug scrollback via slog.
Command debug-history demos durable debug scrollback via slog.
debug-pane command
Command debug-pane demos rolling slog-text viewport.
Command debug-pane demos rolling slog-text viewport.
doctor command
Command doctor is an environment/health check CLI.
Command doctor is an environment/health check CLI.
install-pipeline command
Command install-pipeline demos Tasks, Progress, Capture, and Main.
Command install-pipeline demos Tasks, Progress, Capture, and Main.
internal/demo
Package demo is reserved for advanced example utilities.
Package demo is reserved for advanced example utilities.
live-progress command
Command live-progress is the ordinary multi-progress demo (user API only).
Command live-progress is the ordinary multi-progress demo (user API only).
migrate command
Command migrate shows dry-run Plan vs applied Changes.
Command migrate shows dry-run Plan vs applied Changes.
print command
Command print is the first adoption rung: Print/Printf/Println like fmt.
Command print is the first adoption rung: Print/Printf/Println like fmt.
repo-status command
Command repo-status is a realistic "is this repo safe to retire?" check.
Command repo-status is a realistic "is this repo safe to retire?" check.
scope-plugin command
Command scope-plugin demos evo.Scope + evo.ID for plugin-owned presentation.
Command scope-plugin demos evo.Scope + evo.ID for plugin-owned presentation.
terminal-driver command
Command terminal-driver is an advanced teaching surface: custom TerminalDriver, frame-by-frame logging, and explicit renderer knobs.
Command terminal-driver is an advanced teaching surface: custom TerminalDriver, frame-by-frame logging, and explicit renderer knobs.
verbose command
Command verbose shows Normal vs Verbose message visibility.
Command verbose shows Normal vs Verbose message visibility.
internal
sanitize
Package sanitize neutralizes untrusted text for terminal-safe display.
Package sanitize neutralizes untrusted text for terminal-safe display.
width
Package width computes terminal cell widths for display text.
Package width computes terminal cell widths for display text.
scripts
sync-release-pins command
Command sync-release-pins rewrites install pins on portable surfaces to match evo.PublishedRelease.
Command sync-release-pins rewrites install pins on portable surfaces to match evo.PublishedRelease.
traceability-check command
Command traceability-check verifies every expected §31 ID is present.
Command traceability-check verifies every expected §31 ID is present.
Package terminal provides production terminal drivers for Evident Output.
Package terminal provides production terminal drivers for Evident Output.
Package testkit provides deterministic clocks, screens, and assertions for evo tests.
Package testkit provides deterministic clocks, screens, and assertions for evo tests.

Jump to

Keyboard shortcuts

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