Stream changes from your prooph board event model to your terminal, and run a command — usually an AI coding agent — for every change.
You model a feature on prooph board (even from your phone). The moment you save a change,
spec-stream receives it in real time and runs the command you configured — kicking off
an agent to implement the spec, regenerate docs, notify your team, or anything else.
prooph board change ──▶ realtime event ──▶ spec-stream ──▶ your command / AI agent
Status: beta. The CLI is implemented and covered by an automated test suite, and our first end-to-end tests against a live prooph board workspace confirmed it works — realtime events trigger commands, and own-write filtering behaves as designed. APIs and config may still change before a stable
1.0release. Feedback and issues welcome.
- Spec-driven, continuously. Write a spec in a sticky note; an agent starts working when you save.
- Work from anywhere. Edit the board on mobile while away — agents run on your machine or a server.
- Lightweight. A tiny, dependency-minimal CLI. No framework, no daemon manager required.
- Controllable. Decide exactly which events trigger which commands, and how to queue, debounce, dedupe, or batch them so agents don't collide.
- Node.js ≥ 18 (≥ 20 recommended).
- A prooph board API key for the workspace you want to stream. Create one in prooph board (Settings → API Keys). It looks like
pb_1a2b3c….
spec-stream is a CLI you can run directly with npx — no install step required:
npx @proophboard/spec-stream --helpTo pin a version (recommended while in beta):
npx @proophboard/spec-stream@latest runOr install it globally / as a project dev dependency if you prefer:
# global
npm install -g @proophboard/spec-stream
spec-stream --help
# project (dev dependency)
npm install --save-dev @proophboard/spec-stream
npx spec-stream --helpRequires Node.js ≥ 18. The package ships as ESM.
export PROOPHBOARD_API_KEY="pb_xxxxxxxxxxxxxxxx"
# or put it in a .env file (see below)Scaffold one instantly with:
npx @proophboard/spec-stream initThis writes a starter proophboard.spec-stream.json into the current directory with an
example echo rule you can edit. (Use init --force to overwrite an existing file.)
Or create it by hand:
{
"endpoint": "https://flow.prooph-board.com/api",
"rules": [
{
"on": "element-description-changed",
"run": "echo \"Spec changed for $SPEC_STREAM_ELEMENT_NAME\"",
"concurrency": { "key": "element", "mode": "debounce", "wait": 5000 }
}
]
}This runs your command whenever a sticky note's description changes, collapsing rapid edits to the same note into a single run.
npx @proophboard/spec-streamYou'll see a live log of connections, incoming events, and command runs. Press Ctrl-C to stop. Now edit an element description on your board and watch the command fire.
{
"endpoint": "https://flow.prooph-board.com/api",
"maxConcurrent": 3,
"rules": [
{
"id": "implement-spec",
"on": ["element-description-changed", "element-details-changed"],
"when": { "elementType": ["command", "ui", "event"] },
"run": "claude -p \"Implement the spec for '$SPEC_STREAM_ELEMENT_NAME'. Full event on stdin.\"",
"cwd": "./",
"concurrency": { "key": "element", "mode": "debounce", "wait": 8000, "max": 1 }
},
{
"id": "build-planned-slice",
"on": "slice-status-changed",
"when": { "data": { "newValue.status": ["planned"] } },
"run": "claude -p \"Build the slice $SPEC_STREAM_SLICE_ID. Full event on stdin.\"",
"cwd": "./",
"concurrency": { "key": "slice", "mode": "queue", "max": 1 }
}
]
}- The first rule reacts to specs on
command/ui/eventelements. - Rapid re-saves of the same element collapse into one agent run (
debounce). - The same element is never worked on by two agents at once (
key: element,max: 1), but different elements run in parallel — up tomaxConcurrent. - The second rule shows a common workflow: when you flip a slice's status to
plannedon the board, a build agent starts implementing it. Thewhen.datafilter matches the new status in the event payload (newValue.status), so only theplannedtransition fires — not every status change.when.datacan match any field in the event by dot-path.
Your command receives the change as SPEC_STREAM_* environment variables and the full
event as JSON on stdin. See docs/command-context.md.
Foreground is the default (like tail -f). To run detached:
spec-stream start # start in the background (writes a PID file)
spec-stream status # is it running? connection + counters
spec-stream logs -f # follow the log
spec-stream stop # graceful stop (waits for running commands to finish)For servers, run the foreground command under systemd/Docker and let the manager handle
restarts. See docs/background-mode.md.
# .env
PROOPHBOARD_API_KEY=pb_xxxxxxxxxxxxxxxx
- Node ≥ 20.6:
node --env-file=.env …(orspec-streamloads it automatically when present). - Older Node: install the optional
dotenvdependency.
.env is already git-ignored in this project. Never commit your API key, and never
put it in proophboard.spec-stream.json.
Any prooph board changelog event — element-description-changed,
element-details-changed, element-added, element-renamed, element-comment-added,
slice-added, chapter-added, and ~40 more. Use a single type, a list, or "*".
The full catalog with payloads is in docs/event-reference.md.
The most useful for spec-driven automation are usually element-description-changed and
element-details-changed.
The key feature for automation is deciding when commands run so agents don't fight over the same work:
| Mode | Use it when |
|---|---|
parallel |
Independent side effects (notifications). |
queue |
Every change matters; process one at a time per key. |
debounce |
A spec is being edited; collapse a burst into one run. |
dedupe |
Avoid duplicate long-running jobs on the same target. |
batch |
Coalesce many related changes into a single pass. |
Combined with a concurrency key (element, slice, chapter, global, or a custom
template), this gives precise control. Full guide with timelines:
docs/concurrency.md.
If your triggered agents write back to the board (via the prooph board API/MCP using the
same key), those changes would themselves be changelog events. By default, spec-stream
ignores events made by its own API-key user, so an agent never re-triggers itself.
- This is automatic — no configuration needed.
- Opt a rule back in with
"consumeOwnEvents": trueif you do want it to react to its own user's changes. - Your commands also receive
SPEC_STREAM_SELF_USER_ID/SPEC_STREAM_SELF_EMAILso they can distinguish their own writes.
Once running, spec-stream stays up until you stop it:
- Command errors never stop the stream — they're logged and the loop continues.
- Connection drops trigger reconnection with capped exponential backoff (up to every 30 minutes, retrying indefinitely) and a 30s health check.
- Missed events during a disconnect are replayed on reconnect.
- Invalid startup config (missing key, bad config) fails fast with a clear message — the one case where it exits on purpose.
Details: docs/reconnection.md.
- The API key is a secret: env/
.envonly, never in config, never logged (redacted). - Invoked commands inherit
PROOPHBOARD_API_KEY. Commands run with spec-stream's full environment, so every command (and its subprocesses) can read the API key. This is handy for agents that write back to prooph board, but means you should only run trusted commands and prefer a read-only key. Seedocs/command-context.md. - Configured commands run with your privileges. The config file controls what gets executed — treat it as trusted and review rules before running.
- Event data is untrusted (anyone who can edit the board produces it).
spec-streampasses values as discrete env vars and JSON stdin rather than interpolating them into a shell. If yourrunstring embeds values, quote them, or use the safercommand+argsform (shell: false).
Every option is documented in docs/config-schema.md. Paths
(config discovery, logs, PID file) are in docs/paths.md.
spec-stream exchanges your pb_… API key for a short-lived access token via prooph
board's token endpoint (no long-lived refresh token — the key stays the single
credential, so revoking it stops the stream), then subscribes to your workspace's
realtime changelog stream. Matching events are routed through a scheduler
(queue/debounce/dedupe/batch) and executed as child processes.
The full architecture is in AGENT.md and docs/.
spec-stream can mirror your entire prooph board workspace into a local file tree and
keep it up to date in near-realtime from the same changelog stream it already consumes.
AI agents can then read the model with plain filesystem tools (grep, glob, cat) instead
of making API calls.
With the optional sync-back command, edits to the local file tree are pushed back to prooph board — making the sync fully two-way:
prooph board ──▶ spec-stream run ──▶ .spec-stream/model/ (kept live)
│
agent edits files ─┘
│
spec-stream sync-back ──▶ prooph board
sync-back works standalone — no git required.
Add a localSync block to your proophboard.spec-stream.json:
{
"endpoint": "https://flow.prooph-board.com/api",
"localSync": {
"enabled": true,
"dir": ".spec-stream/model"
},
"rules": []
}On the next spec-stream run (or start), it fetches the full workspace via the REST
API, writes the initial file tree, then applies every incoming changelog event
incrementally. Restarts catch up on missed events automatically.
.spec-stream/
sync-state.json # resume cursor (do not edit)
model/
workspace.json
uuid-index.json # flat { uuid → "relative/dir" } for fast id resolution
chapters/
[Context]/
[Chapter name]/
chapter.json
index.md # generated slice summary
slices/
[index]_[Slice]/
slice.json
details.md
lanes/
[laneType]/
[Lane]/
elements/
[index]_[Element]/
element.json
description.md
details.md
play-function.ts # if set
play-type.ts # if set
scenarios/
[Scenario name]/
scenario.json # Exploration Mode scenario
element-details/ # canonical shared details (one per name+type+context)
lane-details/ # canonical shared lane details
milestones/
[Milestone]/
milestone.json
description.md
Every .json carries the raw values (names, ids). Directory names use sanitized
slugs — safe for all filesystems and easy to grep. UUIDs are not embedded in paths;
uuid-index.json maps every entity UUID to its directory for O(1) resolution. Use
@proophboard/spec-stream sync --rebuild to force a full rebuild from the REST API at any time.
Run sync-back any time you want to push local edits back to the board — after an agent
finishes, before a deploy, or on demand:
npx @proophboard/spec-stream sync-backPreview what would be synced without making any changes:
npx @proophboard/spec-stream sync-back --dry-run --verboseYou can also wire it into a git pre-commit hook if you want automatic sync on every commit:
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/sh
npx @proophboard/spec-stream sync-back
EOF
chmod +x .git/hooks/pre-commitIf the sync fails, the hook aborts the commit so API errors are caught early.
After editing model files, run a structural consistency check before pushing:
npx @proophboard/spec-stream model validateThis checks all .json files for syntax errors, missing required fields, and dangling
UUID references (element laneId/sliceId, scenario expectation sliceId/elementId).
Exits 0 if clean, 1 with a per-issue report if not. Add --verbose to see every
checked path.
MODEL_SCHEMA.md at the repo root is a compact reference document
describing the full file tree layout, every JSON schema, and the play-function.ts /
play-type.ts / scenario.json conventions. It is designed to be loaded as a skill or
system-prompt context for AI agents so they can read and write the local model correctly
without trial and error:
- What each file means and which ones are editable
- JSON field names, types, and allowed values for every entity
- How to write a scenario from scratch, step by step
- How
sync-backtranslates file edits into API calls
Full details in docs/sync-back.md.
Full layout details, the event→mutation table, and convergence guarantees are in
docs/local-sync.md.
AGENT.md— idea + overall architecture (start here to contribute).docs/— architecture, auth, config, events, concurrency, logging, paths, reconnection, background mode, and the prooph board dependency.docs/local-sync.md— local model sync: layout, event→mutation table, convergence.docs/sync-back.md— two-way sync: pushing local edits back to prooph board.
MIT © prooph board