evo

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Sep 17, 2026 License: Apache-2.0 Imports: 12 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 — so the same call sites render correctly whether stdout is a real terminal or a log file, and the exit code always matches what the screen just said.

Install

go get github.com/zachbornheimer/evident-output@v1.0.0

Requires Go 1.25+. License: Apache-2.0.

Quickstart

import (
    "context"
    "os"

    evo "github.com/zachbornheimer/evident-output"
)

func main() {
    evo.Init(evo.Config{Title: "bpp-csharp"}) // first statement — arms first paint before any I/O
    os.Exit(evo.Main(run)) // exits the process itself; evo.Run(ctx, run) if you need the Result without exiting
}

func run(ctx context.Context) error {
    // Start as casually as fmt — then promote to structure when useful.
    evo.Println("Reading configuration")
    evo.Printf("Found %d packages\n", 18)

    evo.Task("working tree").Done()
    evo.Task("branches").Block(
        "local-only branch",
        evo.Detail("commit or stash before continuing"),
    )

    evo.Task("cleanup").Delete("stale local branch", func() error {
        return removeStaleBranches()
    }, evo.Affected(2)) // singular object, ledger renders "2 stale local branches"

    installs := evo.Group("install")
    for _, pkg := range packages {
        pkg := pkg
        installs.Task(pkg).Define(func(ctx context.Context) error { return install(pkg) })
    }
    return nil // Block is a presentation outcome, not a Go error
}

On a real terminal, install draws an in-place, colored, animated progress line while it runs — no extra code. Piped (prog > log.txt, CI, an agent harness), the same call sites fall back to plain, durable lines:

Reading configuration
Found 18 packages
✓ working tree
⊘ branches      local-only branch
   └─ commit or stash before continuing
◐ install  0/2
◐ install  1/2  a
◐ install  2/2  b
✓ cleanup
✓ install

[changed] cleanup  deleted 2 stale local branches

[blocked]  bpp-csharp

Exit code 1 — see the table below. Try the live, colored version: go run ./examples/repo-status/.

Conclusion band → exit code

The trailing [state] band and the process exit code always agree — never read one without checking the other. · partial and · warned are modifiers on the state, not a state of their own.

Band Exit code Meaning
[changed] 0 A mutation verb (Delete/Create/…) recorded outside DryRun
[planned] 0 A mutation verb recorded under Config.DryRun (would, not did)
[ready] 0 Every task resolved Done; no mutation verb recorded
[blocked] 1 At least one Block, and nothing Failed
[failed] 2 At least one Fail, or a caller-supplied misuse
[cancelled] 130 Cancel or an interrupt ended the run early
any of the above + · partial unchanged The run also left an unresolved task — same exit code as the state above
any of the above + · warned unchanged At least one Warn annotated a task without otherwise changing the headline — Warn never resolves the task itself; Done/Fail/Block/… still must

Pick the entity

Shape Use when
Task One atomic unit — a check/gate resolved directly (Done/Warn/Block/Fail/Skipped) or work submitted with Define / a mutation verb
Group Independent collection of atomic tasks (state is derived); the scheduler may overlap eligible children; one group.Task(name).Define(...) per item for homogeneous items
Sequence Ordered dependency of tasks (state is derived); a failed child auto-resolves later siblings to NotStarted; both nest via .Sequence/.Group

Learn more

Documentation

Overview

Package evo is Evident Output: a presentation and execution-tracking library for CLI state, progress, evidence, provenance, and conclusions.

Application code owns declaring work. Evo owns scheduling that work, tracking whether it is already satisfied, and presenting the result — so the same call sites render correctly whether stdout is a real terminal, a log file, or a machine consumer, and the exit code always matches what the screen just said.

Runnable examples for every concept below live alongside this file in example_1_0_test.go: ExampleInit, ExampleRun, ExampleMain, ExampleTask, ExampleGroup, ExampleSequence, ExampleTaskHandle_Define, ExampleTaskHandle_Verify, ExampleTaskHandle_Key, ExampleFile, and ExampleFact — go doc / pkg.go.dev attach each to the symbol it names.

func main() {
    evo.Init(evo.Config{Title: "repo"}) // first statement — arms first paint before any I/O
    os.Exit(evo.Main(run))
}

func run(ctx context.Context) error {
    evo.Println("Reading configuration")
    evo.Task("working tree").Done()
    t := evo.Task("fetch")
    cmd.Stdout = t.Writer()
    cmd.Stderr = t.Writer()
    return nil // Block is a presentation outcome, not a Go error
}

Migrating from 0.5

evo.MainWith and Task/Group/Sequence.Each were removed in 1.0.0. See docs/migration/1.0.md for every breaking change with before/after code, and docs/guides/teaching-ladder.md for the current adoption order.

Adoption ladder (spec §44 — guess-driven defaults, the naive spelling is correct)

  1. evo.Task(name) + Task.Define(func(context.Context) error) for one atomic unit of work — the scheduling and execution boundary (§7). A Task resolved directly with no Define call (Done/Warn/Block/Fail/Skipped) renders as a fact row instead of a spinner.
  2. evo.Group(name) / evo.Sequence(name) for collections: one named child Task per item (group.Task(name)), not a hand-maintained counter — Group's children may overlap, Sequence's run in declaration order and cascade a failure to NotStarted for later siblings. Group.Each and Sequence.Each were removed in 1.0.0; a repeated child name under the same parent is a duplicate sibling declaration, not a get-or-create (§3.1).
  3. evo.File(ctx, evo.FileSpec{...}) for declarative managed-state file content — Evo creates, rewrites on drift, and no-ops when the desired state already holds. ctx must come from a Task's Define callback.
  4. evo.Exec for external work with declared outputs and a Basis of Fingerprints that determine freshness (planned; not yet implemented).
  5. A Task-level Basis of evo.Fingerprint values (evo.FSPath, evo.Value, evo.App) when an operation's freshness depends on semantic external inputs beyond File/Exec's own tracked state.
  6. Task.After for exceptional scheduler edges that a Sequence would otherwise express more simply.
  7. Task.Fact / evo.Fact for discovered information, Task.Warn for a non-terminal annotation, Output Effects, and Config.DryRun for the would/did split.
  8. Task.Verify(func(context.Context) (bool, error)) only for domains Evo cannot track automatically — the one boolean, read-only escape hatch; a Verify that reports the desired state already holds skips Define and resolves ResolutionAlreadySatisfied.
  9. Top-level Config.Format / Config.Verbosity only when the host CLI needs machine output or verbose detail — never set per Task.

Do not require named Evidence declarations (a legacy mutating callback registered under that name) for common resources; evo.File/evo.Exec cover the ordinary cases without one.

Ordinary surface

evo.Init/evo.Main/evo.Run, Output.Run for a hosted/Isolated instance, Print*, evo.Task/evo.Group/evo.Sequence, Task.Define / mutation verbs / Task.Writer, Task.Fail / Task.Failf / Task.Block / Task.Blockf, evo.Confirm, evo.Reason, slog via SlogHandler (level from Config.Debug.Level).

Advanced surface

For testing and tooling call sites that need a hosted instance instead of the package-level default: Config.Isolated returns an independent *Output that never touches package state; Output.Run(ctx, run) Result seals it (the hosted counterpart of Main, returning the full Result — Conclusion plus the application error — instead of just the derived exit code, and never exiting the process). Task.Key overrides a Task's stable identity when its name changes across runs but tracked state must not (§3.1). Task.Verify, evo.File, and Fingerprint (evo.FSPath/evo.Value/evo.App) are the tracked-state primitives; Config.AppID/Config.StateDir override the manifest's storage location and namespace.

Example (BeginnerAPI)

Example_beginnerAPI proves the beginner shape compiles and renders real rows, not an empty // Output: that only proves compile (evo-dialect-axes- report.md axis 2: "the example discards stdout and asserts nothing"). Sequence (declaration order, one Running child at a time) keeps the two child rows deterministic across runs; Group.Each would be correct too but collapses an all-success aggregate into a single summary line.

package main

import (
	"bytes"
	"context"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{Stdout: &buf, Stderr: io.Discard, Plain: true})
	check := func(string) error { return nil }
	worktrees := out.Sequence("worktrees")
	for _, path := range []string{"repo-a", "repo-b"} {
		task := worktrees.Task(path)
		task.Define(func(ctx context.Context) error { return check(path) })
	}
	if err := out.Finish(); err != nil {
		fmt.Println(err)
	}
	fmt.Print(buf.String())
}
Output:
✓ worktrees
   ✓ repo-a
   ✓ repo-b

Index

Examples

Constants

View Source
const (
	ExitOK        = core.ExitOK
	ExitBlocked   = core.ExitBlocked
	ExitFailed    = core.ExitFailed
	ExitCancelled = core.ExitCancelled
)

Default exit codes from architecture §26.

View Source
const (
	// ResolutionExecuted marks a Task whose Define callback was entered and
	// returned successfully.
	ResolutionExecuted = core.ResolutionExecuted
	// ResolutionAlreadySatisfied marks a Task whose Define callback was
	// skipped because a pre-Define Verify observed the desired state
	// already held.
	ResolutionAlreadySatisfied = core.ResolutionAlreadySatisfied
	// ResolutionNoWork marks a Task explicitly resolved successfully
	// without ever reaching Define.
	ResolutionNoWork = core.ResolutionNoWork
)
View Source
const (
	// GlyphsAuto detects the vocabulary from locale and TTY interactivity.
	GlyphsAuto = txt.GlyphsAuto
	// GlyphsUnicode forces the Unicode vocabulary regardless of locale.
	GlyphsUnicode = txt.GlyphsUnicode
	// GlyphsASCII forces the ASCII vocabulary regardless of locale.
	GlyphsASCII = txt.GlyphsASCII
)
View Source
const (
	Pending    = core.Pending
	Running    = core.Running
	Done       = core.Done
	Blocked    = core.Blocked
	Failed     = core.Failed
	Skipped    = core.Skipped
	Cancelled  = core.Cancelled
	Empty      = core.Empty
	Incomplete = core.Incomplete
	// NotStarted marks a group task that never ran because an earlier sibling
	// already failed or was cancelled — rendered "-  <name>  not started" and
	// excluded from the conclusion (the group's verdict comes from the
	// failed/cancelled sibling, not from its unstarted followers).
	NotStarted = core.NotStarted
)

EntityState values — see the type doc comment above for the naming rationale (no State* prefix on this block).

View Source
const (
	StateReady     = core.StateReady
	StateChanged   = core.StateChanged
	StateWarning   = core.StateWarning
	StateBlocked   = core.StateBlocked
	StateFailed    = core.StateFailed
	StateCancelled = core.StateCancelled
	StatePlanned   = core.StatePlanned
)

ConclusionState values — the trailing "[state]" band a run can end in.

View Source
const (
	Indeterminate = core.Indeterminate
	Determinate   = core.Determinate
	BytesKind     = core.BytesKind
)

ProgressKind values — which measurement a task's Progress reports.

View Source
const (
	// VisibilityNormal messages always project at VerbosityNormal (C11:
	// prefixed consistently with VisibilityVerbose — the two enum members
	// previously disagreed on their own naming convention).
	VisibilityNormal = core.VisibilityNormal
	// VisibilityVerbose messages project only when Config.Verbosity is VerbosityVerbose.
	VisibilityVerbose = core.VisibilityVerbose
)
View Source
const (
	ColorAuto   = engine.ColorAuto
	ColorAlways = engine.ColorAlways
	ColorNever  = engine.ColorNever
)
View Source
const (
	FormatHuman    = engine.FormatHuman
	FormatData     = engine.FormatData
	FormatExternal = engine.FormatExternal
	// FormatJSON writes one final v2 "evo.run" document to Stdout at
	// Finish; human presentation still goes to Stderr (spec §32.1).
	FormatJSON = engine.FormatJSON
	// FormatJSONL streams v2 "evo.event" JSON lines to Stdout as they
	// occur, plus a final run.finished line (spec §32.1).
	FormatJSONL = engine.FormatJSONL
)
View Source
const (
	VerbosityNormal  = engine.VerbosityNormal
	VerbosityVerbose = engine.VerbosityVerbose
)
View Source
const (
	ProjectionHuman      = engine.ProjectionHuman
	ProjectionPlain      = engine.ProjectionPlain
	ProjectionJSON       = engine.ProjectionJSON
	ProjectionJSONL      = engine.ProjectionJSONL
	ProjectionStreamJSON = engine.ProjectionStreamJSON
)
View Source
const (
	LevelUnset = engine.LevelUnset
	LevelTrace = engine.LevelTrace
	LevelDebug = engine.LevelDebug
	LevelInfo  = engine.LevelInfo
	LevelWarn  = engine.LevelWarn
	LevelError = engine.LevelError
)
View Source
const (
	DebugPresentationHistory = engine.DebugPresentationHistory
	DebugPresentationPane    = engine.DebugPresentationPane
)
View Source
const (
	EvidenceStreamCombined = engine.EvidenceStreamCombined
	EvidenceStreamStdout   = engine.EvidenceStreamStdout
	EvidenceStreamStderr   = engine.EvidenceStreamStderr
)
View Source
const (
	ProblemCodeDuplicateSiblingName    = engine.ProblemCodeDuplicateSiblingName
	ProblemCodeVerificationUnsatisfied = engine.ProblemCodeVerificationUnsatisfied
)

Problem codes are stable, machine-readable Problem.Code values a consumer matches on instead of parsing Summary text.

View Source
const DefaultVisibleNames = engine.DefaultVisibleNames
View Source
const EventSchemaVersion = core.EventSchemaVersion

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 = render.JSONSchemaVersion

JSONSchemaVersion is the final JSON document schema version. Tracks the 0.3 contract series (pre-1.0 wire format may still evolve). Bumped from 0.2: "items" no longer exists as a separate wire kind — the item/task fold means every entity (including a fact-check resolved without ever running) is a "tasks" row (CHANGELOG "Unreleased").

View Source
const PublishedRelease = "v1.0.0"

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. Promote CHANGELOG ## Unreleased → ## [X.Y.Z] (Keep a Changelog).
  2. Set PublishedRelease to the new tag (e.g. "v0.2.11").
  3. Prefer: mise run test && mise run cut-release (cut-release syncs pins, stages CHANGELOG, refuses Unreleased drift).
  4. Tag that commit; do not move prior tags.

version_drift_test.go enforces the portable surface stays synchronized.

Variables

View Source
var (
	ErrExecSpecMissingExecutable     = engine.ErrExecSpecMissingExecutable
	ErrExecExecutableNotFound        = engine.ErrExecExecutableNotFound
	ErrExecNonzeroExit               = engine.ErrExecNonzeroExit
	ErrExecOutputMissingAfterSuccess = engine.ErrExecOutputMissingAfterSuccess
)

Exec-specific usage and outcome errors (spec §8.4).

View Source
var (
	ErrFileSpecMissingPath          = engine.ErrFileSpecMissingPath
	ErrFileUnmanagedContentsMissing = engine.ErrFileUnmanagedContentsMissing
	ErrFilePathIsSymlink            = engine.ErrFilePathIsSymlink
	ErrFilePathTypeMismatch         = engine.ErrFilePathTypeMismatch
)

File-specific usage errors (spec §8.1).

View Source
var (
	ErrClosed               = engine.ErrClosed
	ErrAlreadyResolved      = engine.ErrAlreadyResolved
	ErrUnresolvedTask       = engine.ErrUnresolvedTask
	ErrInvalidProgress      = engine.ErrInvalidProgress
	ErrProgressRegression   = engine.ErrProgressRegression
	ErrDuplicateKey         = engine.ErrDuplicateKey
	ErrInvalidConfig        = engine.ErrInvalidConfig
	ErrRenderer             = engine.ErrRenderer
	ErrLimitExceeded        = engine.ErrLimitExceeded
	ErrReasonSkipOnly       = engine.ErrReasonSkipOnly
	ErrReasonWrongTask      = engine.ErrReasonWrongTask
	ErrConcurrentRunning    = engine.ErrConcurrentRunning
	ErrDryRunDeclaredLate   = engine.ErrDryRunDeclaredLate
	ErrTerminalWithoutSink  = engine.ErrTerminalWithoutSink
	ErrNotStarted           = engine.ErrNotStarted
	ErrWaitDeadlock         = engine.ErrWaitDeadlock
	ErrDuplicateSiblingName = engine.ErrDuplicateSiblingName
	ErrKeyAfterDefine       = engine.ErrKeyAfterDefine
	ErrNoTaskContext        = engine.ErrNoTaskContext
	ErrTaskClosed           = engine.ErrTaskClosed
)

Functions

func Confirm added in v0.3.0

func Confirm(question string, opts ...ConfirmOption) bool

Confirm asks question on the default instance and returns whether the user accepted.

Example

ExampleConfirm asks a question and resolves it non-interactively via AssumeYes — the gate that owns the whole ask-decide-resolve flow.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	ok := out.Confirm("delete the branch?", evo.AssumeYes(true))
	fmt.Println(ok)
}
Output:
true

func Delay added in v0.2.7

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

ExampleDelay returns a non-nil *time.Duration for Config fields where zero is meaningful, like VisibilityDelay.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	d := evo.Delay(0)
	fmt.Println(*d)
}
Output:
0s

func EncodeEventJSON added in v0.5.0

func EncodeEventJSON(e Event) ([]byte, error)

EncodeEventJSON encodes one journal event as a single JSON object (no newline).

Example

ExampleEncodeEventJSON encodes one journal event as a single JSON object, with no trailing newline.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	data, err := evo.EncodeEventJSON(evo.Event{Type: "task.done", Name: "apply patch"})
	fmt.Println(err)
	fmt.Println(string(data))
}
Output:
<nil>
{"schema_version":"0.3","sequence":0,"type":"task.done","name":"apply patch","timestamp":"0001-01-01T00:00:00Z"}

func EncodeJSON

func EncodeJSON(s Snapshot) ([]byte, error)

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

Example

ExampleEncodeJSON encodes a finished Snapshot as the final wire JSONDocument (§25.1).

package main

import (
	"encoding/json"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	out.Task("apply patch").Done()
	_ = out.Finish()
	data, err := evo.EncodeJSON(out.Snapshot())
	var doc evo.JSONDocument
	_ = json.Unmarshal(data, &doc)
	fmt.Println(err, doc.Conclusion.State)
}
Output:
<nil> ready

func EncodeJSONL

func EncodeJSONL(events []Event) ([]byte, error)

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

Example

ExampleEncodeJSONL encodes durable events as JSON Lines (§25.2).

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	events := []evo.Event{{Type: "task.done", Name: "apply patch"}}
	data, err := evo.EncodeJSONL(events)
	fmt.Println(err)
	fmt.Println(len(data) > 0)
}
Output:
<nil>
true

func Exec added in v1.0.0

func Exec(ctx context.Context, spec ExecSpec) error

Exec declares/reconciles one managed-state subprocess invocation: it skips spawning when a prior record proves the operation is already current (matching definition, Basis, and every declared Output digest), otherwise runs the child and verifies its declared Outputs afterward. A nonzero exit, or a declared Output missing after a zero exit, fails the operation. ctx must come from a Task's Define callback; called any other way it returns ErrNoTaskContext or ErrTaskClosed.

Example

ExampleExec reconciles one managed-state subprocess invocation from inside a Task's Define callback, through the same ProcessRunner facade a test replaces with testkit.ProcessRunner.

package main

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"os"
	"path/filepath"

	evo "github.com/zachbornheimer/evident-output"
	"github.com/zachbornheimer/evident-output/testkit"
)

func main() {
	dir, err := os.MkdirTemp("", "evo-example-exec")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer func() { _ = os.RemoveAll(dir) }()
	outPath := filepath.Join(dir, "out.bin")

	runner := testkit.NewProcessRunner()
	runner.Script("/usr/bin/tool", testkit.ScriptedProcess{ExitCode: 0})
	// The scripted runner never actually writes outPath, so declare it
	// ahead of time the way a real generator's own subprocess would.
	if err := os.WriteFile(outPath, []byte("generated"), 0o644); err != nil {
		fmt.Println(err)
		return
	}

	var buf bytes.Buffer
	out := evo.Init(evo.Config{
		Isolated: true, Stdout: &buf, Stderr: io.Discard, Plain: true, StateDir: dir,
		Options: []evo.Option{evo.Runner(runner)},
	})
	task := out.Task("generate")
	task.Define(func(ctx context.Context) error {
		return evo.Exec(ctx, evo.ExecSpec{
			Executable: "/usr/bin/tool",
			Args:       []string{"--out", outPath},
			Outputs:    []string{outPath},
		})
	})
	_ = task.Wait()
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✓ generate
[changed] generate  ran /usr/bin/tool

[changed]

func Fact added in v0.4.0

func Fact(name, value string)
Example

ExampleFact records a discovered name/value annotation about the run itself.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	evo.SetDefault(out)
	evo.Fact("language", "go")
	_ = out.Finish()
	fmt.Println(len(out.Snapshot().Facts) == 1, out.Snapshot().Facts[0].Value)
}
Output:
true go

func File added in v1.0.0

func File(ctx context.Context, spec FileSpec) error

File declares/reconciles one managed-state file resource: it creates a missing file, rewrites one whose contents differ from FileSpec.Contents, and/or chmods one whose mode differs from FileSpec.Mode — a no-op when every managed attribute already matches. ctx must come from a Task's Define callback; called any other way it returns ErrNoTaskContext or ErrTaskClosed.

Example

ExampleFile declares/reconciles one managed-state file resource: Evo creates it, rewrites it when Contents differ, and no-ops when the desired state already holds — common file work never needs a hand- written Evidence callback (spec §8, §56).

package main

import (
	"context"
	"fmt"
	"io"
	"os"
	"path/filepath"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	dir, err := os.MkdirTemp("", "evo-example-file")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer func() { _ = os.RemoveAll(dir) }()
	path := filepath.Join(dir, "config.json")

	out := evo.Init(evo.Config{Isolated: true, StateDir: dir, Stdout: io.Discard, Stderr: io.Discard})
	result := out.Run(context.Background(), func(ctx context.Context) error {
		task := out.Task("config")
		task.Define(func(ctx context.Context) error {
			return evo.File(ctx, evo.FileSpec{Path: path, Contents: []byte(`{"ok":true}`)})
		})
		return nil
	})
	contents, err := os.ReadFile(path)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(result.ExitCode())
	fmt.Println(string(contents))
}
Output:
0
{"ok":true}

func IsCharDevice

func IsCharDevice(w io.Writer) bool
Example

ExampleIsCharDevice reports whether w is an interactive character device (a real terminal) — false for an ordinary buffer or file.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	fmt.Println(evo.IsCharDevice(io.Discard))
}
Output:
false

func Main

func Main(run RunFunc) int

Main executes run against the default Output and returns the derived exit code; it does not itself call os.Exit — callers write os.Exit(evo.Main(run)).

Example

ExampleMain shows deriving a process exit code from a RunFunc without evo.Main itself calling os.Exit — the caller writes os.Exit(evo.Main(run)).

package main

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	evo.SetDefault(evo.Init(evo.Config{Stdout: &buf, Stderr: io.Discard, Plain: true}))
	code := evo.Main(func(ctx context.Context) error {
		return errors.New("disk full")
	})
	fmt.Println(code)
}
Output:
2

func Pluralize added in v0.3.0

func Pluralize(quantity int64, singular string) string
Example

ExamplePluralize formats a quantity with its singular noun pluralized when the quantity isn't exactly one.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	fmt.Println(evo.Pluralize(1, "branch"))
	fmt.Println(evo.Pluralize(3, "branch"))
}
Output:
branch
branches

func Print added in v0.3.0

func Print(args ...any)

Print formats like fmt.Sprint and enqueues human-facing text on the default instance.

Example

ExamplePrint shows fmt.Sprint-style human text on the default instance.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	evo.SetDefault(evo.Init(evo.Config{Stdout: &buf, Stderr: io.Discard, Plain: true}))
	evo.Print("repo ", "clean")
	_ = evo.Default().Finish()
	fmt.Print(buf.String())
}
Output:
repo clean

func Printf added in v0.3.0

func Printf(format string, args ...any)

Printf formats like fmt.Sprintf and enqueues human-facing text on the default instance.

Example

ExamplePrintf shows fmt.Sprintf-style human text on the default instance.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	evo.SetDefault(evo.Init(evo.Config{Stdout: &buf, Stderr: io.Discard, Plain: true}))
	evo.Printf("found %d issues", 3)
	_ = evo.Default().Finish()
	fmt.Print(buf.String())
}
Output:
found 3 issues

func Println added in v0.3.0

func Println(args ...any)

Println formats like fmt.Sprintln and enqueues a complete line on the default instance.

Example

ExamplePrintln shows a complete human line on the default instance.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	evo.SetDefault(evo.Init(evo.Config{Stdout: &buf, Stderr: io.Discard, Plain: true}))
	evo.Println("reading configuration")
	_ = evo.Default().Finish()
	fmt.Print(buf.String())
}
Output:
reading configuration

func RenderPlain

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

ExampleRenderPlain renders a Snapshot as the durable plain-text report — the same renderer Config.Plain wires up automatically.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	out.Task("apply patch").Done()
	_ = out.Finish()
	data, err := evo.RenderPlain(out.Snapshot(), evo.PlainOptions{NoColor: true})
	fmt.Println(err)
	fmt.Print(string(data))
}
Output:
<nil>
✓ apply patch

func SetDefault added in v0.3.0

func SetDefault(out *Output)

SetDefault installs out as the package-level default Output.

Example

ExampleSetDefault installs an explicit Output as the package-level default, so evo.Task and friends operate on it.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{Stdout: &buf, Stderr: io.Discard, Plain: true, Isolated: true})
	evo.SetDefault(out)
	evo.Task("wire default").Done()
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✓ wire default

func SlogHandler added in v0.3.0

func SlogHandler() slog.Handler

SlogHandler returns a slog.Handler journaling to the default instance.

Example

ExampleSlogHandler shows journaling through the standard library's slog.Logger into the default instance's debug journal.

package main

import (
	"bytes"
	"fmt"
	"io"
	"log/slog"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	evo.SetDefault(evo.Init(evo.Config{
		Stdout: io.Discard, Stderr: &buf, Plain: true,
		Debug: evo.DebugConfig{Level: evo.LevelDebug},
	}))
	logger := slog.New(evo.SlogHandler())
	logger.Info("connected to registry")
	_ = evo.Default().Finish()
	fmt.Println(bytes.Contains(buf.Bytes(), []byte("connected to registry")))
}
Output:
true

func TruncateNames added in v0.2.16

func TruncateNames(names []string, visible int) string
Example

ExampleTruncateNames bounds a name list to visible entries, summarizing the rest.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	fmt.Println(evo.TruncateNames([]string{"main", "dev", "release", "hotfix"}, 2))
}
Output:
main, dev … +2 more

func Warn added in v0.4.0

func Warn(summary string)
Example

ExampleWarn annotates the run itself with a warning, without resolving any task.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	evo.SetDefault(out)
	evo.Warn("cache directory missing, rebuilding")
	_ = out.Finish()
	fmt.Println(out.Conclusion().Warned)
}
Output:
true

func WriteJSON added in v0.2.0

func WriteJSON(w io.Writer, result Result) error

WriteJSON serializes result as the stable v2 "evo.run" wire document plus one trailing newline (spec §53) — the HTTP/embedding counterpart of FormatJSON's automatic Stdout write. It never serializes internal snapshots directly, and applies the same redaction Result's Conclusion already carries. HTTP status (or any other transport-level outcome) is the embedding application's own concern; Evo's outcome/exit semantics stay in the body (Conclusion.State/ExitCode).

Example

ExampleWriteJSON serializes a finished Result as the stable v2 "evo.run" wire document plus one trailing newline — the HTTP/embedding counterpart of FormatJSON's automatic Stdout write.

package main

import (
	"bytes"
	"context"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	result := out.Run(context.Background(), func(ctx context.Context) error {
		out.Task("apply patch").Done()
		return nil
	})
	var buf bytes.Buffer
	err := evo.WriteJSON(&buf, result)
	fmt.Println(err)
	fmt.Println(bytes.Contains(buf.Bytes(), []byte(`"evo.run"`)))
}
Output:
<nil>
true

Types

type Action

type Action = core.Action

Action is a recommended next step for the user.

Aliased into internal/core alongside the rest of the data model — see Snapshot's doc comment (snapshot.go) for why.

Example

ExampleAction shows the recommended-next-step shape attached to a Problem or a resolved Task via Next/NextCommand.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	action := evo.Action{Label: "retry with --force"}
	fmt.Println(action.Label)
}
Output:
retry with --force

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.

Example

ExampleCommand builds a recommended next step naming an executable command to run.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	action := evo.Command("git", "push", "--force-with-lease")
	fmt.Println(action.Command.Executable, action.Command.Args)
}
Output:
git [push --force-with-lease]

func Label added in v0.3.0

func Label(text string) Action

Label builds a plain-text recommended next step with no executable command (e.g. a policy hint like "pass --yes to confirm non-interactively").

Example

ExampleLabel builds a plain-text recommended next step with no executable command — a policy hint like "pass --yes to confirm non-interactively".

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	action := evo.Label("pass --yes to confirm non-interactively")
	fmt.Println(action.Label)
}
Output:
pass --yes to confirm non-interactively

type Attachment added in v0.3.0

type Attachment = core.Attachment

Attachment is an additional label/value problem attachment.

Named Attachment (not Evidence) because Evidence names the retained process-output sink (see Evidence in capture.go) — this is a single labeled fact attached to a Problem, a different concept from that sink.

Example

ExampleAttachment shows an additional label/value fact attached to a Problem — a different concept from the Evidence retention sink.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	a := evo.Attachment{Label: "stderr", Value: "permission denied"}
	fmt.Println(a.Label, a.Value)
}
Output:
stderr permission denied

type ChangesSnapshot

type ChangesSnapshot = core.ChangesSnapshot

ChangesSnapshot is an immutable changes section.

Example

ExampleChangesSnapshot reads an immutable changes section: the records a mutation verb recorded, run without DryRun.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	out.Task("prune branches").Delete("stale branch", func() error { return nil }, evo.Affected(2))
	_ = out.Finish()
	changes := out.Snapshot().Changes[0]
	fmt.Println(changes.Records[0].Verb, changes.Records[0].Quantity)
}
Output:
deleted 2

type ColorMode added in v0.2.0

type ColorMode = engine.ColorMode
Example

ExampleColorMode selects the color policy — default ColorAuto uses TTY detection and honors NO_COLOR.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	c := evo.ColorNever
	fmt.Println(c == evo.ColorNever)
}
Output:
true

type CommandSpec

type CommandSpec = core.CommandSpec

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

Example

ExampleCommandSpec shows an executable plus argv — never a shell string — the shape Command builds and Action.Command carries.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	spec := evo.CommandSpec{Executable: "git", Args: []string{"push", "--force-with-lease"}}
	fmt.Println(spec.Executable, spec.Args)
}
Output:
git [push --force-with-lease]

type Conclusion

type Conclusion = core.Conclusion

Conclusion is the multidimensional meaning of a finished command.

Aliased into internal/core alongside the rest of the data model — see Snapshot's doc comment (snapshot.go) for why, and EVIDENT_OUTPUT_ARCHITECTURE_SPEC_v0.5.md §38 for the full layout.

Example

ExampleConclusion shows the multidimensional meaning of a finished command, read from a real run.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	out.Task("apply patch").Done()
	_ = out.Finish()
	c := out.Conclusion()
	fmt.Println(c.State, c.ExitCode)
}
Output:
ready 0

type ConclusionJSON

type ConclusionJSON = render.ConclusionJSON

ConclusionJSON is JSON-friendly conclusion.

Example

ExampleConclusionJSON shows the JSON-friendly conclusion projection.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	c := evo.ConclusionJSON{State: evo.StateReady, ExitCode: evo.ExitOK}
	fmt.Println(c.State, c.ExitCode)
}
Output:
ready 0

type ConclusionState

type ConclusionState = core.ConclusionState

ConclusionState is the human headline for a finished output.

Example

ExampleConclusionState shows the human headline for a finished output.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	out.Task("apply patch").Done()
	_ = out.Finish()
	fmt.Println(out.Conclusion().State == evo.StateReady)
}
Output:
true

type Config

type Config = engine.Config
Example

ExampleConfig shows the ordinary application-facing construction surface: a Title and an explicit Stdout writer.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	cfg := evo.Config{Title: "demo", Stdout: &buf, Stderr: io.Discard, Plain: true, Isolated: true}
	out := evo.Init(cfg)
	out.Task("scan").Done()
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✓ scan

[ready]  demo

func DefaultConfig added in v0.2.0

func DefaultConfig() Config
Example

ExampleDefaultConfig shows building a mutable baseline Config and overriding one field before passing it to Init.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	cfg := evo.DefaultConfig()
	cfg.Title = "repo-retire"
	fmt.Println(cfg.Title)
}
Output:
repo-retire

type ConfirmOption added in v0.3.0

type ConfirmOption = engine.ConfirmOption
Example

ExampleConfirmOption shows the interface every Confirm modifier (AssumeYes, ConfirmDetail, Destructive, PolicyFlag, PolicyHint) implements.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	opt := evo.AssumeYes(true)
	fmt.Println(opt != nil)
}
Output:
true

func AssumeYes added in v0.3.0

func AssumeYes(v bool) ConfirmOption
Example

ExampleAssumeYes resolves a Confirm gate non-interactively — the programmatic equivalent of a caller's own --yes flag.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	ok := out.Confirm("proceed?", evo.AssumeYes(true))
	fmt.Println(ok)
}
Output:
true

func ConfirmDetail added in v0.3.0

func ConfirmDetail(lines ...string) ConfirmOption
Example

ExampleConfirmDetail attaches context lines rendered under the prompt.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{Stdout: &buf, Stderr: io.Discard, Plain: true, Isolated: true})
	out.Confirm("delete 3 branches?", evo.AssumeYes(true), evo.ConfirmDetail("main", "release"))
	fmt.Println("resolved")
}
Output:
resolved

func Destructive added in v0.3.0

func Destructive() ConfirmOption
Example

ExampleDestructive marks a Confirm gate as guarding a destructive action.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	ok := out.Confirm("wipe the cache?", evo.AssumeYes(true), evo.Destructive())
	fmt.Println(ok)
}
Output:
true

func PolicyFlag added in v0.3.0

func PolicyFlag(flag string) ConfirmOption
Example

ExamplePolicyFlag names the flag a script can pass to bypass the gate non-interactively — rendered in the assumed-policy hint.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	ok := out.Confirm("continue?", evo.AssumeYes(true), evo.PolicyFlag("--yes"))
	fmt.Println(ok)
}
Output:
true

func PolicyHint added in v0.3.0

func PolicyHint(command string, args ...string) ConfirmOption
Example

ExamplePolicyHint attaches a recommended non-interactive command instead of the default "pass --yes" wording.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	ok := out.Confirm("continue?", evo.AssumeYes(true), evo.PolicyHint("tool", "--yes"))
	fmt.Println(ok)
}
Output:
true

type DebugConfig added in v0.2.0

type DebugConfig = engine.DebugConfig
Example

ExampleDebugConfig configures the debug journal presentation: the minimum level and whether it renders as durable history or a bounded pane.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	cfg := evo.DebugConfig{Level: evo.LevelDebug, View: evo.DebugPresentationHistory}
	fmt.Println(cfg.Level == evo.LevelDebug, cfg.View == evo.DebugPresentationHistory)
}
Output:
true true

type DebugPaneOption

type DebugPaneOption = engine.DebugPaneOption
Example

ExampleDebugPaneOption shows the interface every debug-pane knob (NewestFirst, OldestFirst, PaneHeight, PreserveDebugTail) implements.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	opt := evo.PaneHeight(5)
	fmt.Println(opt != nil)
}
Output:
true

func NewestFirst

func NewestFirst() DebugPaneOption
Example

ExampleNewestFirst orders a debug pane newest-entry-first.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{
		Isolated: true, Plain: true, Stdout: &buf, Stderr: io.Discard,
		Debug:   evo.DebugConfig{Level: evo.LevelDebug, View: evo.DebugPresentationPane},
		Options: []evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor(), evo.DebugPane(evo.NewestFirst())},
	})
	out.Task("demo").Done()
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✓ demo

func OldestFirst

func OldestFirst() DebugPaneOption
Example

ExampleOldestFirst orders a debug pane oldest-entry-first.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{
		Isolated: true, Stdout: io.Discard, Stderr: io.Discard,
		Options: []evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor(), evo.DebugPane(evo.OldestFirst())},
	})
	out.Task("demo").Done()
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✓ demo

func PaneHeight

func PaneHeight(lines int) DebugPaneOption
Example

ExamplePaneHeight bounds a debug pane's visible line count (default 5).

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{
		Isolated: true, Stdout: io.Discard, Stderr: io.Discard,
		Options: []evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor(), evo.DebugPane(evo.PaneHeight(3))},
	})
	out.Task("demo").Done()
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✓ demo

func PreserveDebugTail

func PreserveDebugTail() DebugPaneOption
Example

ExamplePreserveDebugTail forces a diagnostic tail on every Finish in pane mode.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{
		Isolated: true, Stdout: io.Discard, Stderr: io.Discard,
		Options: []evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor(), evo.DebugPane(evo.PreserveDebugTail())},
	})
	out.Task("demo").Done()
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✓ demo

type DebugPresentation

type DebugPresentation = engine.DebugPresentation
Example

ExampleDebugPresentation selects history vs pane presentation for the debug journal (default History).

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	view := evo.DebugPresentationPane
	fmt.Println(view == evo.DebugPresentationPane)
}
Output:
true

type EffectRecord

type EffectRecord = core.EffectRecord

EffectRecord is one semantic change or plan row.

Example

ExampleEffectRecord shows one semantic change or plan row.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	r := evo.EffectRecord{Verb: "delete", Quantity: 2, HasQty: true, Object: "stale branch"}
	fmt.Println(r.Verb, r.Quantity, r.Object)
}
Output:
delete 2 stale branch

type EntityOption added in v0.2.3

type EntityOption = engine.EntityOption
Example

ExampleEntityOption shows the interface ID and StartPhase implement — an advanced, platform-scale Task-declaration configuration surface.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	opt := evo.ID("download-base-image")
	fmt.Println(opt != nil)
}
Output:
true

func ID added in v0.2.3

func ID(id string) EntityOption

ID sets a stable machine key. Superseded: Task is name-only.

Example

ExampleID sets a stable machine key independent of a Task's human label (superseded today: Task is name-only, kept for advanced/platform callers building their own declaration layer over EntityOption).

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	opt := evo.ID("download-base-image")
	fmt.Println(opt != nil)
}
Output:
true

func StartPhase added in v0.3.0

func StartPhase(text string) EntityOption

StartPhase sets a task's first doing-text at declare time. Superseded: call Doing.

Example

ExampleStartPhase sets a task's first doing-text at declare time (superseded today: call TaskHandle.Doing after declaring instead).

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	opt := evo.StartPhase("resolving dependencies")
	fmt.Println(opt != nil)
}
Output:
true

type EntityState

type EntityState = core.EntityState

EntityState is the lifecycle state of an item or task.

C11 naming sweep: these members stay bare (Done, Failed, Blocked, ...) rather than gaining a State* prefix to match ConclusionState below — prefixing would collide outright with ConclusionState's own StateFailed/ StateBlocked/StateCancelled/StateWarning constants (same package, same identifiers, different types is still a duplicate declaration in Go). Renaming ConclusionState's constants instead would ripple into the JSON wire (schema 0.3, frozen this release) and every existing golden — this is the "document instead" branch the census decision allows.

Aliased into internal/core alongside the rest of the data model — see Snapshot's doc comment (snapshot.go) for why.

Example

ExampleEntityState shows the lifecycle state of an item or task, read from a resolved TaskSnapshot.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	task := out.Task("apply patch")
	task.Done()
	_ = out.Finish()
	state := task.Snapshot().State
	fmt.Println(state == evo.Done)
}
Output:
true

type Event

type Event = core.Event

Event is an immutable journal record.

Aliased into internal/core alongside the rest of the data model — see Snapshot's doc comment (snapshot.go) for why.

Example

ExampleEvent shows the immutable journal record durable event streams carry.

package main

import (
	"fmt"
	"time"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	e := evo.Event{Type: "task.done", Name: "apply patch", Timestamp: time.Unix(0, 0)}
	fmt.Println(e.Type, e.Name)
}
Output:
task.done apply patch

type EventJSON

type EventJSON = render.EventJSON

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

Example

ExampleEventJSON shows a JSON Lines event record (§25.2).

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	e := evo.EventJSON{Type: "task.done", Name: "apply patch"}
	fmt.Println(e.Type, e.Name)
}
Output:
task.done apply patch

type Evidence

type Evidence = engine.Evidence
Example

ExampleEvidence shows the retained/redacted process-output sink's zero value: with no owning Output attached (only reachable internally via TaskHandle.Writer), Write is a safe no-op rather than a panic, so an embedder that receives a zero Evidence can always call its methods.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var e evo.Evidence
	n, err := e.Write([]byte("compiling module\n"))
	fmt.Println(n, err)
	fmt.Println(e.Empty())
}
Output:
17 <nil>
true

type EvidenceOption added in v0.3.0

type EvidenceOption = engine.EvidenceOption
Example

ExampleEvidenceOption shows the interface every Evidence construction knob (KeepLastLines, MaxEvidenceBytes, MirrorToDebug, MirrorToDiagnostics) implements. Evidence itself has no exported constructor accepting these today — the option value is real and constructible, but its effect isn't reachable from the public surface yet, so this Example proves construction rather than behavior.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	opt := evo.KeepLastLines(50)
	fmt.Println(opt != nil)
}
Output:
true

func KeepLastLines added in v0.1.2

func KeepLastLines(n int) EvidenceOption
Example

ExampleKeepLastLines sets how many trailing lines Evidence retains (default 200). See ExampleEvidenceOption for why this proves construction, not effect.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	opt := evo.KeepLastLines(50)
	fmt.Println(opt != nil)
}
Output:
true

func MaxEvidenceBytes added in v0.3.0

func MaxEvidenceBytes(n int) EvidenceOption
Example

ExampleMaxEvidenceBytes sets an approximate byte budget for Evidence's retained lines (default 256KiB). See ExampleEvidenceOption for why this proves construction, not effect.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	opt := evo.MaxEvidenceBytes(64 << 10)
	fmt.Println(opt != nil)
}
Output:
true

func MirrorToDebug added in v0.2.2

func MirrorToDebug() EvidenceOption
Example

ExampleMirrorToDebug journals each completed Evidence line via Debug when DebugLevel allows. See ExampleEvidenceOption for why this proves construction, not effect.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	opt := evo.MirrorToDebug()
	fmt.Println(opt != nil)
}
Output:
true

func MirrorToDiagnostics added in v0.2.2

func MirrorToDiagnostics() EvidenceOption
Example

ExampleMirrorToDiagnostics copies each completed Evidence line to the Diagnostics writer. See ExampleEvidenceOption for why this proves construction, not effect.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	opt := evo.MirrorToDiagnostics()
	fmt.Println(opt != nil)
}
Output:
true

type EvidencePhase added in v1.0.0

type EvidencePhase = core.EvidencePhase

EvidencePhase is one Verify observation attempt (§30): a pre- or post-Define check, and whether it was ever evaluated.

Example

ExampleEvidencePhase shows one Verify observation attempt: whether it was evaluated, and whether the desired state was already satisfied.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	phase := evo.EvidencePhase{Evaluated: true, Satisfied: true, Source: "verify"}
	fmt.Println(phase.Evaluated, phase.Satisfied, phase.Source)
}
Output:
true true verify

type EvidenceStream added in v0.3.0

type EvidenceStream = engine.EvidenceStream
Example

ExampleEvidenceStream identifies which process stream a captured line came from — EvidenceStreamCombined is the default (merged) stream.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	s := evo.EvidenceStreamStdout
	fmt.Println(s == evo.EvidenceStreamStdout)
}
Output:
true

type ExecSpec added in v1.0.0

type ExecSpec = engine.ExecSpec

ExecSpec declares one managed-state subprocess invocation (spec §8.4). Constructing an ExecSpec performs no I/O — Exec performs the operation.

Aliased into internal/engine alongside the rest of the data model.

Example

ExampleExecSpec declares one managed-state subprocess invocation — constructing it performs no I/O; passing it to Exec is what skips spawning when a prior record proves the operation current, or runs the child and verifies its declared Outputs afterward.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	spec := evo.ExecSpec{
		Executable: "python3",
		Args:       []string{"generate.py", "input.xlsx", "out.bin"},
		Basis:      []evo.Fingerprint{evo.FSPath("input.xlsx")},
		Outputs:    []string{"out.bin"},
	}
	fmt.Println(spec.Executable, len(spec.Args))
}
Output:
python3 3

type FactRecord added in v0.4.0

type FactRecord = core.Fact

FactRecord is a discovered name/value annotation — information, not work (user-13-problems.md Problem 8). Named FactRecord, not Fact, because Fact is the evo.Fact/TaskHandle.Fact verb (EffectRecord sets the naming precedent: the verb keeps the plain name, its stored shape gets Record). See TaskHandle.Fact and Output.Fact.

Aliased into internal/core alongside the rest of the data model — see Snapshot's doc comment (snapshot.go) for why.

Example

ExampleFactRecord shows a discovered name/value annotation — information, not work.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	f := evo.FactRecord{Name: "language", Value: "go"}
	fmt.Println(f.Name, f.Value)
}
Output:
language go

type Failure added in v0.3.0

type Failure struct {
	// contains filtered or unexported fields
}
Example

ExampleFailure shows the value TaskHandle.Failf/Blockf return: one recorded error built and returned in a single line, further chainable with Next/NextCommand.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Isolated: true, Stdout: io.Discard, Stderr: io.Discard, Plain: true})
	task := out.Task("clone repository")
	err := task.Failf("clone failed: %w", fmt.Errorf("connection refused"))
	_ = out.Finish()
	fmt.Println(err.Error())
}
Output:
clone failed: connection refused

func (*Failure) Error added in v0.3.0

func (f *Failure) Error() string

func (*Failure) Next added in v0.3.0

func (f *Failure) Next(actions ...Action) *Failure

func (*Failure) NextCommand added in v0.3.0

func (f *Failure) NextCommand(executable string, args ...string) *Failure

func (*Failure) Unwrap added in v0.3.0

func (f *Failure) Unwrap() error

type Field

type Field = core.Field

Field is a structured diagnostic or log field.

Example

ExampleField shows a structured diagnostic or log field.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	f := evo.Field{Key: "retries", Value: 3}
	fmt.Println(f.Key, f.Value)
}
Output:
retries 3

type FileFS added in v1.0.0

type FileFS = engine.FileFS
Example

ExampleFileFS is the facade every evo.File call performs filesystem I/O through instead of the os package directly — testkit.FileFS satisfies it deterministically for tests (including scripting a chmod failure); production uses the real filesystem.

package main

import (
	"context"
	"fmt"
	"io"
	"os"
	"path/filepath"

	evo "github.com/zachbornheimer/evident-output"
	"github.com/zachbornheimer/evident-output/testkit"
)

func main() {
	dir, err := os.MkdirTemp("", "evo-example-filefs")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer func() { _ = os.RemoveAll(dir) }()
	path := filepath.Join(dir, "config.json")

	fsys := testkit.NewFileFS()
	out := evo.Init(evo.Config{
		Isolated: true, FileFS: fsys, Plain: true, Color: evo.ColorNever,
		// StateDir isolates this example's manifest to its own temp
		// directory (spec §11.3) — without it, File's default manifest
		// path is derived from the real machine cache dir and can
		// contend with any other concurrently running evo.File caller.
		StateDir: dir,
		Stdout:   io.Discard, Stderr: io.Discard,
	})
	agent := out.Task("write config")
	agent.Define(func(ctx context.Context) error {
		return evo.File(ctx, evo.FileSpec{Path: path, Contents: []byte(`{"ok":true}`)})
	})
	_ = out.Finish()

	contents, err := os.ReadFile(path)
	fmt.Println(err == nil, string(contents))
}
Output:
true {"ok":true}

type FileSpec added in v1.0.0

type FileSpec = engine.FileSpec

FileSpec declares one managed-state file resource (spec §8). Constructing a FileSpec performs no I/O — File performs the operation.

Aliased into internal/engine alongside the rest of the data model.

Example

ExampleFileSpec declares one managed-state file resource — constructing it performs no I/O; passing it to File is what creates, rewrites on drift, or no-ops when Path/Contents/Mode already match.

package main

import (
	"fmt"
	"os"
	"path/filepath"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	dir, err := os.MkdirTemp("", "evo-example-filespec")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer func() { _ = os.RemoveAll(dir) }()

	spec := evo.FileSpec{
		Path:     filepath.Join(dir, "config.json"),
		Contents: []byte(`{"ok":true}`),
		Mode:     0o644,
	}
	fmt.Println(spec.Path != "")
}
Output:
true

type Fingerprint added in v1.0.0

type Fingerprint = fingerprint.Fingerprint

Fingerprint observes one Basis input's current content identity (spec §11.1). Implementations must not mutate the world.

Aliased into internal/fingerprint alongside FSPath/Value/App — the same pattern action.go/fact.go use for the rest of the data model.

Example

ExampleFingerprint observes one Basis input's current content identity — FSPath, Value, and App are its three constructors; a custom implementation may observe anything else Basis needs to track.

package main

import (
	"context"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	fp := evo.Value("go-version", "1.23")
	v, err := fp.Fingerprint(context.Background())
	fmt.Println(err == nil, v.Kind != "")
}
Output:
true true

func App added in v1.0.0

func App() Fingerprint

App fingerprints the running application itself — see internal/fingerprint.App. Include it in an operation's Basis only when the application's own implementation is a semantic input to that operation's result.

Example

ExampleApp fingerprints the running application itself — include it in an operation's Basis only when the application's own implementation is a semantic input to that operation's result.

package main

import (
	"context"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	fp := evo.App()
	v, err := fp.Fingerprint(context.Background())
	fmt.Println(err == nil, v.Kind != "")
}
Output:
true true

func FSPath added in v1.0.0

func FSPath(path string) Fingerprint

FSPath fingerprints the filesystem content at path: a regular file's type-marked byte digest, a directory's deterministic Merkle digest over sorted entries, a symlink's target text (never followed), or a stable "missing" digest — see internal/fingerprint.FSPath.

Example

ExampleFSPath fingerprints the filesystem content at path: a regular file's type-marked byte digest, a directory's Merkle digest over sorted entries, a symlink's target text, or a stable "missing" digest.

package main

import (
	"context"
	"fmt"
	"os"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	f, err := os.CreateTemp("", "evo-example-fspath")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer func() { _ = os.Remove(f.Name()) }()
	_ = f.Close()

	fp := evo.FSPath(f.Name())
	v, err := fp.Fingerprint(context.Background())
	fmt.Println(err == nil, v.Key == f.Name())
}
Output:
true true

func Value added in v1.0.0

func Value(name string, v any) Fingerprint

Value fingerprints a caller-supplied scalar (string, bool, any signed/ unsigned integer, any finite float, time.Time, or []byte) under a stable, safe name — see internal/fingerprint.Value. Only the digest and name are ever persisted, never the raw value.

Example

ExampleValue fingerprints a caller-supplied scalar under a stable, safe name — only the digest and name are ever persisted, never the raw value.

package main

import (
	"context"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	fp := evo.Value("feature-flag", true)
	v, err := fp.Fingerprint(context.Background())
	fmt.Println(err == nil, v.Key)
}
Output:
true feature-flag

type FingerprintValue added in v1.0.0

type FingerprintValue = fingerprint.FingerprintValue

FingerprintValue is one Fingerprint's observed identity: a stable machine Kind, a stable non-secret Key, and a SHA-256 Digest.

Example

ExampleFingerprintValue is one Fingerprint's observed identity: a stable machine Kind, a stable non-secret Key, and a SHA-256 Digest — only the digest and name are ever persisted, never the raw value.

package main

import (
	"context"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	v, err := evo.Value("go-version", "1.23").Fingerprint(context.Background())
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(v.Key)
}
Output:
go-version

type FixedClock

type FixedClock = engine.FixedClock
Example

ExampleFixedClock always returns the same instant — the deterministic clock every timestamp-sensitive test in this repo injects via evo.Clock.

package main

import (
	"fmt"
	"time"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	clock := evo.FixedClock{T: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)}
	fmt.Println(clock.Now())
}
Output:
2024-01-01 00:00:00 +0000 UTC

type Format added in v0.2.0

type Format = engine.Format
Example

ExampleFormat selects the overall stream-routing mode — zero is FormatHuman, ordinary human (and optional interactive) presentation.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	f := evo.FormatData
	fmt.Println(f == evo.FormatData)
}
Output:
true

func ParseFormat added in v1.0.0

func ParseFormat(s string) (Format, error)

ParseFormat parses "human", "data", "external", "json", or "jsonl" (case-insensitive, surrounding whitespace ignored) into a Format — the entry point a host CLI's own --format/--json flag binds to (spec §32.1). Evo does not parse os.Args itself, and never infers FormatJSON merely because Stdout is a pipe.

Example

ExampleParseFormat parses a host CLI's own --format/--json flag value — evo does not parse os.Args itself, and never infers FormatJSON merely because Stdout is a pipe.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	f, err := evo.ParseFormat("json")
	fmt.Println(err, f == evo.FormatJSON)
}
Output:
<nil> true

type GlyphProfile added in v0.3.0

type GlyphProfile = txt.GlyphProfile

GlyphProfile selects which glyph vocabulary state markers render in (evo-rec.md "Tightened glyph vocabulary", rule GLYPH-001: glyph selection via capability profile, cell-width measurement not rune counts).

The zero value, GlyphsAuto, keeps today's Unicode vocabulary off a TTY (a non-interactive stream can't show a human mojibake, so there is nothing to guard against) and on any TTY whose locale already advertises UTF-8. It downgrades to the ASCII vocabulary only on an interactive terminal without UTF-8 locale support — the one case where the status column would otherwise render as mojibake.

Aliased into internal/text (glyph tables and the rendering primitives that select from them live there — see EVIDENT_OUTPUT_ARCHITECTURE_SPEC_v0.5.md §38).

Example

ExampleGlyphProfile shows the vocabulary selector Glyphs takes: the zero value, GlyphsAuto, detects Unicode-vs-ASCII from locale and interactivity.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	profile := evo.GlyphsUnicode
	fmt.Println(profile == evo.GlyphsUnicode)
}
Output:
true

type GroupHandle added in v0.3.0

type GroupHandle struct {
	// contains filtered or unexported fields
}
Example

ExampleGroupHandle shows the collection handle Group returns: it declares its own children and reports a collection-level Snapshot.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	group := out.Group("packages")
	group.Task("curl").Done()
	_ = out.Finish()
	fmt.Println(group.Snapshot().Name)
}
Output:
packages

func Group added in v0.3.0

func Group(name string) *GroupHandle
Example

ExampleGroup declares an independent, concurrent collection of child Tasks on the default instance.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	evo.SetDefault(evo.Init(evo.Config{Stdout: &buf, Stderr: io.Discard, Plain: true}))
	install := evo.Group("install")
	install.Task("curl").Done()
	_ = evo.Default().Finish()
	fmt.Print(buf.String())
}
Output:
✓ install
   ✓ curl

func (*GroupHandle) Group added in v0.5.0

func (g *GroupHandle) Group(name string) *GroupHandle

func (*GroupHandle) Sequence added in v0.5.0

func (g *GroupHandle) Sequence(name string) *SequenceHandle

func (*GroupHandle) Snapshot added in v0.3.0

func (g *GroupHandle) Snapshot() TasksSnapshot

func (*GroupHandle) Summary added in v0.3.0

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

func (*GroupHandle) Task added in v0.3.0

func (g *GroupHandle) Task(name string) *TaskHandle

type JSONAction

type JSONAction = render.JSONAction

JSONAction is a wire-format action.

Example

ExampleJSONAction shows a wire-format recommended next step.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	a := evo.JSONAction{Label: "retry with --force"}
	fmt.Println(a.Label)
}
Output:
retry with --force

type JSONChanges

type JSONChanges = render.JSONChanges

JSONChanges is wire-format changes.

Example

ExampleJSONChanges shows wire-format changes.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	c := evo.JSONChanges{Subject: "branches", Records: []evo.JSONEffectRecord{{Verb: "deleted", Object: "stale branch"}}}
	fmt.Println(c.Subject, c.Records[0].Verb)
}
Output:
branches deleted

type JSONCollection

type JSONCollection = render.JSONCollection

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

Example

ExampleJSONCollection shows a wire-format task collection with child IDs (§25.1).

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	c := evo.JSONCollection{Name: "packages", Children: []string{"curl"}}
	fmt.Println(c.Name, c.Children)
}
Output:
packages [curl]

type JSONCommand

type JSONCommand = render.JSONCommand

JSONCommand is argv for display.

Example

ExampleJSONCommand shows argv for display on the wire.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	c := evo.JSONCommand{Executable: "git", Args: []string{"push", "--force-with-lease"}}
	fmt.Println(c.Executable, c.Args)
}
Output:
git [push --force-with-lease]

type JSONDocument

type JSONDocument = render.JSONDocument

JSONDocument is the final machine projection (§25.1).

Aliased into internal/render alongside the JSON encoding machinery that produces it — see EVIDENT_OUTPUT_ARCHITECTURE_SPEC_v0.5.md §38.

Example

ExampleJSONDocument shows the final machine projection's top-level shape.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	doc := evo.JSONDocument{SchemaVersion: evo.JSONSchemaVersion}
	fmt.Println(doc.SchemaVersion)
}
Output:
0.4

type JSONEffectRecord

type JSONEffectRecord = render.JSONEffectRecord

JSONEffectRecord is a change/plan row.

Example

ExampleJSONEffectRecord shows a change/plan row on the wire.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	q := int64(2)
	r := evo.JSONEffectRecord{Verb: "deleted", Quantity: &q, Object: "stale branch"}
	fmt.Println(r.Verb, *r.Quantity, r.Object)
}
Output:
deleted 2 stale branch

type JSONMessage added in v0.2.0

type JSONMessage = render.JSONMessage

JSONMessage is a wire-format user-facing message.

Example

ExampleJSONMessage shows a wire-format user-facing message.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	m := evo.JSONMessage{Visibility: "normal", Text: "reading configuration"}
	fmt.Println(m.Visibility, m.Text)
}
Output:
normal reading configuration

type JSONOutputMeta

type JSONOutputMeta = render.JSONOutputMeta

JSONOutputMeta identifies the output instance.

Example

ExampleJSONOutputMeta identifies the output instance on the wire.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	meta := evo.JSONOutputMeta{Subject: "repo-retire"}
	fmt.Println(meta.Subject)
}
Output:
repo-retire

type JSONPlan

type JSONPlan = render.JSONPlan

JSONPlan is wire-format plan.

Example

ExampleJSONPlan shows wire-format plan.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	p := evo.JSONPlan{Subject: "branches", Records: []evo.JSONEffectRecord{{Verb: "delete", Object: "stale branch"}}}
	fmt.Println(p.Subject, p.Records[0].Verb)
}
Output:
branches delete

type JSONProblem

type JSONProblem = render.JSONProblem

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

Example

ExampleJSONProblem shows a wire-format problem (no raw Cause by default).

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	p := evo.JSONProblem{Summary: "schema mismatch", Code: "E_SCHEMA"}
	fmt.Println(p.Summary, p.Code)
}
Output:
schema mismatch E_SCHEMA

type JSONProgress

type JSONProgress = render.JSONProgress

JSONProgress is wire-format progress.

Example

ExampleJSONProgress shows wire-format progress.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	p := evo.JSONProgress{Kind: evo.Determinate, Completed: 50, Total: 100}
	fmt.Println(p.Kind, p.Completed, p.Total)
}
Output:
determinate 50 100

type JSONTask

type JSONTask = render.JSONTask

JSONTask is a wire-format task.

Example

ExampleJSONTask shows a wire-format task.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	t := evo.JSONTask{Name: "apply patch", State: evo.Done}
	fmt.Println(t.Name, t.State)
}
Output:
apply patch done

type LiveSurface

type LiveSurface = engine.LiveSurface
Example

ExampleLiveSurface shows the interactive terminal surface a live-region renderer paints onto — a superset of TerminalDriver.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var surface evo.LiveSurface = fakeLiveSurface{}
	fmt.Println(surface.ID(), surface.IsInteractive())
}

// fakeLiveSurface is a minimal evo.LiveSurface for ExampleLiveSurface — real
// callers pass a concrete driver (e.g. from internal/terminal).
type fakeLiveSurface struct{}

func (fakeLiveSurface) ID() string          { return "fake" }
func (fakeLiveSurface) Columns() int        { return 80 }
func (fakeLiveSurface) Rows() int           { return 24 }
func (fakeLiveSurface) IsInteractive() bool { return false }
func (fakeLiveSurface) WriteLive(string)    {}
func (fakeLiveSurface) ClearLive()          {}
func (fakeLiveSurface) WriteDurable(string) {}
func (fakeLiveSurface) WriteFinal(string)   {}
Output:
fake false

type LogLevel

type LogLevel = engine.LogLevel
Example

ExampleLogLevel shows the Debug journal threshold — its own type, distinct from slog.Level (SlogHandler translates between the two internally).

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	level := evo.LevelDebug
	fmt.Println(level == evo.LevelDebug)
}
Output:
true

type LogRecord added in v0.2.4

type LogRecord = engine.LogRecord
Example

ExampleLogRecord shows the shape journaled to Debug/Capture mirrors and the slog bridge: a time, level, message, and structured attrs.

package main

import (
	"fmt"
	"log/slog"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	rec := evo.LogRecord{Message: "starting up", Level: slog.LevelInfo}
	fmt.Println(rec.Message, rec.Level)
}
Output:
starting up INFO

type MessageSnapshot added in v0.2.0

type MessageSnapshot = core.MessageSnapshot

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

Example

ExampleMessageSnapshot shows one logical user-facing message in the canonical model, read from a finished Snapshot.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	evo.SetDefault(out)
	evo.Println("reading configuration")
	_ = out.Finish()
	msg := out.Snapshot().Messages[0]
	fmt.Println(msg.Text, msg.Visibility == evo.VisibilityNormal)
}
Output:
reading configuration true

type MutationOption added in v0.5.0

type MutationOption = engine.MutationOption
Example

ExampleMutationOption shows the interface Affected implements, configuring how many objects one atomic mutation touches.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	opt := evo.Affected(3)
	fmt.Println(opt != nil)
}
Output:
true

func Affected added in v0.4.0

func Affected(n int) MutationOption
Example

ExampleAffected sets how many objects one atomic mutation touches — omit it for a Task that affects a single item.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	task := out.Task("prune branches")
	task.Delete("stale branches", func() error { return nil }, evo.Affected(5))
	_ = task.Wait()
	_ = out.Finish()
	fmt.Println(task.Snapshot().State)
}
Output:
done

type NoopRedactor

type NoopRedactor = engine.NoopRedactor
Example

ExampleNoopRedactor leaves strings unchanged — the default Redactor.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var r evo.NoopRedactor
	fmt.Println(r.RedactString("token=abc123"))
}
Output:
token=abc123

type Option

type Option = engine.Option
Example

ExampleOption shows the functional-option interface every Config knob below (AlsoWrite, Plain, Width, ...) implements.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	opt := evo.NoColor()
	fmt.Println(opt != nil)
}
Output:
true

func AlsoWrite

func AlsoWrite(w io.Writer) Option
Example

ExampleAlsoWrite mirrors every written byte to an additional writer — useful for tee-ing human output to a log file alongside the terminal.

package main

import (
	"bytes"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

// runOption builds an isolated Output from the raw-Option escape hatch
// (Config.Options), declares one Task, Finishes, and returns the rendered
// plain-text bytes — the shared shape every Option Example below uses to
// prove its option compiles and participates in a real run.
func runOption(opts ...evo.Option) string {
	var buf bytes.Buffer
	all := append([]evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor()}, opts...)
	out := evo.Init(evo.Config{Isolated: true, Options: all})
	out.Task("demo").Done()
	_ = out.Finish()
	return buf.String()
}

func main() {
	var mirror bytes.Buffer
	fmt.Print(runOption(evo.AlsoWrite(&mirror)))
	fmt.Println(mirror.Len() > 0)
}
Output:
✓ demo
true

func Clock

func Clock(ts TimeSource) Option
Example

ExampleClock injects a deterministic TimeSource in place of the real wall clock — the seam every timestamp-sensitive test in this repo uses.

package main

import (
	"bytes"
	"fmt"
	"time"

	evo "github.com/zachbornheimer/evident-output"
)

// runOption builds an isolated Output from the raw-Option escape hatch
// (Config.Options), declares one Task, Finishes, and returns the rendered
// plain-text bytes — the shared shape every Option Example below uses to
// prove its option compiles and participates in a real run.
func runOption(opts ...evo.Option) string {
	var buf bytes.Buffer
	all := append([]evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor()}, opts...)
	out := evo.Init(evo.Config{Isolated: true, Options: all})
	out.Task("demo").Done()
	_ = out.Finish()
	return buf.String()
}

func main() {
	fixed := evo.FixedClock{T: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)}
	fmt.Print(runOption(evo.Clock(fixed)))
}
Output:
✓ demo

func DataProjection

func DataProjection() Option
Example

ExampleDataProjection reserves Stdout for the application's domain payload; human presentation moves to Stderr.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{
		Isolated: true, Plain: true, Stdout: io.Discard, Stderr: &buf, Options: []evo.Option{evo.DataProjection()},
	})
	out.Task("demo").Done()
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✓ demo

func DebugAddSource added in v0.3.0

func DebugAddSource() Option
Example

ExampleDebugAddSource resolves each debug record's call site to a source=file.go:line field on human/pane/history rendering.

package main

import (
	"bytes"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

// runOption builds an isolated Output from the raw-Option escape hatch
// (Config.Options), declares one Task, Finishes, and returns the rendered
// plain-text bytes — the shared shape every Option Example below uses to
// prove its option compiles and participates in a real run.
func runOption(opts ...evo.Option) string {
	var buf bytes.Buffer
	all := append([]evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor()}, opts...)
	out := evo.Init(evo.Config{Isolated: true, Options: all})
	out.Task("demo").Done()
	_ = out.Finish()
	return buf.String()
}

func main() {
	fmt.Print(runOption(evo.DebugAddSource()))
}
Output:
✓ demo

func DebugHistory

func DebugHistory() Option
Example

ExampleDebugHistory selects durable scrollback (the default) for the debug journal — appended above the live region instead of a bounded pane.

package main

import (
	"bytes"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

// runOption builds an isolated Output from the raw-Option escape hatch
// (Config.Options), declares one Task, Finishes, and returns the rendered
// plain-text bytes — the shared shape every Option Example below uses to
// prove its option compiles and participates in a real run.
func runOption(opts ...evo.Option) string {
	var buf bytes.Buffer
	all := append([]evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor()}, opts...)
	out := evo.Init(evo.Config{Isolated: true, Options: all})
	out.Task("demo").Done()
	_ = out.Finish()
	return buf.String()
}

func main() {
	fmt.Print(runOption(evo.DebugHistory()))
}
Output:
✓ demo

func DebugLevel

func DebugLevel(level LogLevel) Option
Example

ExampleDebugLevel sets the minimum debug journal level, surfacing Debug/Capture mirrors when set to LevelTrace or LevelDebug.

package main

import (
	"bytes"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

// runOption builds an isolated Output from the raw-Option escape hatch
// (Config.Options), declares one Task, Finishes, and returns the rendered
// plain-text bytes — the shared shape every Option Example below uses to
// prove its option compiles and participates in a real run.
func runOption(opts ...evo.Option) string {
	var buf bytes.Buffer
	all := append([]evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor()}, opts...)
	out := evo.Init(evo.Config{Isolated: true, Options: all})
	out.Task("demo").Done()
	_ = out.Finish()
	return buf.String()
}

func main() {
	fmt.Print(runOption(evo.DebugLevel(evo.LevelDebug)))
}
Output:
✓ demo

func DebugPane

func DebugPane(opts ...DebugPaneOption) Option
Example

ExampleDebugPane selects a bounded rolling viewport for the debug journal instead of durable scrollback.

package main

import (
	"bytes"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

// runOption builds an isolated Output from the raw-Option escape hatch
// (Config.Options), declares one Task, Finishes, and returns the rendered
// plain-text bytes — the shared shape every Option Example below uses to
// prove its option compiles and participates in a real run.
func runOption(opts ...evo.Option) string {
	var buf bytes.Buffer
	all := append([]evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor()}, opts...)
	out := evo.Init(evo.Config{Isolated: true, Options: all})
	out.Task("demo").Done()
	_ = out.Finish()
	return buf.String()
}

func main() {
	fmt.Print(runOption(evo.DebugPane(evo.PaneHeight(3))))
}
Output:
✓ demo

func Diagnostics

func Diagnostics(w io.Writer) Option
Example

ExampleDiagnostics routes diagnostics (the debug journal's default destination) to an explicit writer.

package main

import (
	"bytes"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

// runOption builds an isolated Output from the raw-Option escape hatch
// (Config.Options), declares one Task, Finishes, and returns the rendered
// plain-text bytes — the shared shape every Option Example below uses to
// prove its option compiles and participates in a real run.
func runOption(opts ...evo.Option) string {
	var buf bytes.Buffer
	all := append([]evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor()}, opts...)
	out := evo.Init(evo.Config{Isolated: true, Options: all})
	out.Task("demo").Done()
	_ = out.Finish()
	return buf.String()
}

func main() {
	var diag bytes.Buffer
	fmt.Print(runOption(evo.Diagnostics(&diag)))
}
Output:
✓ demo

func DryRun added in v0.3.0

func DryRun() Option
Example

ExampleDryRun declares the run a dry run: mutation verbs render as [planned] rows with the imperative verb instead of [changed] rows.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{Isolated: true, Plain: true, Stdout: &buf, Stderr: io.Discard, DryRun: true})
	out.Task("prune branches").Delete("stale branch", func() error { return nil }, evo.Affected(3))
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
[dry-run] no changes will be made

✓ prune branches

[planned] prune branches  delete 3 stale branches

[planned]

func ExternalProjection

func ExternalProjection() Option
Example

ExampleExternalProjection disables inline rendering entirely — only snapshots are available, for an embedder that owns its own presentation.

package main

import (
	"bytes"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

// runOption builds an isolated Output from the raw-Option escape hatch
// (Config.Options), declares one Task, Finishes, and returns the rendered
// plain-text bytes — the shared shape every Option Example below uses to
// prove its option compiles and participates in a real run.
func runOption(opts ...evo.Option) string {
	var buf bytes.Buffer
	all := append([]evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor()}, opts...)
	out := evo.Init(evo.Config{Isolated: true, Options: all})
	out.Task("demo").Done()
	_ = out.Finish()
	return buf.String()
}

func main() {
	fmt.Print(runOption(evo.ExternalProjection()))
}
Output:
✓ demo

func Glyphs added in v0.3.0

func Glyphs(p GlyphProfile) Option

Glyphs selects the glyph capability profile (default GlyphsAuto).

Example

ExampleGlyphs selects the state-glyph vocabulary — GlyphsASCII forces the ASCII vocabulary regardless of locale.

package main

import (
	"bytes"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

// runOption builds an isolated Output from the raw-Option escape hatch
// (Config.Options), declares one Task, Finishes, and returns the rendered
// plain-text bytes — the shared shape every Option Example below uses to
// prove its option compiles and participates in a real run.
func runOption(opts ...evo.Option) string {
	var buf bytes.Buffer
	all := append([]evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor()}, opts...)
	out := evo.Init(evo.Config{Isolated: true, Options: all})
	out.Task("demo").Done()
	_ = out.Finish()
	return buf.String()
}

func main() {
	fmt.Print(runOption(evo.Glyphs(evo.GlyphsASCII)))
}
Output:
[ok] demo

func MaxEntities

func MaxEntities(n int) Option
Example

ExampleMaxEntities caps how many entities the debug journal / history retains before it starts dropping the oldest.

package main

import (
	"bytes"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

// runOption builds an isolated Output from the raw-Option escape hatch
// (Config.Options), declares one Task, Finishes, and returns the rendered
// plain-text bytes — the shared shape every Option Example below uses to
// prove its option compiles and participates in a real run.
func runOption(opts ...evo.Option) string {
	var buf bytes.Buffer
	all := append([]evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor()}, opts...)
	out := evo.Init(evo.Config{Isolated: true, Options: all})
	out.Task("demo").Done()
	_ = out.Finish()
	return buf.String()
}

func main() {
	fmt.Print(runOption(evo.MaxEntities(64)))
}
Output:
✓ demo

func MaxEvents

func MaxEvents(n int) Option
Example

ExampleMaxEvents caps how many durable events the journal retains.

package main

import (
	"bytes"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

// runOption builds an isolated Output from the raw-Option escape hatch
// (Config.Options), declares one Task, Finishes, and returns the rendered
// plain-text bytes — the shared shape every Option Example below uses to
// prove its option compiles and participates in a real run.
func runOption(opts ...evo.Option) string {
	var buf bytes.Buffer
	all := append([]evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor()}, opts...)
	out := evo.Init(evo.Config{Isolated: true, Options: all})
	out.Task("demo").Done()
	_ = out.Finish()
	return buf.String()
}

func main() {
	fmt.Print(runOption(evo.MaxEvents(64)))
}
Output:
✓ demo

func MaxFrameRate

func MaxFrameRate(framesPerSecond int) Option
Example

ExampleMaxFrameRate caps how often the live region repaints per second.

package main

import (
	"bytes"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

// runOption builds an isolated Output from the raw-Option escape hatch
// (Config.Options), declares one Task, Finishes, and returns the rendered
// plain-text bytes — the shared shape every Option Example below uses to
// prove its option compiles and participates in a real run.
func runOption(opts ...evo.Option) string {
	var buf bytes.Buffer
	all := append([]evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor()}, opts...)
	out := evo.Init(evo.Config{Isolated: true, Options: all})
	out.Task("demo").Done()
	_ = out.Finish()
	return buf.String()
}

func main() {
	fmt.Print(runOption(evo.MaxFrameRate(30)))
}
Output:
✓ demo

func NoColor

func NoColor() Option
Example

ExampleNoColor disables semantic color regardless of TTY/NO_COLOR detection.

package main

import (
	"bytes"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

// runOption builds an isolated Output from the raw-Option escape hatch
// (Config.Options), declares one Task, Finishes, and returns the rendered
// plain-text bytes — the shared shape every Option Example below uses to
// prove its option compiles and participates in a real run.
func runOption(opts ...evo.Option) string {
	var buf bytes.Buffer
	all := append([]evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor()}, opts...)
	out := evo.Init(evo.Config{Isolated: true, Options: all})
	out.Task("demo").Done()
	_ = out.Finish()
	return buf.String()
}

func main() {
	fmt.Print(runOption())
}
Output:
✓ demo

func Plain

func Plain() Option
Example

ExamplePlain disables live interactive frames, on a TTY or off — the durable report every non-interactive CI log needs.

package main

import (
	"bytes"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

// runOption builds an isolated Output from the raw-Option escape hatch
// (Config.Options), declares one Task, Finishes, and returns the rendered
// plain-text bytes — the shared shape every Option Example below uses to
// prove its option compiles and participates in a real run.
func runOption(opts ...evo.Option) string {
	var buf bytes.Buffer
	all := append([]evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor()}, opts...)
	out := evo.Init(evo.Config{Isolated: true, Options: all})
	out.Task("demo").Done()
	_ = out.Finish()
	return buf.String()
}

func main() {
	fmt.Print(runOption())
}
Output:
✓ demo

func Redact

func Redact(r Redactor) Option
Example

ExampleRedact injects a Redactor that scrubs sensitive values before journal, Capture retention, and human rendering.

package main

import (
	"bytes"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

// runOption builds an isolated Output from the raw-Option escape hatch
// (Config.Options), declares one Task, Finishes, and returns the rendered
// plain-text bytes — the shared shape every Option Example below uses to
// prove its option compiles and participates in a real run.
func runOption(opts ...evo.Option) string {
	var buf bytes.Buffer
	all := append([]evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor()}, opts...)
	out := evo.Init(evo.Config{Isolated: true, Options: all})
	out.Task("demo").Done()
	_ = out.Finish()
	return buf.String()
}

func main() {
	fmt.Print(runOption(evo.Redact(evo.NoopRedactor{})))
}
Output:
✓ demo

func ResultStream added in v0.2.3

func ResultStream(w io.Writer) Option
Example

ExampleResultStream routes the domain-payload writer FormatData's ResultWriter falls back to when Config.Result is unset.

package main

import (
	"bytes"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

// runOption builds an isolated Output from the raw-Option escape hatch
// (Config.Options), declares one Task, Finishes, and returns the rendered
// plain-text bytes — the shared shape every Option Example below uses to
// prove its option compiles and participates in a real run.
func runOption(opts ...evo.Option) string {
	var buf bytes.Buffer
	all := append([]evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor()}, opts...)
	out := evo.Init(evo.Config{Isolated: true, Options: all})
	out.Task("demo").Done()
	_ = out.Finish()
	return buf.String()
}

func main() {
	var result bytes.Buffer
	fmt.Print(runOption(evo.ResultStream(&result)))
}
Output:
✓ demo

func Runner added in v1.0.0

func Runner(r ProcessRunner) Option
Example

ExampleRunner installs a ProcessRunner other than the real spawner — the seam every evo.Exec test in this repo uses to replace the OS process with a deterministic testkit fake.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
	"github.com/zachbornheimer/evident-output/testkit"
)

func main() {
	runner := testkit.NewProcessRunner()
	runner.Script("/usr/bin/tool", testkit.ScriptedProcess{ExitCode: 0})

	var buf bytes.Buffer
	out := evo.Init(evo.Config{
		Isolated: true, Stdout: &buf, Stderr: io.Discard, Plain: true,
		Options: []evo.Option{evo.Runner(runner)},
	})
	out.Task("demo").Done()
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✓ demo

func Stdin added in v0.3.0

func Stdin(r io.Reader) Option
Example

ExampleStdin sets the facade Confirm reads one answer line from — Plain mode never reads stdin (it blocks on policy instead), so this Example leaves live rendering enabled and only points Stdin at a canned answer.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	answer := bytes.NewBufferString("y\n")
	out := evo.Init(evo.Config{
		Isolated: true, Stdout: io.Discard, Stderr: io.Discard,
		Options: []evo.Option{evo.To(io.Discard), evo.Stdin(answer)},
	})
	ok := out.Confirm("continue?")
	fmt.Println(ok)
}
Output:
true

func Strict

func Strict() Option
Example

ExampleStrict makes every recorded misuse panic instead of only counting it — a debug-build safety net for library-authoring call sites.

package main

import (
	"bytes"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

// runOption builds an isolated Output from the raw-Option escape hatch
// (Config.Options), declares one Task, Finishes, and returns the rendered
// plain-text bytes — the shared shape every Option Example below uses to
// prove its option compiles and participates in a real run.
func runOption(opts ...evo.Option) string {
	var buf bytes.Buffer
	all := append([]evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor()}, opts...)
	out := evo.Init(evo.Config{Isolated: true, Options: all})
	out.Task("demo").Done()
	_ = out.Finish()
	return buf.String()
}

func main() {
	fmt.Print(runOption(evo.Strict()))
}
Output:
✓ demo

func Terminal

func Terminal(driver TerminalDriver) Option
Example

ExampleTerminal injects a custom TerminalDriver for identity/sink detection instead of evident-output's own terminal probing.

package main

import (
	"bytes"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

// runOption builds an isolated Output from the raw-Option escape hatch
// (Config.Options), declares one Task, Finishes, and returns the rendered
// plain-text bytes — the shared shape every Option Example below uses to
// prove its option compiles and participates in a real run.
func runOption(opts ...evo.Option) string {
	var buf bytes.Buffer
	all := append([]evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor()}, opts...)
	out := evo.Init(evo.Config{Isolated: true, Options: all})
	out.Task("demo").Done()
	_ = out.Finish()
	return buf.String()
}

func main() {
	fmt.Print(runOption(evo.Terminal(namedTerminal{"custom"})))
}

// namedTerminal is a minimal evo.TerminalDriver for ExampleTerminal — real
// callers pass a concrete driver (e.g. from internal/terminal); this
// package's Example only needs one that satisfies the interface.
type namedTerminal struct{ id string }

func (t namedTerminal) ID() string { return t.id }
Output:
✓ demo

func Title added in v0.2.7

func Title(subject string) Option
Example

ExampleTitle sets the subject shown in the conclusion band.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{Isolated: true, Plain: true, Stdout: &buf, Stderr: io.Discard, Title: "repo-retire"})
	out.Task("scan").Done()
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✓ scan

[ready]  repo-retire

func To

func To(w io.Writer) Option
Example

ExampleTo routes the ordinary human stream to an explicit writer.

package main

import (
	"bytes"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

// runOption builds an isolated Output from the raw-Option escape hatch
// (Config.Options), declares one Task, Finishes, and returns the rendered
// plain-text bytes — the shared shape every Option Example below uses to
// prove its option compiles and participates in a real run.
func runOption(opts ...evo.Option) string {
	var buf bytes.Buffer
	all := append([]evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor()}, opts...)
	out := evo.Init(evo.Config{Isolated: true, Options: all})
	out.Task("demo").Done()
	_ = out.Finish()
	return buf.String()
}

func main() {
	fmt.Print(runOption())
}
Output:
✓ demo

func VisibilityDelay

func VisibilityDelay(delay time.Duration) Option
Example

ExampleVisibilityDelay sets the wait before the first live paint — use evo.Delay(d) to build the *time.Duration value from a literal.

package main

import (
	"bytes"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

// runOption builds an isolated Output from the raw-Option escape hatch
// (Config.Options), declares one Task, Finishes, and returns the rendered
// plain-text bytes — the shared shape every Option Example below uses to
// prove its option compiles and participates in a real run.
func runOption(opts ...evo.Option) string {
	var buf bytes.Buffer
	all := append([]evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor()}, opts...)
	out := evo.Init(evo.Config{Isolated: true, Options: all})
	out.Task("demo").Done()
	_ = out.Finish()
	return buf.String()
}

func main() {
	fmt.Print(runOption(evo.VisibilityDelay(0)))
}
Output:
✓ demo

func Width

func Width(columns int) Option
Example

ExampleWidth sets a fixed render width instead of detecting the terminal's own column count.

package main

import (
	"bytes"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

// runOption builds an isolated Output from the raw-Option escape hatch
// (Config.Options), declares one Task, Finishes, and returns the rendered
// plain-text bytes — the shared shape every Option Example below uses to
// prove its option compiles and participates in a real run.
func runOption(opts ...evo.Option) string {
	var buf bytes.Buffer
	all := append([]evo.Option{evo.To(&buf), evo.Plain(), evo.NoColor()}, opts...)
	out := evo.Init(evo.Config{Isolated: true, Options: all})
	out.Task("demo").Done()
	_ = out.Finish()
	return buf.String()
}

func main() {
	fmt.Print(runOption(evo.Width(80)))
}
Output:
✓ demo

type Output

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

Output, TaskHandle, and the other presentation handles are wrappers, not aliases: engine test helpers must not appear in go doc or the rec surface.

Example

ExampleOutput shows the hosted-instance shape: build an isolated Output, declare a Task on it directly, and Finish it — never touching the package-level default.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{Stdout: &buf, Stderr: io.Discard, Plain: true, Isolated: true})
	out.Task("build").Done()
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✓ build

func Default added in v0.3.0

func Default() *Output

Default returns the package-level default Output, lazily creating one with a zero Config the first time it's needed.

Example

ExampleDefault shows the package-level default instance, lazily created with a zero Config.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	evo.SetDefault(nil)
	out := evo.Default()
	fmt.Println(out != nil)
}
Output:
true

func Init added in v0.3.0

func Init(configs ...Config) *Output

Init is the sole Output constructor. It builds an Output from cfg, installs it as the package-level default, and arms first paint — call once, in main, before any I/O.

Example

ExampleInit shows the sole Output constructor: build one, declare a task, and Finish it.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{Stdout: &buf, Stderr: io.Discard, Plain: true, Isolated: true})
	out.Task("read config").Done()
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✓ read config

func (*Output) Cancel

func (o *Output) Cancel(reason string)

func (*Output) Close

func (o *Output) Close() error

func (*Output) Conclusion

func (o *Output) Conclusion() Conclusion

func (*Output) Confirm added in v0.3.0

func (o *Output) Confirm(question string, opts ...ConfirmOption) bool

func (*Output) Context added in v0.5.0

func (o *Output) Context() context.Context

func (*Output) Err

func (o *Output) Err() error

func (*Output) Fact added in v0.4.0

func (o *Output) Fact(name, value string)

func (*Output) Fail

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

func (*Output) Failf added in v0.3.0

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

func (*Output) Finish

func (o *Output) Finish() error

func (*Output) Group added in v0.3.0

func (o *Output) Group(name string) *GroupHandle

func (*Output) Next

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

func (*Output) NextCommand

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

func (*Output) Print added in v0.2.0

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

func (*Output) Printf added in v0.2.0

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

func (*Output) Println added in v0.2.0

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

func (*Output) ResultWriter added in v0.2.3

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

func (*Output) Run added in v0.3.0

func (o *Output) Run(ctx context.Context, run RunFunc) Result

Run executes run against o and returns the Result (Conclusion plus the application error, if any); it never exits the process.

func (*Output) Sequence added in v0.4.0

func (o *Output) Sequence(name string) *SequenceHandle

func (*Output) Snapshot

func (o *Output) Snapshot() Snapshot

func (*Output) Suspend

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

func (*Output) Task

func (o *Output) Task(name string) *TaskHandle

func (*Output) Warn added in v0.4.0

func (o *Output) Warn(summary string)

func (*Output) Writer added in v0.2.0

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

type PlainOptions

type PlainOptions = engine.PlainOptions
Example

ExamplePlainOptions configures RenderPlain's durable-report rendering.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	opts := evo.PlainOptions{Width: 80, NoColor: true}
	fmt.Println(opts.Width, opts.NoColor)
}
Output:
80 true

type PlanSnapshot

type PlanSnapshot = core.PlanSnapshot

PlanSnapshot is an immutable plan section.

Example

ExamplePlanSnapshot reads an immutable plan section: the records a mutation verb recorded under DryRun.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true, DryRun: true})
	out.Task("prune branches").Delete("stale branch", func() error { return nil }, evo.Affected(2))
	_ = out.Finish()
	plan := out.Snapshot().Plans[0]
	fmt.Println(plan.Records[0].Verb, plan.Records[0].Quantity)
}
Output:
delete 2

type Printer added in v0.2.0

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

ExamplePrinter shows the Printer handle's own Print/Printf/Println verbs — evo.Verbose() is the only constructor that returns one.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	evo.SetDefault(evo.Init(evo.Config{
		Stdout: &buf, Stderr: io.Discard, Plain: true, Verbosity: evo.VerbosityVerbose,
	}))
	printer := evo.Verbose()
	printer.Print("cache ")
	printer.Printf("hit for %s", "module x")
	printer.Println()
	_ = evo.Default().Finish()
	fmt.Print(buf.String())
}
Output:
cache hit for module x

func Verbose added in v0.2.0

func Verbose() *Printer

Verbose returns a Printer scoped to Verbose visibility on the default instance.

Example

ExampleVerbose shows a Printer scoped to Verbose visibility: it only projects when Config.Verbosity is VerbosityVerbose.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	evo.SetDefault(evo.Init(evo.Config{
		Stdout: &buf, Stderr: io.Discard, Plain: true, Verbosity: evo.VerbosityVerbose,
	}))
	evo.Verbose().Println("cache hit for module x")
	_ = evo.Default().Finish()
	fmt.Print(buf.String())
}
Output:
cache hit for module x

func (*Printer) Print added in v0.2.0

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

func (*Printer) Printf added in v0.2.0

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

func (*Printer) Println added in v0.2.0

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

func (*Printer) Writer added in v0.2.0

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

type Problem

type Problem = core.Problem

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

Aliased into internal/core alongside the rest of the data model — see Snapshot's doc comment (snapshot.go) for why.

Example

ExampleProblem shows the structured evidence shape explaining a negative task outcome — the payload Fail/Block/Warn build from ProblemOptions.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	p := evo.Problem{Summary: "schema mismatch", Code: "E_SCHEMA"}
	fmt.Println(p.Summary, p.Code)
}
Output:
schema mismatch E_SCHEMA

type ProblemOption

type ProblemOption = engine.ProblemOption

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

Example

ExampleProblemOption shows the interface every Problem-configuring constructor (Detail, Code, On, Count, Location, Next, NextCommand) implements.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	opt := evo.Detail("the file was not found")
	fmt.Println(opt != nil)
}
Output:
true

func Code

func Code(value string) ProblemOption

Code sets a stable problem code.

Example

ExampleCode sets a stable, machine-readable Problem code a consumer can match on instead of parsing Summary text.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{Isolated: true, Plain: true, Stdout: &buf, Stderr: io.Discard})
	out.Task("apply migration").Fail("schema mismatch", evo.Code("E_SCHEMA"))
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✗ apply migration  schema mismatch

func Count

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

Count sets a quantity and optional unit.

Example

ExampleCount sets a quantity and optional unit on a Problem.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{Isolated: true, Plain: true, Stdout: &buf, Stderr: io.Discard})
	out.Task("upload artifacts").Fail("upload failed", evo.Count(3, "files"))
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✗ upload artifacts  upload failed

func Detail

func Detail(text string) ProblemOption

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

Example

ExampleDetail sets user-visible detail text on a Problem raised via TaskHandle.Fail.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{Isolated: true, Plain: true, Stdout: &buf, Stderr: io.Discard})
	out.Task("read config").Fail("parse error", evo.Detail("unexpected token at line 4"))
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✗ read config  parse error
   └─ unexpected token at line 4

func Location

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

Location sets a source location on a Problem (renamed from At — C5: a free-function At collided in name, though not in call syntax, with Output.At(visibility), confusing autocomplete and readers alike).

Example

ExampleLocation sets a source location on a Problem.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{Isolated: true, Plain: true, Stdout: &buf, Stderr: io.Discard})
	out.Task("validate manifest").Fail("unknown field", evo.Location("manifest.yaml", 4, 1))
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✗ validate manifest  unknown field

func Next

func Next(action Action) ProblemOption

Next attaches actions to a problem.

Example

ExampleNext attaches a recommended next step to a Problem.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{Isolated: true, Plain: true, Stdout: &buf, Stderr: io.Discard})
	out.Task("push branch").Fail("rejected: non-fast-forward", evo.Next(evo.Label("pull --rebase first")))
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✗ push branch  rejected: non-fast-forward

func NextCommand

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

NextCommand attaches a recommended command action.

Example

ExampleNextCommand attaches a recommended command action to a Problem.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{Isolated: true, Plain: true, Stdout: &buf, Stderr: io.Discard})
	out.Task("push branch").Fail("rejected: non-fast-forward", evo.NextCommand("git", "pull", "--rebase"))
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✗ push branch  rejected: non-fast-forward

func On

func On(subject string) ProblemOption

On sets the problem subject.

Example

ExampleOn sets the problem subject.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{Isolated: true, Plain: true, Stdout: &buf, Stderr: io.Discard})
	out.Task("clean workspace").Fail("permission denied", evo.On("/var/cache"))
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✗ clean workspace  permission denied
   ├─ /var/cache  permission denied

type ProcessCommand added in v1.0.0

type ProcessCommand = engine.ProcessCommand
Example

ExampleProcessCommand is the resolved shape evo.Exec passes to a ProcessRunner — Path already resolved on PATH, Args exactly as declared, Stdout/Stderr wired to the Task's own capture.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	cmd := evo.ProcessCommand{
		Path:   "/usr/bin/python3",
		Args:   []string{"generate.py"},
		Stdout: io.Discard,
		Stderr: io.Discard,
	}
	fmt.Println(cmd.Path, len(cmd.Args))
}
Output:
/usr/bin/python3 1

type ProcessOutcome added in v1.0.0

type ProcessOutcome = engine.ProcessOutcome
Example

ExampleProcessOutcome is one spawned command's terminal, already-observed result — a nonzero ExitCode is not itself an error; evo.Exec decides what a nonzero exit means.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	outcome := evo.ProcessOutcome{ExitCode: 0}
	fmt.Println(outcome.ExitCode == 0)
}
Output:
true

type ProcessRunner added in v1.0.0

type ProcessRunner = engine.ProcessRunner
Example

ExampleProcessRunner is the facade every evo.Exec spawn goes through instead of exec.Cmd/os/exec directly — testkit.ProcessRunner satisfies it deterministically for tests; production uses the real spawner.

package main

import (
	"context"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
	"github.com/zachbornheimer/evident-output/testkit"
)

func main() {
	runner := testkit.NewProcessRunner()
	runner.Script("/usr/bin/tool", testkit.ScriptedProcess{ExitCode: 0})

	outcome, err := runner.Run(context.Background(), evo.ProcessCommand{Path: "/usr/bin/tool"})
	fmt.Println(err == nil, outcome.ExitCode)
}
Output:
true 0

type Progress

type Progress = core.Progress

Progress is absolute measurement for a task.

Example

ExampleProgress shows the absolute measurement TaskHandle.Progress records, read back from the resolved TaskSnapshot.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	task := out.Task("download image")
	task.Progress(50, 100)
	task.Done()
	_ = out.Finish()
	p := task.Snapshot().Progress
	fmt.Println(p.Completed, p.Total)
}
Output:
50 100

type ProgressKind

type ProgressKind = core.ProgressKind

ProgressKind classifies task measurement.

Example

ExampleProgressKind classifies which measurement a task's Progress reports.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	kind := evo.Determinate
	fmt.Println(kind == evo.Determinate)
}
Output:
true

type Projection added in v0.5.0

type Projection = engine.Projection
Example

ExampleProjection selects presentation encoding independent of Format — human, plain, json, jsonl, or stream-json.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	p := evo.ProjectionPlain
	fmt.Println(p == evo.ProjectionPlain)
}
Output:
true

type ReasonOption added in v0.3.0

type ReasonOption = engine.ReasonOption
Example

ExampleReasonOption shows the interface every Reason constraint (ForSkip, OnTask) implements.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	opt := evo.ForSkip()
	fmt.Println(opt != nil)
}
Output:
true

func ForSkip added in v0.3.0

func ForSkip() ReasonOption
Example

ExampleForSkip shows constructing the ReasonOption that restricts a taxonomy Reason to TaskHandle.Skipped (recording it via Kept is misuse). evo.Reason itself takes no options today — this constrained-reason form is reachable only through the internal reasonGetOrCreate a future advanced entrypoint would expose; the option value is still real and constructible.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	opt := evo.ForSkip()
	fmt.Println(opt != nil)
}
Output:
true

func OnTask added in v0.3.0

func OnTask(taskName string) ReasonOption
Example

ExampleOnTask shows constructing the ReasonOption that restricts a taxonomy Reason to one named task (see ExampleForSkip for why it isn't wired through evo.Reason yet).

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	opt := evo.OnTask("integration tests")
	fmt.Println(opt != nil)
}
Output:
true

type Redactor

type Redactor = engine.Redactor
Example

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

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var r evo.Redactor = evo.NoopRedactor{}
	fmt.Println(r.RedactString("token=abc123"))
}
Output:
token=abc123

type Resolution added in v1.0.0

type Resolution = core.Resolution

Resolution names why a Task settled successfully (§29/§30).

Example

ExampleResolution names why a Task settled successfully.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	task := out.Task("apply patch")
	task.Done()
	_ = out.Finish()
	fmt.Println(task.Snapshot().Resolution == evo.ResolutionNoWork)
}
Output:
true

type Result added in v1.0.0

type Result = core.Result

Result is the outcome of Run/Main/Output.Run — the finished Conclusion plus the application error the run callback returned, if any. Run and Output.Run return it directly; Main derives its int exit code from it. See EVIDENT_OUTPUT_ARCHITECTURE spec §1.1, §32.2.

Example

ExampleResult shows the outcome of Run/Main/Output.Run: the finished Conclusion plus the application error, if any.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	result := evo.Result{Conclusion: evo.Conclusion{State: evo.StateFailed, ExitCode: evo.ExitFailed}}
	fmt.Println(result.ExitCode())
}
Output:
2

func Run added in v0.4.0

func Run(ctx context.Context, run RunFunc) Result

Run executes run against the default Output and returns the Result (Conclusion plus the application error, if any); it never exits the process.

Example

ExampleRun shows executing application work against the default instance and inspecting the returned Result instead of exiting the process.

package main

import (
	"bytes"
	"context"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	evo.SetDefault(evo.Init(evo.Config{Stdout: &buf, Stderr: io.Discard, Plain: true}))
	result := evo.Run(context.Background(), func(ctx context.Context) error {
		evo.Task("apply migration").Done()
		return nil
	})
	fmt.Println(result.Err)
	fmt.Println(result.Conclusion.State)
}
Output:
<nil>
ready

type RunFunc added in v1.0.0

type RunFunc = engine.RunFunc

RunFunc is the shape of application work handed to Run/Main/Output.Run — a context.Context carries cancellation (wired to SIGINT/SIGTERM by those entrypoints) in place of the pre-v0.6 no-context func() error form.

Example

ExampleRunFunc shows the RunFunc shape application code hands to Run/Main/Output.Run: a context.Context in, an error out.

package main

import (
	"context"
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var run evo.RunFunc = func(ctx context.Context) error { return nil }
	fmt.Println(run(context.Background()))
}
Output:
<nil>

type SequenceHandle added in v0.4.0

type SequenceHandle struct {
	// contains filtered or unexported fields
}
Example

ExampleSequenceHandle shows the ordered collection handle Sequence returns.

package main

import (
	"context"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	seq := out.Sequence("stages")
	task := seq.Task("build")
	task.Define(func(ctx context.Context) error { return nil })
	_ = out.Finish()
	fmt.Println(seq.Snapshot().Name)
}
Output:
stages

func Sequence added in v0.4.0

func Sequence(name string) *SequenceHandle

Sequence declares a self-managing, ordered task container on the default instance.

Example

ExampleSequence declares a self-managing, ordered task container: one Running child at a time, in declaration order.

package main

import (
	"bytes"
	"context"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	evo.SetDefault(evo.Init(evo.Config{Stdout: &buf, Stderr: io.Discard, Plain: true}))
	worktrees := evo.Sequence("worktrees")
	for _, path := range []string{"repo-a", "repo-b"} {
		task := worktrees.Task(path)
		task.Define(func(ctx context.Context) error { return nil })
	}
	_ = evo.Default().Finish()
	fmt.Print(buf.String())
}
Output:
✓ worktrees
   ✓ repo-a
   ✓ repo-b

func (*SequenceHandle) Group added in v0.5.0

func (s *SequenceHandle) Group(name string) *GroupHandle

func (*SequenceHandle) Sequence added in v0.4.0

func (s *SequenceHandle) Sequence(name string) *SequenceHandle

func (*SequenceHandle) Snapshot added in v0.4.0

func (s *SequenceHandle) Snapshot() TasksSnapshot

func (*SequenceHandle) Summary added in v0.4.0

func (s *SequenceHandle) Summary(text string) *SequenceHandle

func (*SequenceHandle) Task added in v0.4.0

func (s *SequenceHandle) Task(name string) *TaskHandle

type Snapshot

type Snapshot = core.Snapshot

Snapshot is an immutable complete presentation state at a version.

Declared as a type alias into internal/core (the repo's data-model package — see EVIDENT_OUTPUT_ARCHITECTURE_SPEC_v0.5.md §38): rendering and evidence-capture machinery import core, never this root package, so the data model has to live where they can reach it without an import cycle back through the behavioral facades (Output, TaskHandle, evidence) that stay declared here. pkg.go.dev cannot expand an aliased type's fields (internal/core is never rendered) — see docs/reference.md for the full field-level reference this doc comment summarizes.

Example

ExampleSnapshot reads the immutable complete presentation state of a finished run.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	out.Task("apply patch").Done()
	_ = out.Finish()
	snap := out.Snapshot()
	fmt.Println(len(snap.Tasks))
}
Output:
1

type SourceLocation added in v0.3.0

type SourceLocation = core.SourceLocation

SourceLocation is a path-based source position. Named SourceLocation (not Location) so the Location(...) ProblemOption constructor below can keep that name without colliding with its own return type.

Example

ExampleSourceLocation shows a path-based source position attached to a Problem via Location.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	loc := evo.SourceLocation{Path: "config.yaml", Line: 12, Column: 3}
	fmt.Println(loc.Path, loc.Line, loc.Column)
}
Output:
config.yaml 12 3

type SystemClock

type SystemClock = engine.SystemClock
Example

ExampleSystemClock uses the real wall clock — the default TimeSource.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var clock evo.SystemClock
	fmt.Println(clock.Now().IsZero())
}
Output:
false

type TaskEvidence added in v1.0.0

type TaskEvidence = core.TaskEvidence

TaskEvidence preserves both observation phases a Task's Verify may have recorded (§30).

Example

ExampleTaskEvidence preserves both observation phases a Task's Verify may record: a before-false/after-true transition is never collapsed into one final boolean.

package main

import (
	"context"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	task := out.Task("ensure directory")
	first := true
	task.Verify(func(ctx context.Context) (bool, error) {
		satisfied := !first
		first = false
		return satisfied, nil
	})
	task.Define(func(ctx context.Context) error { return nil })
	_ = out.Finish()
	ev := task.Snapshot().Evidence
	fmt.Println(ev.Before.Satisfied, ev.After.Satisfied)
}
Output:
false true

type TaskHandle added in v0.3.0

type TaskHandle struct {
	// contains filtered or unexported fields
}
Example

ExampleTaskHandle shows a Task carrying work via Define instead of a bare Done — the handle Task returns.

package main

import (
	"bytes"
	"context"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{Stdout: &buf, Stderr: io.Discard, Plain: true, Isolated: true})
	handle := out.Task("fetch")
	handle.Define(func(ctx context.Context) error { return nil })
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✓ fetch

func Task

func Task(name string) *TaskHandle

Task declares a Task on the default instance.

Example

ExampleTask declares a Task on the default instance and resolves it.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	evo.SetDefault(evo.Init(evo.Config{Stdout: &buf, Stderr: io.Discard, Plain: true}))
	evo.Task("working tree").Done()
	_ = evo.Default().Finish()
	fmt.Print(buf.String())
}
Output:
✓ working tree

func (*TaskHandle) Add added in v0.3.0

func (t *TaskHandle) Add(object string, fn func() error, opts ...MutationOption)

func (*TaskHandle) After added in v0.5.0

func (t *TaskHandle) After(preds ...any) *TaskHandle

func (*TaskHandle) Block added in v0.3.0

func (t *TaskHandle) Block(summary string, options ...ProblemOption)

func (*TaskHandle) Blockf added in v0.3.0

func (t *TaskHandle) Blockf(format string, args ...any) *Failure

func (*TaskHandle) Bytes added in v0.3.0

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

func (*TaskHandle) Cancel added in v0.3.0

func (t *TaskHandle) Cancel(reason string)

func (*TaskHandle) Context added in v0.5.0

func (t *TaskHandle) Context() context.Context

func (*TaskHandle) Create added in v0.3.0

func (t *TaskHandle) Create(object string, fn func() error, opts ...MutationOption)

func (*TaskHandle) Define added in v0.5.0

func (t *TaskHandle) Define(fn func(context.Context) error)

Define freezes this Task's configuration and submits fn to the scheduler — see internal/engine.TaskHandle.Define (§7).

Example

ExampleTaskHandle_Define submits a Task's atomic work to the scheduler — Define is the scheduling and execution boundary (spec §7): the callback runs on an eligible run unless a current pre-Define Verify already proved the desired state satisfied.

package main

import (
	"bytes"
	"context"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{Isolated: true, Stdout: &buf, Stderr: io.Discard, Plain: true})
	task := out.Task("migrate")
	task.Define(func(ctx context.Context) error { return nil })
	_ = task.Wait()
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✓ migrate

func (*TaskHandle) Delete added in v0.3.0

func (t *TaskHandle) Delete(object string, fn func() error, opts ...MutationOption)

func (*TaskHandle) Doing added in v0.4.0

func (t *TaskHandle) Doing(text string, args ...any) *TaskHandle

func (*TaskHandle) Done added in v0.3.0

func (t *TaskHandle) Done(args ...any)

func (*TaskHandle) Fact added in v0.4.0

func (t *TaskHandle) Fact(name, value string)
Example

ExampleTask_Fact records discovered information — not work — as a durable dim line attached to the Task that found it. Fact never resolves the Task and never fakes a checkmark merely to display a value.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{Isolated: true, Stdout: &buf, Stderr: io.Discard, Plain: true})
	scan := out.Task("remote-tracking")
	scan.Fact("stale", "1")
	scan.Done()
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✓ remote-tracking    stale  1

func (*TaskHandle) Fail added in v0.3.0

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

func (*TaskHandle) Failf added in v0.3.0

func (t *TaskHandle) Failf(format string, args ...any) *Failure

func (*TaskHandle) Kept added in v0.3.0

func (t *TaskHandle) Kept(reason TaxonomyReason)

func (*TaskHandle) Key added in v1.0.0

func (t *TaskHandle) Key(key string) *TaskHandle

Key sets an advanced, refactor/rename-stable override for this Task's §3.1 identity — see internal/engine.TaskHandle.Key.

Example

ExampleTaskHandle_Key sets an advanced, refactor/rename-stable override for a Task's stable identity (spec §3.1) — use it when a Task's name changes across runs but its tracked identity must not.

package main

import (
	"bytes"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var buf bytes.Buffer
	out := evo.Init(evo.Config{Isolated: true, Stdout: &buf, Stderr: io.Discard, Plain: true})
	out.Task("migrate 003_add_users.sql").Key("migration:003").Done()
	_ = out.Finish()
	fmt.Print(buf.String())
}
Output:
✓ migrate 003_add_users.sql

func (*TaskHandle) Next added in v0.3.0

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

func (*TaskHandle) NextCommand added in v0.3.0

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

func (*TaskHandle) Progress added in v0.3.0

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

func (*TaskHandle) Push added in v0.3.0

func (t *TaskHandle) Push(object string, fn func() error, opts ...MutationOption)

func (*TaskHandle) Record added in v0.3.0

func (t *TaskHandle) Record(verb string, quantity int, object string)

func (*TaskHandle) RecordLabel added in v0.3.0

func (t *TaskHandle) RecordLabel(label string, quantity int, object string)

func (*TaskHandle) RecordName added in v0.3.0

func (t *TaskHandle) RecordName(verb, object string)

func (*TaskHandle) Remove added in v0.3.0

func (t *TaskHandle) Remove(object string, fn func() error, opts ...MutationOption)

func (*TaskHandle) Skipped added in v0.3.0

func (t *TaskHandle) Skipped(reason TaxonomyReason)

func (*TaskHandle) Snapshot added in v0.3.0

func (t *TaskHandle) Snapshot() TaskSnapshot

func (*TaskHandle) Step added in v0.3.0

func (t *TaskHandle) Step(completed, total int, name string) *TaskHandle

func (*TaskHandle) Update added in v0.3.0

func (t *TaskHandle) Update(object string, fn func() error, opts ...MutationOption)

func (*TaskHandle) Verify added in v1.0.0

func (t *TaskHandle) Verify(fn func(context.Context) (bool, error)) *TaskHandle

Verify registers an advanced current-state observation check — see internal/engine.TaskHandle.Verify (§9.1).

Example

ExampleTaskHandle_Verify registers a boolean, read-only pre-Define check. A Verify that reports the desired state already holds skips Define entirely and resolves ResolutionAlreadySatisfied — the one advanced escape hatch for domains Evo cannot track automatically (spec §56).

package main

import (
	"context"
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Isolated: true, Stdout: io.Discard, Stderr: io.Discard})
	task := out.Task("already-configured")
	task.Verify(func(ctx context.Context) (bool, error) { return true, nil })
	task.Define(func(ctx context.Context) error {
		panic("Define must not run once Verify reports already satisfied")
	})
	_ = task.Wait()
	fmt.Println(task.Snapshot().Resolution)
}
Output:
already_satisfied

func (*TaskHandle) Wait added in v0.5.0

func (t *TaskHandle) Wait() error

func (*TaskHandle) Warn added in v0.3.0

func (t *TaskHandle) Warn(summary string)

func (*TaskHandle) Write added in v0.3.0

func (t *TaskHandle) Write(object string, fn func() error, opts ...MutationOption)

func (*TaskHandle) Writer added in v0.4.0

func (t *TaskHandle) Writer() io.Writer

type TaskSnapshot

type TaskSnapshot = core.TaskSnapshot

TaskSnapshot is an immutable task view.

Example

ExampleTaskSnapshot reads a Task's immutable view after it resolves.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	task := out.Task("apply patch")
	task.Done()
	_ = out.Finish()
	snap := task.Snapshot()
	fmt.Println(snap.Name, snap.State)
}
Output:
apply patch done

type TasksSnapshot

type TasksSnapshot = core.TasksSnapshot

TasksSnapshot is an immutable collection view.

Example

ExampleTasksSnapshot reads a collection's immutable view: its own state plus every child Task it declared.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	group := out.Group("packages")
	group.Task("curl").Done()
	_ = out.Finish()
	snap := group.Snapshot()
	fmt.Println(snap.Name, len(snap.Tasks))
}
Output:
packages 1

type TaxonomyReason added in v0.3.0

type TaxonomyReason struct {
	// contains filtered or unexported fields
}
Example

ExampleTaxonomyReason shows a get-or-create taxonomy Reason: the same string at every call site merges into one bucket.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	evo.SetDefault(out)
	first := evo.Reason("dirty working tree")
	second := evo.Reason("dirty working tree")
	fmt.Println(first.Name() == second.Name())
}
Output:
true

func Reason added in v0.3.0

func Reason(name string) TaxonomyReason

Reason returns a get-or-create taxonomy Reason by name on the default instance.

Example

ExampleReason shows the get-or-create taxonomy lookup an inline evo.Reason("...") call always legally reuses.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	evo.SetDefault(out)
	reason := evo.Reason("protected")
	fmt.Println(reason.Name())
}
Output:
protected

func (TaxonomyReason) Name added in v0.3.0

func (r TaxonomyReason) Name() string

type TaxonomyRecord added in v0.3.0

type TaxonomyRecord = core.TaxonomyRecord

TaxonomyRecord is one accumulated (reason, name) disposition entry — recorded by TaskHandle.Skipped or TaskHandle.Kept, never assembled by hand.

Example

ExampleTaxonomyRecord reads the accumulated (reason, name) disposition TaskHandle.Skipped records — never assembled by hand.

package main

import (
	"fmt"
	"io"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	out := evo.Init(evo.Config{Stdout: io.Discard, Stderr: io.Discard, Plain: true, Isolated: true})
	evo.SetDefault(out)
	task := out.Task("branch main")
	task.Skipped(evo.Reason("protected"))
	_ = out.Finish()
	record := task.Snapshot().Skipped[0]
	fmt.Println(record.Reason, record.Name)
}
Output:
protected branch main

type TerminalDriver

type TerminalDriver = engine.TerminalDriver
Example

ExampleTerminalDriver shows the minimal identity interface a custom terminal integration implements — see evo.Terminal.

var driver evo.TerminalDriver = namedTerminal{"custom"}
fmt.Println(driver.ID())
Output:
custom

type TimeSource

type TimeSource = engine.TimeSource
Example

ExampleTimeSource shows the deterministic clock interface Clock injects in place of the real wall clock.

package main

import (
	"fmt"
	"time"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var clock evo.TimeSource = evo.FixedClock{T: time.Unix(0, 0).UTC()}
	fmt.Println(clock.Now())
}
Output:
1970-01-01 00:00:00 +0000 UTC

type Verbosity added in v0.2.0

type Verbosity = engine.Verbosity
Example

ExampleVerbosity selects which message visibilities project to the human stream — zero is VerbosityNormal.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	v := evo.VerbosityVerbose
	fmt.Println(v == evo.VerbosityVerbose)
}
Output:
true

type Visibility added in v0.2.0

type Visibility = core.Visibility

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

Example

ExampleVisibility selects whether a message is ordinary or verbose user detail — zero is VisibilityNormal.

package main

import (
	"fmt"

	evo "github.com/zachbornheimer/evident-output"
)

func main() {
	var v evo.Visibility
	fmt.Println(v == evo.VisibilityNormal)
}
Output:
true

Directories

Path Synopsis
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 a short sequential probe.
Command debug-history demos a short sequential probe.
debug-pane command
Command debug-pane demos a sequential audit with an optional blocker.
Command debug-pane demos a sequential audit with an optional blocker.
doctor command
Command doctor is an environment/health check CLI.
Command doctor is an environment/health check CLI.
generate-pipeline command
Command generate-pipeline demos spec §64's canonical Exec pipeline shape: a normalize stage (schema.xlsx -> schema.json) feeding a compile stage (schema.json + compile.py -> output.bin), sequenced with Sequence (declaration order, never concurrent) the way a real pipeline must be (a Basis relationship alone never implies scheduling order — see docs/acceptance/v0.6.md's Increment 3 section).
Command generate-pipeline demos spec §64's canonical Exec pipeline shape: a normalize stage (schema.xlsx -> schema.json) feeding a compile stage (schema.json + compile.py -> output.bin), sequenced with Sequence (declaration order, never concurrent) the way a real pipeline must be (a Basis relationship alone never implies scheduling order — see docs/acceptance/v0.6.md's Increment 3 section).
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.
launch-agent-file command
Command launch-agent-file demos spec §12's canonical launchd shape: a Sequence writing a managed plist via evo.File, followed by two Verify-gated Tasks stubbed to succeed.
Command launch-agent-file demos spec §12's canonical launchd shape: a Sequence writing a managed plist via evo.File, followed by two Verify-gated Tasks stubbed to succeed.
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 demonstrates the mutation-verb effect boundary (Add/Create/Write, ...): the same call site records a planned effect under --dry-run (evo.DryRun) or a committed one when it actually runs, and evo derives Changed/Ready/Planned from what happened — the caller never chooses which ledger a mutation lands in.
Command migrate demonstrates the mutation-verb effect boundary (Add/Create/Write, ...): the same call site records a planned effect under --dry-run (evo.DryRun) or a committed one when it actually runs, and evo derives Changed/Ready/Planned from what happened — the caller never chooses which ledger a mutation lands in.
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 named Tasks for host and plugin work.
Command scope-plugin demos named Tasks for host and plugin work.
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
agent/adopt
Package adopt inventories non-evo CLI output in an existing codebase and proposes a migration plan keyed to the adoption ladder (Init/Main → Task/Done → effects → facts/warnings → confirm/dry-run).
Package adopt inventories non-evo CLI output in an existing codebase and proposes a migration plan keyed to the adoption ladder (Init/Main → Task/Done → effects → facts/warnings → confirm/dry-run).
agent/catalog
Package catalog is the task-oriented guidance catalog for agent assistance.
Package catalog is the task-oriented guidance catalog for agent assistance.
agent/harness
Package harness evaluates agent-assistance scenarios (§30.9, MCP-022/049).
Package harness evaluates agent-assistance scenarios (§30.9, MCP-022/049).
agent/preview
Package preview generates multi-profile plain previews from snapshots.
Package preview generates multi-profile plain previews from snapshots.
agent/review
Package review provides deterministic static review of Evident Output usage.
Package review provides deterministic static review of Evident Output usage.
agent/rules
Package rules is the stable review-rule registry (Appendix C namespaces).
Package rules is the stable review-rule registry (Appendix C namespaces).
agent/sections
Package sections is the full-docs counterpart to catalog: catalog holds hand-curated, token-budgeted guidance snippets; sections serves the whole authoritative doc corpus (reference, development, MCP wiring, the adoption ladder, and the per-concept guides catalog already owns) through one list/get pair, mirroring the Svelte MCP's list-sections / get-documentation shape.
Package sections is the full-docs counterpart to catalog: catalog holds hand-curated, token-budgeted guidance snippets; sections serves the whole authoritative doc corpus (reference, development, MCP wiring, the adoption ladder, and the per-concept guides catalog already owns) through one list/get pair, mirroring the Svelte MCP's list-sections / get-documentation shape.
architecture/importprobe/baseline command
Command baseline is architecture's import-probe baseline: byte-for-byte the same program as ./candidate except it imports nothing from evo.
Command baseline is architecture's import-probe baseline: byte-for-byte the same program as ./candidate except it imports nothing from evo.
architecture/importprobe/candidate command
Command candidate is architecture's import-probe candidate program: it imports the root evo package for its side effects only and immediately reports its own process state, so TestImportingRootPackagePerformsNoIOOrGoroutines (in internal/architecture) can diff its behavior against baseline, the otherwise-identical program that imports nothing from evo.
Command candidate is architecture's import-probe candidate program: it imports the root evo package for its side effects only and immediately reports its own process state, so TestImportingRootPackagePerformsNoIOOrGoroutines (in internal/architecture) can diff its behavior against baseline, the otherwise-identical program that imports nothing from evo.
core
Package core owns evident-output's data model: the immutable, fields-only value types a finished or in-flight run presents (Snapshot, Problem, Conclusion, and peers) plus the pure functions that derive one from another (InferConclusion, SanitizeProblem, ...).
Package core owns evident-output's data model: the immutable, fields-only value types a finished or in-flight run presents (Snapshot, Problem, Conclusion, and peers) plus the pure functions that derive one from another (InferConclusion, SanitizeProblem, ...).
fingerprint
Package fingerprint computes observation-only content identities for evo.File/evo.Exec Basis and operation-definition hashing (spec §11.1).
Package fingerprint computes observation-only content identities for evo.File/evo.Exec Basis and operation-definition hashing (spec §11.1).
manifest
Package manifest persists reconciliation truth across Runs: which operation last ran, under which definition, with which Basis and output digests (spec §11.3-11.4).
Package manifest persists reconciliation truth across Runs: which operation last ran, under which definition, with which Basis and output digests (spec §11.3-11.4).
modpin
Package modpin parses a go.mod for the evident-output require pin and replace directive so MCP update and the usage-audit share one parser.
Package modpin parses a go.mod for the evident-output require pin and replace directive so MCP update and the usage-audit share one parser.
render
Package render is evident-output's presentation machinery: plain, structured (JSON/JSONL), and interactive (live) projection of a internal/core Snapshot.
Package render is evident-output's presentation machinery: plain, structured (JSON/JSONL), and interactive (live) projection of a internal/core Snapshot.
text
Package text is repo-owned CLI text machinery: sanitization, terminal cell width measurement, truncation, glyph-safe pluralization/conjugation.
Package text is repo-owned CLI text machinery: sanitization, terminal cell width measurement, truncation, glyph-safe pluralization/conjugation.
wire
Package wire owns the v2 machine wire contract (spec §32.1–§38): the "evo.run" final document and the "evo.event" JSONL line.
Package wire owns the v2 machine wire contract (spec §32.1–§38): the "evo.run" final document and the "evo.event" JSONL line.
wireschema
Package wireschema validates a rendered JSON document against evo's own published JSON Schema (schema/output.v1.json) — the facade that makes the schema file an enforced gate instead of prose nobody checks (P8: "today nothing references that file — make it a gate").
Package wireschema validates a rendered JSON document against evo's own published JSON Schema (schema/output.v1.json) — the facade that makes the schema file an enforced gate instead of prose nobody checks (P8: "today nothing references that file — make it a gate").
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.
tools
gensections command
Command gensections copies the docs the MCP server's list_sections / get_documentation tools serve into internal/agent/sections/embedded, the only directory go:embed can reach from that package.
Command gensections copies the docs the MCP server's list_sections / get_documentation tools serve into internal/agent/sections/embedded, the only directory go:embed can reach from that package.
scripts/bisectability-check command
Command bisectability-check proves every first-parent commit in a range builds on its own — a merge sequence where an intermediate commit only compiles once a *later* commit in the same merge lands (increment 3's 48baff0 is the known instance) breaks git bisect for anyone landing between those two commits, silently, until a bisect run hits exactly that range.
Command bisectability-check proves every first-parent commit in a range builds on its own — a merge sequence where an intermediate commit only compiles once a *later* commit in the same merge lands (increment 3's 48baff0 is the known instance) breaks git bisect for anyone landing between those two commits, silently, until a bisect run hits exactly that range.
scripts/evo-usage-audit command
Command evo-usage-audit scans a Go repository for uses of github.com/zachbornheimer/evident-output (and its subpackages) and prints a markdown usage inventory: one heading per file that uses evo, one fenced code block per top-level declaration that uses it, tagged with how.
Command evo-usage-audit scans a Go repository for uses of github.com/zachbornheimer/evident-output (and its subpackages) and prints a markdown usage inventory: one heading per file that uses evo, one fenced code block per top-level declaration that uses it, tagged with how.
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.
scripts/traceability-check command
Command traceability-check verifies every expected §31 ID is present, and that every .go file TRACEABILITY.md's Test(s) column names still exists (a moved or renamed test file that nobody updated the table for used to pass silently — IDs-present-only checking let the table rot green).
Command traceability-check verifies every expected §31 ID is present, and that every .go file TRACEABILITY.md's Test(s) column names still exists (a moved or renamed test file that nobody updated the table for used to pass silently — IDs-present-only checking let the table rot green).

Jump to

Keyboard shortcuts

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