Summary
Replace the inherited NUKE console output with a two-layer model:
- Serilog owns the structured event stream (one set of log calls, fanned
out to a human sink and a machine sink).
- Spectre.Console owns the rich frame (run header, end-of-run summary
table), driven directly by the build executor — NOT routed through a sink.
Adds first-class NDJSON output so agents/tools can shell out to Fallout and
parse a clean machine stream.
Motivation
Supports the AI-native CLI goals: NDJSON streaming, describe --json,
structured errors, semantic exit codes. The structured-event model maps a
single set of log calls onto both a pretty console and a machine stream, so
human and agent consumers stay in sync from one source of truth.
Design notes
Two layers, kept strictly separate. The trap is driving a Spectre
Progress/Live region from inside an ILogEventSink — those are stateful
console-region takeovers and can't be fed by decoupled events. Logging layer
= the event stream; presentation layer = the frame.
Tasks
Acceptance criteria
fallout build renders rich human output incl. summary table; no markup
parse errors on real-world messages (paths, arrays)
fallout build --output json emits valid NDJSON on stdout, one object per
line, parseable by jq, zero ANSI contamination; diagnostics on stderr
- Exceptions render via Spectre in human mode and are captured (
@x) in json mode
Out of scope (follow-ups)
Progress/Live spinners — human-only polish, separate item; this is where
the two layers can fight over the console
- Custom semantic NDJSON schema — start on CLEF, diverge only if
describe --json consumers need a bespoke contract (cost: re-handling all
property-value unwrapping)
Refs
- Keep sink package surface minimal — assembly-version conflicts in the
build-loaded context are a known NUKE pain point
Summary
Replace the inherited NUKE console output with a two-layer model:
out to a human sink and a machine sink).
table), driven directly by the build executor — NOT routed through a sink.
Adds first-class NDJSON output so agents/tools can shell out to Fallout and
parse a clean machine stream.
Motivation
Supports the AI-native CLI goals: NDJSON streaming,
describe --json,structured errors, semantic exit codes. The structured-event model maps a
single set of log calls onto both a pretty console and a machine stream, so
human and agent consumers stay in sync from one source of truth.
Design notes
Two layers, kept strictly separate. The trap is driving a Spectre
Progress/Liveregion from inside anILogEventSink— those are statefulconsole-region takeovers and can't be fed by decoupled events. Logging layer
= the event stream; presentation layer = the frame.
Tasks
SpectreConsoleSink : ILogEventSink— level→colour mapping,Markup.Escapeon rendered text (paths/arrays/GUIDs contain[ ]),AnsiConsole.WriteExceptionfor exceptionsSerilog.Formatting.Compact.CompactJsonFormatter(CLEF)→ stdout
OutputModeflag + logger build that branches: human → Spectre sink,json → CLEF sink (branch, don't run both — avoids ANSI corrupting the
NDJSON stream by construction)
diagnostics/human chatter on stderr
Table(executor-driven,human mode only)
properties) as the equivalent of the table
sink)
Acceptance criteria
fallout buildrenders rich human output incl. summary table; no markupparse errors on real-world messages (paths, arrays)
fallout build --output jsonemits valid NDJSON on stdout, one object perline, parseable by
jq, zero ANSI contamination; diagnostics on stderr@x) in json modeOut of scope (follow-ups)
Progress/Livespinners — human-only polish, separate item; this is wherethe two layers can fight over the console
describe --jsonconsumers need a bespoke contract (cost: re-handling allproperty-value unwrapping)
Refs
build-loaded context are a known NUKE pain point