Skip to content

Commit 1758287

Browse files
chore(release): 🔖 v0.13.0 (#224)
## Summary Lockstep version bump to 0.13.0 for the Redis Streams event sink release (#222, #223). Includes documentation updates, SDK/executor rebuild, changelog promotion, and golden fixture updates. ## Highlights - Bump `quarry/types/version.go`, `sdk/package.json`, `sdk/src/types/events.ts` to 0.13.0 - Rebuild SDK dist and executor bundle with new version - Promote CHANGELOG.md `[Unreleased]` → `[0.13.0] - 2026-03-12` - Update golden test fixtures with `contract_version` 0.13.0 - Update `PUBLIC_API.md` version references from 0.12.2 → 0.13.0 - Add event sink documentation to configuration guide and integration guide ## Test plan - [ ] CI passes (Go tests, SDK tests, typecheck, lint, biome) - [ ] Golden fixture contract versions match 0.13.0 - [ ] `quarry/types/version.go` = `sdk/package.json` = `CONTRACT_VERSION` = 0.13.0 - [ ] CHANGELOG.md has dated `[0.13.0]` section with link reference 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9f19982 commit 1758287

12 files changed

Lines changed: 175 additions & 34 deletions

File tree

CHANGELOG.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
---
1313

14+
## [0.13.0] - 2026-03-12
15+
16+
### Added
17+
18+
- **Integration**: Pluggable Redis Streams event sink — publishes every event in real time via `XADD` during run execution, enabling downstream consumers to watch events across all runs on a single stream (#222, #223)
19+
- **CLI**: `--event-sink` repeatable flag to activate event sinks (`lode`, `redis`); multiple sinks fan out with independent delivery semantics (#223)
20+
- **CLI**: Redis Streams event sink flags: `--event-sink-redis-url`, `--event-sink-redis-stream-key`, `--event-sink-redis-max-len`, `--event-sink-redis-ttl`, `--event-sink-redis-timeout`, `--event-sink-redis-retries`, `--event-sink-redis-delivery` (#223)
21+
- **Runtime**: Fan-out event sink with per-sink delivery classification — `mandatory` sinks fail the run on error; `best_effort` sinks log warnings and continue (#223)
22+
- **Contracts**: CONTRACT_INTEGRATION.md updated with Event Sink Model (scope, delivery semantics, failure behavior, fan-out inheritance) (#223)
23+
- **Contracts**: CONTRACT_CLI.md updated with event sink flag specifications (#223)
24+
- **Docs**: Integration guide updated with Redis Streams event sink section, comparison table, and YAML config example (#223)
25+
- **Docs**: Configuration guide updated with event sink flags and YAML schema (#223)
26+
27+
### Changed
28+
29+
- **Docs**: PUBLIC_API.md updated with event sink flags and downstream integration references (#223)
30+
31+
---
32+
1433
## [0.12.2] - 2026-03-11
1534

1635
### Changed
@@ -510,7 +529,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
510529

511530
---
512531

513-
[Unreleased]: https://github.com/pithecene-io/quarry/compare/v0.12.2...HEAD
532+
[Unreleased]: https://github.com/pithecene-io/quarry/compare/v0.13.0...HEAD
533+
[0.13.0]: https://github.com/pithecene-io/quarry/compare/v0.12.2...v0.13.0
514534
[0.12.2]: https://github.com/pithecene-io/quarry/releases/tag/v0.12.2
515535
[0.12.1]: https://github.com/pithecene-io/quarry/releases/tag/v0.12.1
516536
[0.12.0]: https://github.com/pithecene-io/quarry/releases/tag/v0.12.0

PUBLIC_API.md

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,24 @@ Quarry is **TypeScript-first** and **ESM-only**.
2626
### Via mise (recommended)
2727

2828
```bash
29-
mise install github:pithecene-io/quarry@0.12.2
29+
mise install github:pithecene-io/quarry@0.13.0
3030
```
3131

3232
Or pin in your `mise.toml`:
3333

3434
```toml
3535
[tools]
36-
"github:pithecene-io/quarry" = "0.12.2"
36+
"github:pithecene-io/quarry" = "0.13.0"
3737
```
3838

3939
### Via Docker
4040

4141
```bash
4242
# Full image — includes Chrome for Testing + fonts (amd64 only, recommended)
43-
docker pull ghcr.io/pithecene-io/quarry:0.12.2
43+
docker pull ghcr.io/pithecene-io/quarry:0.13.0
4444

4545
# Slim image — no browser, multi-arch (BYO Chromium via --browser-ws-endpoint)
46-
docker pull ghcr.io/pithecene-io/quarry:0.12.2-slim
46+
docker pull ghcr.io/pithecene-io/quarry:0.13.0-slim
4747
```
4848

4949
See [docs/guides/container.md](docs/guides/container.md) for `docker run` and Docker Compose examples.
@@ -468,6 +468,25 @@ CLI flags always override config file values.
468468
| `--adapter-timeout <duration>` | `10s` | Notification timeout |
469469
| `--adapter-retries <n>` | `3` | Retry attempts |
470470

471+
**Event sink flags (real-time event delivery, v0.13.0+):**
472+
473+
| Flag | Default | Description |
474+
|------|---------|-------------|
475+
| `--event-sink <type>` | | Event sink type (`lode`, `redis`); repeatable |
476+
| `--event-sink-lode-delivery` | `mandatory` | Delivery mode for Lode event sink |
477+
| `--event-sink-redis-url <url>` | | Redis URL (required when `--event-sink` includes `redis`) |
478+
| `--event-sink-redis-stream-key` | `quarry:events` | Redis Streams key |
479+
| `--event-sink-redis-max-len` | `100000` | Max stream length (-1 disables) |
480+
| `--event-sink-redis-ttl` | `24h` | Stream key expiry (-1 disables) |
481+
| `--event-sink-redis-timeout` | `2s` | Per-operation timeout |
482+
| `--event-sink-redis-retries` | `2` | Retry attempts |
483+
| `--event-sink-redis-delivery` | `mandatory` | Delivery mode for Redis event sink |
484+
485+
> **Event sinks vs adapters:** Event sinks deliver events in real time during a
486+
> run. Adapters fire once after a run completes. Both can be used together.
487+
> When no `--event-sink` flags are set, events go to Lode only (default).
488+
> See `docs/contracts/CONTRACT_INTEGRATION.md` and `docs/guides/integration.md`.
489+
471490
**Fan-out flags (derived work execution):**
472491

473492
| Flag | Default | Description |
@@ -726,22 +745,22 @@ executor runs under Node ESM.
726745

727746
Quarry ships container images via GHCR:
728747

729-
- **Full** (amd64 only): `ghcr.io/pithecene-io/quarry:0.12.2` — includes Chrome for Testing + fonts
730-
- **Slim** (amd64 + arm64): `ghcr.io/pithecene-io/quarry:0.12.2-slim` — no browser (BYO via `--browser-ws-endpoint`)
748+
- **Full** (amd64 only): `ghcr.io/pithecene-io/quarry:0.13.0` — includes Chrome for Testing + fonts
749+
- **Slim** (amd64 + arm64): `ghcr.io/pithecene-io/quarry:0.13.0-slim` — no browser (BYO via `--browser-ws-endpoint`)
731750

732751
For `docker run`, Docker Compose, and sidecar patterns, see [docs/guides/container.md](docs/guides/container.md).
733752

734753
---
735754

736-
## Known Limitations (v0.12.2)
755+
## Known Limitations (v0.13.0)
737756

738757
1. **Single executor type**: Only Node.js executor supported
739758
2. **No built-in retries**: Retry logic is caller's responsibility
740759
3. **No streaming reads**: Artifacts must fit in memory (note: the `streaming` *ingestion policy* is unrelated — it controls write batching, not read access)
741760
4. **No transactional storage writes**: S3 and S3-compatible providers (R2, MinIO) do not provide transactional guarantees across writes
742761
5. **No job scheduling**: Quarry supports in-process derived work via `--depth` but is not a scheduler; external orchestration is the caller's responsibility
743762
6. **Puppeteer required**: All scripts run in a browser context
744-
7. **Event bus adapters**: Webhook and Redis pub/sub adapters are available. Temporal, NATS, and SNS adapters are planned. See `docs/guides/integration.md`.
763+
7. **Integration adapters and sinks**: Webhook, Redis Pub/Sub, and Redis Streams are available. Temporal, NATS, and SNS adapters are planned. Event sink read-side interfaces are tabled for future work. See `docs/guides/integration.md`.
745764
8. **Fan-out partition defaults**: Child runs inherit the root run's `--source` and `--category` unless overridden via `emit.enqueue({ source, category })`. Overrides apply to individual child runs only and do not propagate to grandchildren.
746765
9. **Fan-out target resolution**: `target` in `emit.enqueue()` is resolved as a file path relative to CWD (same as `--script`). Target resolution semantics may change in a future release; config-based logical names are under consideration.
747766

@@ -810,6 +829,10 @@ processing after runs complete, see [docs/guides/integration.md](docs/guides/int
810829
`--adapter redis` publishes to a Redis pub/sub channel after each run completes.
811830
See adapter flags above.
812831

832+
**Event sinks** (v0.13.0+): `--event-sink redis` streams every event to a Redis
833+
Stream in real time during the run. Can be combined with adapters for both
834+
real-time event streaming and post-run notification.
835+
813836
**Fallback pattern**: Polling-based triggers with idempotent checkpoints.
814837

815838
---
@@ -818,7 +841,7 @@ See adapter flags above.
818841

819842
```bash
820843
quarry version
821-
# 0.12.2 (commit: ...)
844+
# 0.13.0 (commit: ...)
822845
```
823846

824847
SDK and runtime versions must match (lockstep versioning).
@@ -827,8 +850,8 @@ SDK and runtime versions must match (lockstep versioning).
827850

828851
| Component | Channel | Install |
829852
|-----------|---------|---------|
830-
| CLI binary | GitHub Releases | `mise install github:pithecene-io/quarry@0.12.2` |
831-
| Container (full, amd64) | GHCR | `docker pull ghcr.io/pithecene-io/quarry:0.12.2` |
832-
| Container (slim, multi-arch) | GHCR | `docker pull ghcr.io/pithecene-io/quarry:0.12.2-slim` |
853+
| CLI binary | GitHub Releases | `mise install github:pithecene-io/quarry@0.13.0` |
854+
| Container (full, amd64) | GHCR | `docker pull ghcr.io/pithecene-io/quarry:0.13.0` |
855+
| Container (slim, multi-arch) | GHCR | `docker pull ghcr.io/pithecene-io/quarry:0.13.0-slim` |
833856
| SDK | JSR | `npx jsr add @pithecene-io/quarry-sdk` |
834857
| SDK | GitHub Packages | `pnpm add @pithecene-io/quarry-sdk` |

docs/CLI_PARITY.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "0.12.2",
2+
"version": "0.13.0",
33
"description": "CLI flag/config parity artifact. Machine-checkable source of truth for CLI flags.",
44
"commands": {
55
"run": {

docs/guides/configuration.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,26 @@ See `docs/guides/proxy.md` for pool configuration format and selection behavior.
116116

117117
See `docs/guides/integration.md` for adapter usage patterns.
118118

119+
### Event Sinks (Real-Time Event Delivery)
120+
121+
| Flag | Type | Default | Purpose |
122+
|------|------|---------|---------|
123+
| `--event-sink` | string (repeatable) | | Event sink type (`lode`, `redis`) |
124+
| `--event-sink-lode-delivery` | string | `mandatory` | Delivery mode for Lode event sink |
125+
| `--event-sink-redis-url` | string | | Redis URL (required when `--event-sink` includes `redis`) |
126+
| `--event-sink-redis-stream-key` | string | `quarry:events` | Redis Streams key |
127+
| `--event-sink-redis-max-len` | int | `100000` | Max stream length (-1 disables trimming) |
128+
| `--event-sink-redis-ttl` | duration | `24h` | Stream key expiry (-1 disables) |
129+
| `--event-sink-redis-timeout` | duration | `2s` | Per-operation timeout |
130+
| `--event-sink-redis-retries` | int | `2` | Retry attempts |
131+
| `--event-sink-redis-delivery` | string | `mandatory` | Delivery mode for Redis event sink |
132+
133+
Event sinks receive events in real time during a run (unlike adapters, which
134+
fire once after a run completes). When no `--event-sink` flags are set, events
135+
go to Lode only (default behavior). Each sink declares a delivery mode:
136+
`mandatory` (failure may fail the run) or `best_effort` (failure logged,
137+
run continues). See `docs/contracts/CONTRACT_INTEGRATION.md` for semantics.
138+
119139
### Fan-Out (Derived Work Execution)
120140

121141
| Flag | Type | Default | Purpose |
@@ -328,6 +348,21 @@ adapter:
328348
Authorization: Bearer ${WEBHOOK_TOKEN}
329349
timeout: 10s
330350
retries: 3
351+
352+
# Event sinks for real-time event delivery (v0.13.0+).
353+
# When absent, events go to Lode only (default behavior).
354+
# events:
355+
# sinks:
356+
# - type: lode
357+
# delivery: mandatory
358+
# - type: redis
359+
# delivery: best_effort
360+
# url: redis://localhost:6379
361+
# stream_key: quarry:events
362+
# max_len: 100000
363+
# ttl: 24h
364+
# timeout: 2s
365+
# retries: 2
331366
```
332367

333368
### Environment Variable Expansion

docs/guides/container.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ Quarry ships two container images via GHCR:
1111

1212
| Image | Tag | Arch | Includes |
1313
|-------|-----|------|----------|
14-
| Full | `ghcr.io/pithecene-io/quarry:0.12.2` | amd64 | Quarry CLI, Node.js, Puppeteer, Chrome for Testing, fonts |
15-
| Slim | `ghcr.io/pithecene-io/quarry:0.12.2-slim` | amd64, arm64 | Quarry CLI, Node.js, Puppeteer (no browser) |
14+
| Full | `ghcr.io/pithecene-io/quarry:0.13.0` | amd64 | Quarry CLI, Node.js, Puppeteer, Chrome for Testing, fonts |
15+
| Slim | `ghcr.io/pithecene-io/quarry:0.13.0-slim` | amd64, arm64 | Quarry CLI, Node.js, Puppeteer (no browser) |
1616

1717
The **full** image is recommended for standalone usage. The **slim** image is
1818
for environments where Chromium is provided externally (e.g., via
@@ -34,7 +34,7 @@ and run as a non-root `quarry` user.
3434
docker run --rm \
3535
-v ./scripts:/work/scripts:ro \
3636
-v ./data:/work/data \
37-
ghcr.io/pithecene-io/quarry:0.12.2 \
37+
ghcr.io/pithecene-io/quarry:0.13.0 \
3838
run \
3939
--script ./scripts/my-script.ts \
4040
--run-id "run-$(date +%s)" \
@@ -50,7 +50,7 @@ docker run --rm \
5050
```yaml
5151
services:
5252
quarry:
53-
image: ghcr.io/pithecene-io/quarry:0.12.2
53+
image: ghcr.io/pithecene-io/quarry:0.13.0
5454
volumes:
5555
- ./scripts:/work/scripts:ro
5656
- ./data:/work/data
@@ -71,7 +71,7 @@ services:
7171
```yaml
7272
services:
7373
quarry:
74-
image: ghcr.io/pithecene-io/quarry:0.12.2
74+
image: ghcr.io/pithecene-io/quarry:0.13.0
7575
volumes:
7676
- ./scripts:/work/scripts:ro
7777
environment:
@@ -99,7 +99,7 @@ services:
9999
- "6379:6379"
100100

101101
quarry:
102-
image: ghcr.io/pithecene-io/quarry:0.12.2
102+
image: ghcr.io/pithecene-io/quarry:0.13.0
103103
depends_on:
104104
- redis
105105
volumes:
@@ -135,7 +135,7 @@ executor where to find them:
135135
```yaml
136136
services:
137137
quarry:
138-
image: ghcr.io/pithecene-io/quarry:0.12.2
138+
image: ghcr.io/pithecene-io/quarry:0.13.0
139139
volumes:
140140
- ./scripts:/work/scripts:ro
141141
- ./node_modules:/work/node_modules:ro
@@ -167,7 +167,7 @@ services:
167167
- "9222:9222"
168168
169169
quarry:
170-
image: ghcr.io/pithecene-io/quarry:0.12.2-slim
170+
image: ghcr.io/pithecene-io/quarry:0.13.0-slim
171171
depends_on:
172172
- chrome
173173
volumes:

docs/guides/integration.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,69 @@ adapter:
183183
retries: 3
184184
```
185185
186+
### Redis Streams Event Sink (v0.13.0+)
187+
188+
Unlike the adapters above, which fire once after a run completes, the Redis
189+
Streams **event sink** publishes every event in real time as the executor
190+
produces it. This enables downstream consumers to watch events across all
191+
runs on a single stream.
192+
193+
```bash
194+
quarry run \
195+
--script ./script.ts \
196+
--run-id run-001 \
197+
--source my-source \
198+
--storage-backend fs \
199+
--storage-path ./data \
200+
--event-sink lode \
201+
--event-sink redis \
202+
--event-sink-redis-url redis://localhost:6379
203+
```
204+
205+
Each event is published via `XADD` with flat fields: `run_id`, `event_type`,
206+
`seq`, `timestamp`, `source`, `category`, and `payload` (JSON-encoded).
207+
208+
#### Event Sink vs Adapter
209+
210+
| | Event Sink | Adapter |
211+
|---|---|---|
212+
| **Timing** | During run (real-time) | After run completes |
213+
| **Events** | Every event | Single `run_completed` summary |
214+
| **Failure** | Configurable (`mandatory` or `best_effort`) | Always best-effort |
215+
| **Transport** | Redis Streams (`XADD`) | Redis Pub/Sub (`PUBLISH`) or HTTP POST |
216+
| **Flags** | `--event-sink` | `--adapter` |
217+
218+
Both can be used together in the same run.
219+
220+
#### YAML Config Example
221+
222+
```yaml
223+
events:
224+
sinks:
225+
- type: lode
226+
delivery: mandatory
227+
- type: redis
228+
delivery: best_effort
229+
url: redis://localhost:6379
230+
stream_key: quarry:events
231+
max_len: 100000
232+
ttl: 24h
233+
```
234+
235+
#### Event Sink Options
236+
237+
| Flag | Default | Description |
238+
|------|---------|-------------|
239+
| `--event-sink-redis-stream-key` | `quarry:events` | Shared stream key |
240+
| `--event-sink-redis-max-len` | `100000` | Approximate stream cap (-1 disables) |
241+
| `--event-sink-redis-ttl` | `24h` | Key expiry (-1 disables) |
242+
| `--event-sink-redis-timeout` | `2s` | Per-operation timeout |
243+
| `--event-sink-redis-retries` | `2` | Retry attempts with exponential backoff |
244+
| `--event-sink-redis-delivery` | `mandatory` | `mandatory` or `best_effort` |
245+
246+
See `docs/contracts/CONTRACT_INTEGRATION.md` §Event Sink Model for full
247+
semantics.
248+
186249
### Interim Pattern (v0.4.x)
187250

188251
Before v0.5.0, use a shell wrapper to trigger downstream notifications:

quarry/executor/bundle/executor.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env node
2-
// Quarry Executor Bundle v0.12.2
2+
// Quarry Executor Bundle v0.13.0
33
// This is a bundled version for embedding in the quarry binary.
44
// Do not edit directly - regenerate with: task executor:bundle
55

@@ -332,7 +332,7 @@ var CONTRACT_VERSION, TerminalEventError, SinkFailedError, StorageFilenameError,
332332
var init_dist = __esm({
333333
"../sdk/dist/index.mjs"() {
334334
"use strict";
335-
CONTRACT_VERSION = "0.12.2";
335+
CONTRACT_VERSION = "0.13.0";
336336
TerminalEventError = class extends Error {
337337
constructor() {
338338
super("Cannot emit: a terminal event (run_error or run_complete) has already been emitted");

quarry/types/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ package types
55
// per the lockstep versioning policy.
66
//
77
// This version is authoritative. Contract docs must reference this constant.
8-
const Version = "0.12.2"
8+
const Version = "0.13.0"

sdk/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pithecene-io/quarry-sdk",
3-
"version": "0.12.2",
3+
"version": "0.13.0",
44
"type": "module",
55
"publishConfig": {
66
"registry": "https://npm.pkg.github.com"

sdk/src/types/events.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Event envelope and payload types per CONTRACT_EMIT.md
33
*/
44

5-
export const CONTRACT_VERSION = '0.12.2' as const
5+
export const CONTRACT_VERSION = '0.13.0' as const
66
export type ContractVersion = typeof CONTRACT_VERSION
77

88
/** Branded type for run identifiers */

0 commit comments

Comments
 (0)