pulse api compose
Audience: CLI users executing a batch of related requests in one call.
pulse api compose runs multiple types.Request
entries against one or more cohorts. The whole batch is one
ComposedRequest; the engine can run the entries sequentially or in
parallel against a bounded worker pool.
LLM agents using MCP: see the
pulse_composeMCP tool and thecompose-requestsskill.
Synopsis
pulse api compose --request FILE [--json] [--stream]
[--parallel N] [--no-fail-fast]
[--no-defaults] [--echo-request]
Flags
| Flag | Alias | Type | Default | Purpose |
|---|---|---|---|---|
--request | -r | string | (required) | Composed-request JSON path |
--json | bool | false | Wrap output in the standard envelope | |
--stream | bool | false | Stream rows as NDJSON; each line is {"index": N, "row": {...}} | |
--parallel | int | 1 | Worker count; 0 = GOMAXPROCS, 1 = sequential | |
--no-fail-fast | bool | false | Aggregate errors across slots instead of cancelling on first failure (parallel mode only) | |
--no-defaults | bool | false | Disable smart operator-type inference | |
--echo-request | bool | false | Include the normalized ComposedRequest on envelope.request; each slot reflects its post-defaults form. Ignored under --stream |
Request file shape
{
"requests": [
{ "cohort": {"filename": "sales.pulse"}, "aggregations": [...] },
{ "cohort": {"filename": "sales.pulse"}, "groups": [...] },
{ "cohort": {"filename": "ops.pulse"}, "filterers": [...] }
]
}
Each requests[i] is a full types.Request. Slots are independent —
they may target different cohorts, use different operators, etc.
When the cohort is a shard archive, each request can target the whole
archive (fan-out across every shard) or one shard via the
archive.pulse#shard.pulse anchor — Compose preserves slot order
regardless:
{
"requests": [
{"cohort": {"filename": "Q1_2019.pulse"}, "aggregations": [...]},
{"cohort": {"filename": "Q1_2019.pulse#20190101.pulse"}, "aggregations": [...]},
{"cohort": {"filename": "wave_2018.pulse"}, "aggregations": [...]}
]
}
Output ordering
Responses come back in input order, regardless of --parallel.
A worker that finishes early waits its turn before emitting. So
data.responses[i] always corresponds to request.requests[i].
Parallel mode
--parallel N:
1(default) — sequentialCompose, equivalent to running each request throughpulse api processin a loop.0—runtime.GOMAXPROCSworkers.>1— exactly N workers.
Workers share Pulse’s read-only registries; per-request stateful operators are constructed fresh. See Parallel Compose for full mechanics.
FailFast semantics
With --no-fail-fast unset (the default, fail-fast on):
- The first failing request cancels in-flight siblings.
- The command exits non-zero with the first error.
With --no-fail-fast:
- Every request runs to its own completion (or per-request timeout).
- Errors aggregate into a single
SERVICE_INTERNALerror whosedetails.failed_indiceslists the slot indices that failed. - Successful slots populate
data.responses[]; failed slots arenull.
Output
--json
{
"format_version": "1.1",
"data": {
"responses": [ /* one Response per slot, in input order */ ],
"overlays": [ /* one OverlayLayer per ComposedRequest.overlays spec; omitted when no Compose overlays */ ]
},
"errors": [],
"warnings": []
}
data is a ComposedResponse object (since the v0.21.0 Compose facade
lift). Each data.responses[i] is a full Response, so per-slot
data.responses[i].components follows the same additive contract as
api process. data.overlays[i] carries the
post-fold Compose-host overlay layer plus its per-layer
warnings[] diagnostics (OverlayWarning{code, message, details});
the slot is omitempty so overlay-free Compose responses are
byte-identical to the legacy []*Response wire shape that shipped
under format_version: "1.0".
--stream
{"index": 0, "row": { ... }}
{"index": 0, "row": { ... }}
{"index": 1, "row": { ... }}
The index field identifies which slot’s request produced each row.
Exit codes
| Code | Meaning |
|---|---|
| 0 | All requests succeeded |
| 1 | One or more requests failed (fail-fast: first error; aggregated: any failure) |
Examples
Sequential batch
pulse api compose --request batch.json --json
Parallel with 4 workers, aggregated errors
pulse api compose --request batch.json --parallel 4 --no-fail-fast --json
Stream a parallel batch into a downstream consumer
pulse api compose --request batch.json --parallel 4 --stream | \
jq -c 'select(.index == 2)'
Related
pulse api process— single-request leaf- Library: Parallel Compose — Go-side equivalents
skills/compose-requests.md(LLM) — request composition patterns