Agent-First Data v0.15: Stdout and Stderr File Destinations

by Agent-First Kit Contributors

v0.15 adds one CLI convention across Rust, Go, Python, and TypeScript: --stdout-file and --stderr-file redirect the process streams to append-only files before normal parsing starts.

AFDATA has always treated stdout as the protocol boundary. One line, one event, structured enough for an agent to parse and strict enough that a helper can depend on it. That rule is still right.

But a CLI sometimes runs somewhere stdout is not the place you want the bytes to land: inside a supervisor, behind a tool runner, in an environment where the caller wants a durable transcript, or in a test harness that needs process output without shell redirection.

v0.15 adds file destinations for the two process streams:

tool --stdout-file /tmp/tool.out --stderr-file /tmp/tool.err command
tool --stdout-file=/tmp/tool.out --stderr-file=/tmp/tool.err command

Stdout bytes go to the stdout file. Stderr bytes go to the stderr file. The stream names are explicit because agents and supervisors often treat the two channels differently: stdout is where AFDATA events usually live, while stderr is where runtime diagnostics and parser failures often appear.

If your CLI emits an AFDATA event to stdout, --stdout-file captures that event. If Rust panics, Python writes a traceback, Go writes a runtime diagnostic, or Node writes an unhandled exception to stderr, --stderr-file captures the raw diagnostic bytes. That distinction matters because stderr is not always an agent event. Sometimes it is the runtime telling you the process broke before your protocol had a chance to speak.

Install before help and version

The helpers parse raw argv before the normal CLI parser runs. They recognize both space-separated and equals forms:

--stdout-file PATH
--stdout-file=PATH
--stderr-file PATH
--stderr-file=PATH

That early parse is deliberate. --help, --version, and parse errors are the places CLIs most often exit before application logic starts. If stream redirection were installed after clap, argparse, flag parsing, or a hand-written parser, the early output would miss the file.

The pattern is:

install stream redirection from raw args
handle --version / --help / parser errors
run the command

The application parser can still expose the flags in its help text, but the file descriptors are already pointed at the requested destinations before any of that text is printed.

Same convention in four languages

v0.15 ships the same convention in each AFDATA package:

LanguageHelper surface
Rustagent_first_data::stream_redirect::install_from_raw_args(...)
Goafdata.InstallStreamRedirectFromArgs(...)
Pythonagent_first_data.stream_redirect.install_from_raw_args(...)
TypeScriptinstallStreamRedirectFromRawArgs(...) from agent-first-data/stream_redirect

Rust, Go, and Python install scoped redirection objects that restore the original descriptors when closed or dropped. The TypeScript helper targets Node CLIs and is process-lifetime by design, because Node does not expose a portable dup2 restore API. The CLI contract is still the same: append stdout to one file, append stderr to another, and leave the bytes alone.

This keeps --output honest

AFDATA already uses --output for a different question: how a protocol event is rendered (json, yaml, plain, or help-only markdown where supported). File destinations are separate from that rendering choice.

That is why the names are explicit:

--stdout-file /tmp/stdout.jsonl
--stderr-file /tmp/stderr.log

The flag tells you which stream moves and where it moves to. It does not imply a format conversion, and it does not compete with --output json.

Also in v0.15

Rust CLI help rendering now uses display names where a tool provides one, and markdown help suppresses the duplicated name - about paragraph that could show up both in the heading and inside the fenced help block. The visible result is small, but it matters for generated docs: one title, one summary, no repeated intro line.

v0.15 is a plumbing release. It gives CLIs a first-party way to put stdout and stderr into files without changing what stdout and stderr mean.