Skip to content

[Feature]: --output-format stream-json for machine-readable execution output #2689

@buildoak

Description

@buildoak

1. Why Do You NEED This Feature?

I'm building an orchestration layer that runs Forge as a subprocess via forge -p "...". Right now I have to scrape the terminal output to figure out what's happening, which tools got called, whether something failed. It's fragile and breaks whenever the TUI formatting changes.

I need a way to get structured events out of a running Forge session. Not static config info, but the actual execution stream: tool calls, their outputs, text deltas, errors, token counts. Basically a machine-readable version of what the TUI shows.

2. What Is NOT Possible Right Now?

  • There's no machine-readable mode for forge -p "..." or interactive sessions. The only output is the human-facing TUI.
  • FORGE_DEBUG_REQUESTS writes raw HTTP request data, which is debug-level stuff, not structured execution events.
  • Can't reliably extract tool call boundaries, durations, or token usage from the rendered terminal output. Regex parsing of ANSI-formatted text is not a real solution.
  • --verbose gives more info but it's still unstructured text meant for a person reading a terminal.

I've tried parsing the TUI output with a combination of ANSI stripping and regex. It works until it doesn't.

3. What WILL Be Possible With This Feature?

  • CI/CD pipelines that run forge -p "..." and parse tool results and token usage without scraping
  • Editor plugins and TUI wrappers that react to events in real time (tool starts, errors, text streaming)
  • Cost tracking and failure detection via structured logs instead of eyeballing terminal output
  • Multi-agent setups where a parent process orchestrates Forge as a subprocess with actual structured communication, not screen-scraping

Proposed Solution (User Experience)

A flag like --output-format stream-json that switches stdout from the TUI to NDJSON (one JSON object per line).

forge -p "fix the bug in auth.rs" --output-format stream-json

Output would look roughly like:

{"type":"tool_call_start","tool":"Read","input":{"path":"src/auth.rs"},"timestamp_ms":1711382400000}
{"type":"tool_output","tool_call_id":"tc_01","duration_ms":487}
{"type":"text_delta","content":"Based on the file..."}
{"type":"turn_complete","input_tokens":12450,"output_tokens":892}

NDJSON because it's the simplest streaming format. Works with jq, standard unix pipes, any language's line reader. Same approach Claude Code uses with its --output-format stream-json. No server, no extra dependencies.

When this flag is active the TUI doesn't render. Stdout is just the event stream. Stderr could still be used for fatal errors or diagnostics if needed.

I could take a crack at the PR if you're open to the general direction.

Alternatives Considered

  • Parsing terminal output: fragile. Any TUI change breaks the parser and you're back to debugging regex.
  • WebSocket or gRPC server: too heavy for this use case. NDJSON on stdout keeps it simple and composable.
  • Extending FORGE_DEBUG_REQUESTS: aimed at HTTP-level debugging, not execution-level events. Different abstraction layer.

Feature Category

Multi-Agent Workflows

Priority/Impact

High - Would significantly improve my workflow

Examples from Other Tools

Claude Code has --output-format stream-json that does basically this. NDJSON events for tool calls, text, system messages, token usage. It's the main way people build orchestration and CI pipelines on top of it.

gh (GitHub CLI) uses --json flags on most commands. docker events --format '{{json .}}' streams container events as JSON lines. Same pattern, well established.

Additional Context

--porcelain already shows the project values machine-readable output for static queries (model info, tool lists, config). This would extend that same philosophy to the execution stream, which is where the real data lives for automation use cases.

Pre-submission Checklist

  • I have searched existing issues and confirmed this is not a duplicate
  • I am willing to submit a PR to implement this feature

Metadata

Metadata

Assignees

No one assigned

    Labels

    type: featureBrand new functionality, features, pages, workflows, endpoints, etc.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions