fo

module
v0.2.3 Latest Latest
Warning

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

Go to latest
Published: May 19, 2026 License: MIT

README

fo

Focused build output renderer. Reads SARIF, go test -json, or lightweight hygiene formats on stdin and renders for terminals, LLMs, or automation.

golangci-lint run --output.sarif.path=stdout ./... | fo
go test -json ./...                                 | fo
go vet ./... 2>&1                                   | fo wrap diag --tool govet | fo

What it does

fo is a stdin-driven presentation layer. It auto-detects the input format, parses it into a canonical Report (the IR), classifies findings against a sidecar baseline (new / persistent / fixed), and renders one of three outputs:

  • human — Tufte-Swiss styled terminal output (default on TTY)
  • llm — token-dense plain text, no ANSI (default when piped)
  • json — machine-parseable Report

Everything funnels through the same Report struct, so wrappers, hygiene formats, and native parsers all benefit from the same diff classification, scoring, and renderers.

Install

go install github.com/dkoosis/fo/cmd/fo@latest

Requires Go 1.24+. Runtime deps: lipgloss, golang.org/x/term.

Input formats

Auto-detected from stdin:

Format Trigger Source
SARIF 2.1.0 JSON shape golangci-lint, gosec, staticcheck, custom tools
go test -json JSON-line shape go test -json ./...
tally # fo:tally header (or bare <count> <label> rows) hygiene scripts, uniq -c pipelines
status # fo:status header doctor scripts, contract checks
metrics # fo:metrics header coverage, benchmarks, sizes

If stdin lacks a header, force a kind with --as tally|status|metrics|diag.

See docs/guides/hygiene-formats.md for the hygiene format reference, migration recipes, and FO_STATE_DIR notes.

Wrappers

fo wrap <name> adapters convert third-party tool output into SARIF or a hygiene format, then pipe to fo for rendering:

archlint        go-arch-lint JSON → SARIF
archlint-text   go-arch-lint plain-text → SARIF
cover           go tool cover -func → fo:metrics
diag            file:line:col: msg → SARIF
gobench         go test -bench → fo:metrics
jscpd           jscpd JSON → SARIF
leaderboard     "<count> <label>" tally → fo:tally

fo wrap list (or fo wrap list --json) prints the current set.

CLI

USAGE
  <input-command> | fo [FLAGS]
  <tool-output>   | fo wrap <name> [FLAGS]

FLAGS
  --format <mode>      auto | human | llm | json   (default: auto)
  --theme <name>       color | mono                (default: auto — color on TTY)
  --state-file <path>  Sidecar state file          (default: .fo/last-run.json)
  --no-state           Skip diff classification + sidecar I/O
  --state-strict       Exit non-zero (2) if sidecar save fails
  --stream             Stream go test -json incrementally (bypasses 256 MiB cap)
  --as <kind>          Format hint when stdin lacks a fo header

SUBCOMMANDS
  fo wrap <name>       Convert tool output to SARIF / hygiene format
  fo wrap list         List available wrappers
  fo state reset       Clear the diff baseline
  fo --version         Print build version
  fo --print-schema    Emit JSON Schema for the Report struct

Exit codes

0   Clean — no errors or test failures
1   Failures — lint errors or test failures present
2   Usage error — bad flags, unrecognized input, stdin problems

Use the exit code, not stdout parsing, to gate CI steps.

Diff classification

fo writes a sidecar at .fo/last-run.json after each run (override with --state-file or FO_STATE_DIR, disable with --no-state). The next run classifies each finding as new, persistent, or fixed by stable fingerprint, and surfaces those deltas in the rendered output.

fo state reset clears the baseline.

Architecture

stdin
  ├─[1] read       (bounded 256 MiB / streaming)
  ├─[2] sniff      (SARIF / go test -json / hygiene / multiplex)
  ├─[3] parse      → Report (IR)
  ├─[4] diff       (vs sidecar baseline)
  ├─[5] mode pick  (TTY → human, piped → llm)
  ├─[6] render     (paint primitives + theme)
  └─[7] exit code  (0 / 1 / 2)
Path Role
cmd/fo/ CLI entry, flag parsing, format sniffing, wrap dispatch
pkg/report/ Canonical Report + multiplex delimiter protocol
pkg/sarif/ SARIF 2.1.0 reader/builder → Report
pkg/testjson/ go test -json parser → Report
pkg/view/ human / llm / json renderers
pkg/paint/ Tufte-Swiss primitives (bars, sparklines, tables)
pkg/theme/ Color / mono theme system
pkg/state/ Sidecar baseline for diff classification
pkg/score/, pkg/fingerprint/ Severity scoring + finding identity
pkg/status/, pkg/metrics/, pkg/tally/ Hygiene format parsers
pkg/wrapper/wrap*/ Tool-specific adapters
internal/boundread/, internal/lineread/ Stdin readers

Adding a wrapper

  1. Create a package under pkg/wrapper/ exposing Convert(in io.Reader, out io.Writer) error.
  2. Add a case to the wrap dispatch in cmd/fo/main.go and import the package.
  3. Wire a one-line description into the wrap list table.

No interface, no registry — a deliberate switch.

License

MIT

Directories

Path Synopsis
cmd
fo command
fo renders build tool output as information-dense terminal visualizations.
fo renders build tool output as information-dense terminal visualizations.
internal
boundread
Package boundread reads from an io.Reader with a hard byte cap so a pathological tool can't OOM the wrapper process.
Package boundread reads from an io.Reader with a hard byte cap so a pathological tool can't OOM the wrapper process.
kvtok
Package kvtok is a shared whitespace tokenizer for fo's tiny key=value header DSLs (pkg/scene and pkg/suppress).
Package kvtok is a shared whitespace tokenizer for fo's tiny key=value header DSLs (pkg/scene and pkg/suppress).
lineread
Package lineread provides a bounded line reader used by fo's input pipelines.
Package lineread provides a bounded line reader used by fo's input pipelines.
pkg
cluster
Package cluster groups go test failures that share a root cause — same topmost user-code stack frame OR same normalized assertion text — so renderers can collapse N failures from one bug into one expandable group.
Package cluster groups go test failures that share a root cause — same topmost user-code stack frame OR same normalized assertion text — so renderers can collapse N failures from one bug into one expandable group.
fingerprint
Package fingerprint computes a stable per-finding identity used by the diff classifier (pkg/state) to match findings across fo runs.
Package fingerprint computes a stable per-finding identity used by the diff classifier (pkg/state) to match findings across fo runs.
metrics
Package metrics parses fo's metrics input format — keyed numeric values used for hygiene rollups (coverage %, LOC counts, build time, benchmark deltas, dependency counts).
Package metrics parses fo's metrics input format — keyed numeric values used for hygiene rollups (coverage %, LOC counts, build time, benchmark deltas, dependency counts).
paint
Package paint provides Tufte-Swiss visual primitives: bars, sparklines, alignment helpers.
Package paint provides Tufte-Swiss visual primitives: bars, sparklines, alignment helpers.
report
Multi-tool delimiter protocol — multiplexes several tool outputs into a single stdin stream via lines of the form:
Multi-tool delimiter protocol — multiplexes several tool outputs into a single stdin stream via lines of the form:
sarif
Package sarif models SARIF 2.1.0 — the format fo treats as canonical for static-analysis input.
Package sarif models SARIF 2.1.0 — the format fo treats as canonical for static-analysis input.
scene
Package scene parses fo's scene input format — narrated, multi-actor walk-throughs grouped into numbered acts.
Package scene parses fo's scene input format — narrated, multi-actor walk-throughs grouped into numbered acts.
score
Package score ranks static-analysis findings so renderers can lead with the ones that matter.
Package score ranks static-analysis findings so renderers can lead with the ones that matter.
state
Package state persists a sidecar record of prior fo runs and classifies the current run's findings against that history.
Package state persists a sidecar record of prior fo runs and classifies the current run's findings against that history.
status
Package status parses fo's status input format — labeled rows with PASS/FAIL/WARN/SKIP state, used for contract tables, doctor checks, module gates, and any "list of named conditions" output that today gets handed to printf|awk.
Package status parses fo's status input format — labeled rows with PASS/FAIL/WARN/SKIP state, used for contract tables, doctor checks, module gates, and any "list of named conditions" output that today gets handed to printf|awk.
suppress
Package suppress parses fo's .fo/ignore suppression file — a line-based list of rule suppressions used to silence individual findings during diff classification and rendering.
Package suppress parses fo's .fo/ignore suppression file — a line-based list of rule suppressions used to silence individual findings during diff classification and rendering.
tally
Package tally parses fo's tally input format — a count→label distribution that renders as a Leaderboard view.
Package tally parses fo's tally input format — a count→label distribution that renders as a Leaderboard view.
testjson
Package testjson parses `go test -json` NDJSON streams into the renderer-facing report.Report.
Package testjson parses `go test -json` NDJSON streams into the renderer-facing report.Report.
theme
Package theme provides the v2 Tufte-Swiss theme system: structure (bold, dim, alignment) lives in the mono preset; color layers on top.
Package theme provides the v2 Tufte-Swiss theme system: structure (bold, dim, alignment) lives in the mono preset; color layers on top.
view
Strategy: extend BulletItem with optional *ClusterRender (per Task 0 orient).
Strategy: extend BulletItem with optional *ClusterRender (per Task 0 orient).
wrapper
Package wrapper is a namespace for SARIF converters that adapt third-party tool output to SARIF 2.1.0.
Package wrapper is a namespace for SARIF converters that adapt third-party tool output to SARIF 2.1.0.
wrapper/wraparchlint
Package wraparchlint converts go-arch-lint JSON output into SARIF 2.1.0.
Package wraparchlint converts go-arch-lint JSON output into SARIF 2.1.0.
wrapper/wraparchlinttext
Package wraparchlinttext converts go-arch-lint plain-text output into SARIF.
Package wraparchlinttext converts go-arch-lint plain-text output into SARIF.
wrapper/wrapcover
Package wrapcover converts `go tool cover -func` output into fo's metrics format.
Package wrapcover converts `go tool cover -func` output into fo's metrics format.
wrapper/wrapdiag
Package wrapdiag converts line-based Go diagnostics into SARIF 2.1.0.
Package wrapdiag converts line-based Go diagnostics into SARIF 2.1.0.
wrapper/wrapgobench
Package wrapgobench converts raw `go test -bench` output into fo's metrics format.
Package wrapgobench converts raw `go test -bench` output into fo's metrics format.
wrapper/wrapjscpd
Package wrapjscpd converts jscpd JSON duplication reports into SARIF 2.1.0.
Package wrapjscpd converts jscpd JSON duplication reports into SARIF 2.1.0.
wrapper/wrapleaderboard
Package wrapleaderboard converts plain `count label` tally input into fo's tally format.
Package wrapleaderboard converts plain `count label` tally input into fo's tally format.

Jump to

Keyboard shortcuts

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