streaming-architecture — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited streaming-architecture (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
What it is: streaming-architecture is the discipline for designing one logical result as an ordered sequence of values over time, with explicit flow control, framing, error, resume, and termination semantics.
Mental model: Every streaming design has a producer, stream, consumer, backpressure path, and termination signal. Transports encode those primitives differently; they do not replace the design work.
Why it exists: Some results are too large, too slow, or too useful early to wait for a complete batch response. Streaming gives earlier value and bounded memory only when the contract is explicit.
What it is NOT: It is not browser freshness UX, one-shot API payload design, durable worker execution, model/tool transcript protocol design, event-contract design, or the page-level rendering taxonomy.
Adjacent concepts: real-time-updates owns browser freshness and live-dashboard UX; api-design owns one bounded request/response surface; background-jobs owns durable queued work; tool-call-flow owns model/tool message-history protocol; rendering-models owns CSR/SSR/SSG/RSC taxonomy; event-contract-design owns event payload and topic contracts.
One-line analogy: A streaming architecture is a conveyor belt: boxes move one at a time, the dock signals when it is full, and a final marker says the shipment is complete.
Common misconception: The transport is not the concept. The concept is the contract for ordered incremental delivery, backpressure, and termination.
The discipline of designing systems that emit and consume sequences of values over time with explicit flow control. Covers the five primitives (producer, stream, consumer, backpressure, termination), the transport mechanisms (HTTP chunked transfer, SSE, WebSocket, HTTP/2 streams, gRPC streaming, WHATWG Streams, Node streams), the directionality and backpressure-model taxonomies, in-stream error semantics, delivery guarantees, the design contract between producer and consumer, and the failure modes that streaming systems exhibit at scale (slow consumer, abandoned consumer, mid-stream disconnect, head-of-line blocking, partial-result correctness).
Streaming is the response to a category of problem that batch request/response cannot solve: results that are too big to materialize, too slow to wait for, or too useful at the front to delay until the back arrives. The cost is a more demanding contract between producer and consumer — error semantics get harder, backpressure must be explicit, connections must be managed — but for the problem class it serves, batch is not an inferior streaming; batch is wrong.
The deeper philosophy is that streaming is a contract about time. The five primitives — producer, stream, consumer, backpressure, termination — are the same whether the transport is an SSE event source, a gRPC bidirectional RPC, a WHATWG ReadableStream piping into a TransformStream, an RSC chunked response, or an LLM emitting tokens. A practitioner who learns the contract once can move between transports at the cost of an encoding translation; a practitioner who learns only one transport's API conflates the contract with its encoding and treats every new streaming surface as a new concept.
The discipline of streaming architecture is to know when streaming is the right shape, to design the contract explicitly when it is, and to make backpressure and termination first-class in that contract rather than emergent properties of the transport.
| Primitive | What it is | What it owns | Failure mode if absent |
|---|---|---|---|
| Producer | The source of values | Emission rate, ordering, framing | Stream cannot exist |
| Stream | The ordered emission channel | Carrying values in order; no random access | Values arrive out of order or lost in transit |
| Consumer | The processing sink | Processing rate, ack of received values | Producer has no purpose; values discarded |
| Backpressure | Flow-control signal upstream | Matching producer rate to consumer rate | Memory exhaustion, dropped values, crash |
| Termination | Explicit end-of-stream signal | Distinguishing "done" from "quiet" | Consumer waits forever; resource leak |
Any streaming system can be analyzed as: who is the producer, what is the stream's framing, who is the consumer, how does backpressure travel upstream, and how is termination signaled. A streaming system that has no answer for any of these is incomplete and will fail under load.
| Transport | Directionality | Framing | Backpressure | Reconnect | Typical use |
|---|---|---|---|---|---|
| HTTP chunked transfer (RFC 9112) | Server→client | Length-prefixed chunks | TCP-level only | None | Large response body of unknown length |
| Server-Sent Events (HTML LS, EventSource) | Server→client | Newline-delimited event:/data: lines | TCP-level only | Built-in via Last-Event-ID | Live feeds, progress, LLM token streams |
| WebSocket (RFC 6455) | Bidirectional | Length-prefixed frames | Application-level | None (manual) | Chat, real-time games, collaborative editing |
| HTTP/2 streams (RFC 9113) | Bidirectional per stream | Per-stream framing with WINDOW_UPDATE flow control | Built-in via WINDOW_UPDATE | None (manual) | gRPC transport, multiplexed APIs |
| gRPC streaming | Server/client/bidi | Protobuf-framed values | Built-in via HTTP/2 flow control | Manual | Typed RPC, microservice streams |
| WHATWG ReadableStream | In-process | Reader queues | Built-in via pull model | N/A | Browser-side stream composition |
| Node.js Readable | In-process | Object or buffer chunks | Built-in via highWaterMark | N/A | Server-side file/network plumbing |
Selection rule: pick directionality first (one-way → SSE or HTTP chunked; two-way → WebSocket or gRPC bidi), then framing needs (binary structured → gRPC or WebSocket; text events → SSE; opaque bytes → HTTP chunked), then infrastructure compatibility (HTTP/1.1 proxies often break WebSocket and SSE; HTTP/2 proxies are friendlier).
SSE is the lowest-ceremony, highest-compatibility transport for server→client streaming. The HTML Living Standard EventSource API ships in every modern browser.
GET /stream HTTP/1.1
Accept: text/event-stream
HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-store
event: token
data: {"id":1,"text":"Hello"}
event: token
data: {"id":2,"text":" world"}
event: done
data: {}Properties:
event:, data:, and id: fields.Last-Event-ID header on the resume request.For LLM token streaming, progress bars, status feeds, dashboards, and any one-way live update channel, SSE is the right starting point. Move to WebSocket only if bidirectionality is required.
WebSocket (RFC 6455) is a bidirectional, framed, binary-or-text protocol upgraded from HTTP. Both ends can send at any time.
GET /ws HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: ...
Sec-WebSocket-Version: 13
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: ...Properties:
For collaborative editing, multiplayer games, chat, and any interaction where both sides need to send unsolicited messages, WebSocket is the right transport. For one-way server-driven updates, it is more machinery than necessary and SSE is usually a better fit.
The slow-consumer failure mode is the most consequential streaming failure. A producer that emits at 1000 events/sec and a consumer that processes at 100/sec produces 900 events/sec of accumulation. After one minute, the buffer holds 54,000 events; after one hour, 3.24 million. Without backpressure, this exhausts memory.
| Backpressure strategy | How it works | Trade-off |
|---|---|---|
| Pull (consumer asks) | Producer emits only when consumer calls read() | Implicit; correct by construction; requires pull-capable producer |
| Credit-based push | Consumer signals "I can accept N more"; producer emits up to N then waits | Explicit; works over network; adds round-trip latency |
| Buffered push with drop | Producer emits freely; buffer drops oldest/newest on overflow | Bounded memory; lossy; only acceptable when loss is OK |
| Buffered push with block | Producer emits freely; producer blocks when buffer full | Bounded memory; propagates slowness upstream; only works in-process |
| Sampling | Consumer samples N values/sec, discarding the rest | Lossy by design; correct for telemetry; wrong for correctness streams |
For each new streaming endpoint, the answer to "what happens when the consumer is slower than the producer?" must be one of these strategies — explicitly, not by accident.
Termination is a distinct message, not the absence of new values. A consumer that interprets a 10-second silence as "the stream ended" will be wrong on any production network. Explicit termination signals:
| Transport | Termination signal |
|---|---|
| HTTP chunked | Zero-length chunk |
| SSE | Server closes the connection; client may auto-reconnect |
| WebSocket | Close frame with status code |
| gRPC | Status message on the trailer |
| WHATWG ReadableStream | Reader's read() returns {done: true} |
Resume after disconnect is a separate concern. SSE has it built in (Last-Event-ID); WebSocket requires application-level resume tokens; gRPC offers reconnect but not exactly-once across reconnects. A streaming consumer must be designed for "the connection dropped at value 4,732; reconnect and continue at 4,733" if that semantic matters.
| Strategy | When to use | Cost |
|---|---|---|
| Fail-fast (terminate stream on error) | The error invalidates everything after | Loses partial-results value of streaming |
| In-band error value | Errors are part of the value type (e.g., a tool-call result with an error payload) | Forces consumers to handle two value shapes |
| Out-of-band signal (HTTP trailer, WebSocket close code) | The stream is a sequence of successful values; errors are exceptional | Consumer must watch two channels |
The choice depends on whether the consumer can usefully proceed past an error. For LLM token streams, an error mid-generation is usually fatal — fail-fast. For a search-results stream, one row's permission error need not stop the others — in-band errors. For a long-lived telemetry stream, errors are out-of-band by convention.
| Framework feature | Underlying mechanism |
|---|---|
| React Server Components streaming | HTTP chunked transfer; framework-specific chunk format |
| Next.js Suspense streaming | Streaming SSR over HTTP chunked transfer |
Remix loader streaming with defer() | Promise serialization over the response stream |
fetch() response body | WHATWG ReadableStream wrapping the network response |
Node res.write() / res.end() | Node Readable on the response object |
| LLM token streaming SDKs | HTTP response streams, often SSE-like event frames; SDK parses frames into iterable values |
Each of these is the same five-primitive contract dressed in a framework's API. The framework adds typing, suspense integration, error boundary handling, and ergonomic composition — but the underlying contract is the streaming-architecture primitive.
After applying this skill, verify:
| Instead of this skill | Use | Why |
|---|---|---|
| Designing the message-history protocol between a model and a tool runtime | tool-call-flow | tool-call-flow is a specialization of streaming for the model↔runtime cycle; this skill is the underlying primitive |
| Designing event payload contracts or domain-event topic semantics | event-contract-design | event-contract-design owns named occurrence payloads and topic contracts; streaming owns ordered-emission channels |
| Designing the JSON shape of a single response payload | api-design | api-design owns request/response surfaces; streaming-architecture owns multi-value-over-time surfaces |
| Keeping a browser dashboard, notification list, or progress view fresh | real-time-updates | real-time-updates owns user-visible freshness UX, reconnect catch-up, and transport selection for browser views |
| Moving long-running work into a durable queue with retry policy | background-jobs | background-jobs owns durable execution and retries; streaming-architecture owns incremental delivery while a producer is emitting |
| Designing the page-level rendering taxonomy | rendering-models | rendering-models owns CSR/SSR/SSG/RSC; this skill owns the streaming primitive those depend on |
text/event-stream protocol.pipe().<!-- skill-graph-context:start (generated — do not edit by hand) -->
Classification
backend-engineeringtrueengineering/realtimeWhen to use
streaming-architecture, how should this endpoint stream, producer stream consumer backpressure termination, what's the backpressure story, partial result deliveryNot for
Related skills
client-server-boundary, performance-budgets, api-design, real-time-updatesevent-contract-design, rendering-models, real-time-updates, api-design, background-jobs, client-server-boundary, performance-budgets, tool-call-flowConcept
Grounding
universalhttps://www.rfc-editor.org/rfc/rfc9112#name-chunked-transfer-coding, https://www.rfc-editor.org/rfc/rfc9113#name-streams-and-multiplexing, https://www.rfc-editor.org/rfc/rfc6455, https://html.spec.whatwg.org/multipage/server-sent-events.html, https://streams.spec.whatwg.org/, https://nodejs.org/api/stream.html, https://grpc.io/docs/what-is-grpc/core-concepts/, https://www.reactive-streams.org/, https://react.dev/reference/react-dom/server/renderToPipeableStream, https://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Using_readable_streamsKeywords
streaming, stream, backpressure, SSE, server-sent events, chunked transfer, HTTP/2, WebSocket, WHATWG Streams, ReadableStream<!-- skill-graph-context:end -->
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.