Pipelex 0.30.1 Treats Agent CLIs Like APIs, Not Terminals With Better Branding

Agent CLIs have spent the last year cosplaying as terminals while production systems quietly started treating them like APIs. Pipelex 0.30.1 is a small release, but it lands on exactly the seam where that pretense breaks: stdout and stderr are not vibes. If another runner is parsing them, they are protocol channels.

The release tightens the contract for pipelex-agent, the machine-consumed side of Pipelex’s declarative AI workflow tooling. Stdout is now reserved for structured success output — JSON or markdown — while stderr is reserved for structured error envelopes. Arbitrary Python logging is suppressed process-wide. That sounds like housekeeping until you have watched a downstream orchestration layer fail because one dependency printed an INFO line before a JSON object.

Pipelex names the failure modes directly. A log.debug from telemetry_factory.py, a log.warning from validation_error_categorizer.py, or verbose output from dependencies such as anthropic, httpx, botocore, or openai could corrupt downstream parsers. One example in the release is mthds-js calling JSON.parse(stderr) during a validate hook. That is the kind of bug that looks absurd in a postmortem and completely inevitable in a real stack.

The terminal is not the interface anymore

Pipelex describes itself as a declarative language for composable AI workflows, “for agents and mere humans.” That split matters. The human CLI can be permissive: tables on stdout, debug logs, redirectable output, and all the normal ergonomics Unix users expect. The agent CLI has a different job. It is not chatting with a person at a prompt. It is serving another program that needs deterministic, parseable output.

Version 0.30.1 follows 0.30.0, which already moved package logs off stdout by default and forced agent CLI console log and print targets away from the JSON data channel. The new release goes further. make_pipelex_for_agent_cli injects config overrides into Pipelex.make() so default_log_level = OFF and package_log_levels.pipelex = OFF. Then silence_logging_for_agent_cli() calls logging.disable(sys.maxsize), a process-global cutoff checked before per-logger levels.

That is blunt. It is also correct for this surface. In an ordinary library, process-global log suppression would be a smell. In a subprocess API where stdout and stderr are the wire protocol, it is boundary enforcement. The release even wires the Typer app callback so every subcommand inherits the suppression, including init and accept-gateway-terms, which bypass the usual agent factory path. There are belt-and-braces calls left in the factory paths for direct library callers too. This is what it looks like when maintainers have been burned by a real integration bug and then close every side door.

The project also removes --log-level from pipelex-agent. That is the part some developers will dislike on first read. User configuration usually wins in CLI tools. But machine interfaces cannot let a local TOML file turn a structured channel into confetti. For humans, verbose debugging still belongs in the separate pipelex CLI. For agents and runners, the output contract wins.

Structured output is governance, not polish

This is easy to dismiss as a logging patch. It is more than that. Agent runtime governance starts with knowing what the runtime emitted, what the caller parsed, and which failure state actually occurred. If the process prints human diagnostics into a structured stream, every layer above it is forced to guess. Was the tool call invalid? Did the LLM produce malformed output? Did a validation hook fail? Did the framework crash? Or did httpx simply decide to be chatty?

That ambiguity matters because agent systems increasingly chain tools, CLIs, MCP servers, workflow engines, and JavaScript/Python/Rust adapters together. The clean diagram says “agent calls tool.” The production version says “orchestrator shells out to CLI, CLI loads config, config enables dependency logging, dependency emits warning, caller parses stderr as JSON, model sees a tool error, retry policy kicks in, and the human blames the agent.” Parser roulette is not an architecture.

Pipelex’s regression test is the practical bit: it sets anthropic, httpx, botocore, and openai to DEBUG in user TOML and asserts stdout and stderr stay clean. That is the right adversarial test. Do not test the happy path where everyone behaves. Test the path where every dependency tries to talk and the machine contract still holds.

There is also a useful lesson in the earlier 0.30.0 tradeoff. PR #934 preserved redirectable human CLI behavior such as pipelex show backends > out.txt, while tightening the agent path. That is better design than making one universal CLI mode serve incompatible audiences. Humans need legibility and control. Agent runners need stable envelopes. Pretending those are the same requirement is how frameworks accumulate footguns.

For teams building agent tooling, the action list is boring and non-optional. Reserve stdout for one category of data. Decide whether stderr is human diagnostics or structured errors; do not make it both. Version the envelope if clients parse it. Add tests that force dependency loggers to DEBUG. Separate human verbosity flags from machine interfaces. Treat shell commands consumed by agents as APIs with contracts, not scripts that happen to return text.

Pipelex 0.30.1 is not a flashy release. That is why it is useful. The agent ecosystem has enough demos showing tools calling tools. It needs more releases that say, plainly, that one stray log line can corrupt the runtime boundary. Looks small in the changelog. Looks obvious after the outage.

Sources: Pipelex v0.30.1 release, Pipelex v0.30.0 release, PR #939, PR #934