- Docs
- Tools
- Reactive
Tools
Reactive
Four primitives for turning one-shot pipelines into continuous ones – watch, listen, record, replay.
The four primitives
pluck.watch(uri, options); // poll → yield WatchEvent on every change
pluck.listen(uri, options); // poll + sense + fire a handler when a condition matches
pluck.record(uri, options); // run the pipeline AND save a deterministic trace
pluck.replay(tracePath); // re-run the pipeline from a trace, zero network
All four are first-class methods on PluckInstance. They compose: record a single run, replay it deterministically in CI, or watch a URI and compose each change event into a downstream action.
pluck.watch(uri) – change detection
Poll a URI at an interval, yield a WatchEvent whenever the content hash changes:
import { createPluck } from "@sizls/pluck";
const pluck = createPluck();
for await (const event of pluck.watch("https://status.example.com", {
interval: 10_000, // poll every 10 seconds
maxDuration: 60_000, // stop after 1 minute
})) {
switch (event.type) {
case "initial":
console.log("Baseline established:", event.result?.text.slice(0, 50));
break;
case "changed":
console.log("Content changed!", event.result?.text.slice(0, 200));
await slack.post("#alerts", `Status page updated: ${event.uri}`);
break;
case "unchanged":
// skipped – no alert noise
break;
case "error":
console.error("Poll failed:", event.error.message);
break;
case "stopped":
console.log("Watcher stopped gracefully.");
break;
}
}
The CLI equivalent is a one-liner:
pluck watch https://status.example.com --interval 30s --on-change "./alert.sh"
pluck watch is the reactive primitive for anything URL-based – status pages, pricing pages, news headlines, API responses. For signal-based watching (mic, video), use pluck.listen.
pluck.listen(uri, opts) – sense-triggered handlers
listen combines watch-style polling with sense-based condition evaluation. Fire a handler when a sense condition matches:
const stop = await pluck.listen("mic://input", {
on: { ultrasonic: { present: true } }, // fire when ultrasonic carrier is detected
interval: 5_000,
handler: async (event) => {
console.log("Ultrasonic carrier detected:", event.carrierHz);
await pluck.act("https://hooks.example/alert", {
action: "post",
input: { kind: "ultrasonic", carrierHz: event.carrierHz },
});
},
});
// Later:
await stop();
listen is the reactive primitive for signals. Detect infrasonic rumbles (seismic precursors / HVAC failures), ultrasonic beacons (cross-device tracking), DTMF tones (line monitoring), rPPG pulse changes. Every sensor from Concepts: Sense is available as a trigger condition.
pluck.record(uri) – capture a deterministic fixture
record runs the full pipeline AND writes a .plucktrace.json bundle with every intermediate phase output:
await pluck.record("https://news.ycombinator.com", {
out: "./fixtures/hn.plucktrace.json",
});
// Writes ./fixtures/hn.plucktrace.json with the complete run.
The CLI equivalent:
pluck record https://news.ycombinator.com -o ./fixtures/hn.plucktrace.json
Use it to seed CI fixtures. Run your pipeline once against live data, commit the fixture, then replay it deterministically forever.
pluck.replay(tracePath) – deterministic re-run
replay takes a .plucktrace.json and reproduces the pipeline run bit-for-bit – no network, no side-effects:
import { replay } from "@sizls/pluck";
const result = await replay("./fixtures/hn.plucktrace.json");
// Same result as the original run, same PluckResult shape.
result.output("markdown"); // works exactly as before
result.receipt; // same signed receipt if the original had one
The CLI equivalent is a one-liner:
pluck replay ./fixtures/hn.plucktrace.json
pluck replay ./fixtures/hn.plucktrace.json --format json
Use it for CI snapshot-testing: record once, replay in every commit, fail the build if the output shape changes.
Composing the four
The primitives compose into common patterns:
// Pattern 1 – watch + act: status page changes trigger a webhook.
for await (const event of pluck.watch(uri, { interval: 60_000 })) {
if (event.type === "changed") {
await pluck.act("https://hooks.example/status", {
action: "post",
input: { uri, diff: event.diff },
});
}
}
// Pattern 2 – record + replay: deterministic CI.
// (once) pluck record https://news.ycombinator.com -o ./fixtures/hn.plucktrace.json
// (CI) pluck replay ./fixtures/hn.plucktrace.json --strict
// Pattern 3 – listen + act: signal detection fires a real-world action.
await pluck.listen("mic://", {
on: { dtmf: { present: true } },
handler: async (event) => {
await pluck.act("postgres://ops/alerts", {
action: "insert",
input: { kind: "dtmf", digits: event.digits, at: event.startTime },
});
},
});
What's next
- Concepts: Sense – the sensor catalogue that
listenconsumes. - Studio – visualise recorded traces with time-travel scrubbing.
- Reference: CLI –
pluck watch,pluck listen,pluck record,pluck replay.