overengineeringstudio / overengineeringstudio/effect-utils
@overeng/tui-react: make machine output modes safer and less surprising for CLI scripting
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 82
- Forks
- 2
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 121
Description
Context
Several CLIs built on @overeng/tui-react expose --output json|ndjson|pipe and are usable from scripts, but the current output contract is harder to consume than it needs to be.
The issue is not limited to one CLI. The same behavior shows up in multiple consumers because it comes from the shared tui-react output/runtime layer.
Current behavior
json
Final JSON output is wrapped in a Success / Failure envelope rather than emitting just the app payload.
For non-struct states this becomes:
{ "_tag": "Success", "value": { ...state } }
ndjson
Progressive JSON output emits:
- an initial raw state line
- intermediate raw state lines
- a final wrapped
Success/Failureline
This is a valid design, but it is surprising for CLI scripting unless the contract is very explicit.
pipe
pipe is currently a final React render mode, not a strict machine-output mode. That is fine for some commands, but the name strongly suggests something script-safe and raw.
Whether it is safe for scripting depends on the command's view, which makes the contract easy to misread.
Why this is a problem
For CLI scripting, there are two separate needs:
- a stable machine-readable contract
- a human-readable final render that happens to work when piped
Right now these are too close together.
The result is:
- JSON consumers need CLI-specific decoding knowledge
- NDJSON consumers need to understand initial-state and final-envelope semantics
pipecan look machine-safe while actually rendering human framing
Relevant implementation points
Shared behavior appears to come from these places:
packages/@overeng/tui-react/src/effect/TuiApp.tsx- final JSON wrapping in
Success/Failure - progressive NDJSON initial raw-state emission + final wrapped line
- final JSON wrapping in
packages/@overeng/tui-react/src/effect/OutputMode.tsxpipedefined as final React output mode
packages/@overeng/tui-react/src/effect/cli.tsx- shared
outputOption/outputModeLayerused by multiple CLIs
- shared
Desired behavior
A more explicit split between human and machine output modes.
Possible directions:
- Keep current behavior, but document it much more explicitly.
- Introduce a stricter machine mode, for example
raworjson-final/json-stream. - Make
jsonemit only the payload by default, and reserve envelopes for a separate mode. - Make
ndjsonemit a documented event stream shape instead of mixing raw states with a wrapped final line. - Rename or better document
pipeso it is clear that it is a final visual render mode, not necessarily script-safe.
Recommendation
I think the minimum improvement should be:
- document the exact contracts for
json,ndjson, andpipe - clarify that
pipeis a final render mode - add one truly machine-safe mode with a minimal predictable contract
Workaround
Consumers can use json today, but they need to know about the extra envelope shape. ndjson is also usable, but only if they explicitly handle the initial-state line and final wrapped line.
Filed by an AI assistant on behalf of @schickling
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read packages/@overeng/tui-react/src/effect/TuiApp.tsx, OutputMode.tsx, and cli.tsx to trace the shared json, ndjson, and pipe contracts used by multiple CLIs. Compare the current behavior with the listed directions and establish a documented, predictable machine-output contract while making the final render behavior of pipe explicit; the issue does not name a specific test.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- cli, tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 32/100