Consider input/output holistically (beyond the JSON-only presumption) #18

Closed
opened 2026-06-30 03:51:06 +00:00 by navicore · 1 comment
Owner

Opening this to start a discussion, not to land a specific design.

Framing

The compiled-binary contract today ties a program's output fairly tightly to a single wire format: the engine wrapper serialises query bindings as JSON, and program-authored write/1 bytes share that same stdout. That coupling has held well for the "program is a pure relation; caller extracts via the query" model that linting.pl and the worker reactor demonstrate.

But "the answer is always JSON" is a presumption I'd like to question before it ossifies. Real production binaries will want their inputs and outputs in other shapes — YAML, TOML, CSV, line-delimited records, plain human prose, things not invented yet — and the caller will often be another program (or a human in a shell) that has its own expectations about the stream it's consuming.

The constraint I think is worth holding

I don't think it's a problem for a compiled program to be limited to stdin and stdout as its only I/O surface. That's a clean, portable, Unix-shaped contract and it fits the immutable-binary thesis. The interesting question is not how many channels a program has, but how the format of those two channels is conceived.

What I'd like us to consider wholemeal

Rather than add formats one at a time as ad-hoc flags, can we imagine the input/output story as an architecture in its own right — one where:

  • many input and output formats are possible on the same two streams, not just the one the engine wrapper happens to ship with;
  • the engine's own contract (the fields it emits or consumes — solutions, exhausted, exit codes, the --query itself) stays as inflexible as it needs to for correctness, while the serialisation of those fields is the part that's open to many formats; and
  • program-authored output and engine-authored output can coexist on stdout without one corrupting the other, whatever format either is in.

The distinction I want to draw is: the shape of the data is fixed; the encoding of the data is plural. Today we've collapsed those two into "JSON, everywhere," and I'd like us to separate them before we build further on top.

What I'm not assuming

  • Not proposing a specific format list, a specific format/2, a specific flag, or a specific streaming model. Those are all downstream of the architectural decision.
  • Not asking the program to gain channels beyond stdin/stdout.
  • Not asking the engine wrapper to go away — it's load-bearing for exit codes and the caller contract.

I'd like this thread to be where we work out what the right framing is before we scope any concrete change. Thoughts welcome — especially on whether "fixed fields, plural encodings" is the right axis to split on, or whether there's a better way to hold the design space open.

Opening this to start a discussion, not to land a specific design. ## Framing The compiled-binary contract today ties a program's output fairly tightly to a single wire format: the engine wrapper serialises query bindings as JSON, and program-authored `write/1` bytes share that same stdout. That coupling has held well for the "program is a pure relation; caller extracts via the query" model that `linting.pl` and the worker reactor demonstrate. But "the answer is always JSON" is a presumption I'd like to question before it ossifies. Real production binaries will want their inputs and outputs in other shapes — YAML, TOML, CSV, line-delimited records, plain human prose, things not invented yet — and the caller will often be another program (or a human in a shell) that has its own expectations about the stream it's consuming. ## The constraint I think is worth holding I don't think it's a problem for a compiled program to be limited to **stdin and stdout** as its only I/O surface. That's a clean, portable, Unix-shaped contract and it fits the immutable-binary thesis. The interesting question is not *how many channels* a program has, but **how the format of those two channels is conceived**. ## What I'd like us to consider wholemeal Rather than add formats one at a time as ad-hoc flags, can we imagine the input/output story as an architecture in its own right — one where: - many input and output formats are *possible* on the same two streams, not just the one the engine wrapper happens to ship with; - the engine's own contract (the fields it emits or consumes — solutions, exhausted, exit codes, the `--query` itself) stays as **inflexible** as it needs to for correctness, while the **serialisation of those fields** is the part that's open to many formats; and - program-authored output and engine-authored output can coexist on stdout without one corrupting the other, whatever format either is in. The distinction I want to draw is: **the shape of the data is fixed; the encoding of the data is plural.** Today we've collapsed those two into "JSON, everywhere," and I'd like us to separate them before we build further on top. ## What I'm not assuming - Not proposing a specific format list, a specific `format/2`, a specific flag, or a specific streaming model. Those are all downstream of the architectural decision. - Not asking the program to gain channels beyond stdin/stdout. - Not asking the engine wrapper to go away — it's load-bearing for exit codes and the caller contract. I'd like this thread to be where we work out what the right framing is before we scope any concrete change. Thoughts welcome — especially on whether "fixed fields, plural encodings" is the right axis to split on, or whether there's a better way to hold the design space open.
Author
Owner

wrong repo

wrong repo
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
navicore/loglings#18
No description provided.