stage-signal
A tiny, harness-agnostic stage lifecycle CLI for agent orchestrators.
Coding agents run for a long time. Something else usually has to notice when a stage of work finished, failed, or got stuck waiting on the outside world — then start the next stage, pause, or alert a human.
stage-signal is that boring contract: a small CLI + on-disk status file that the agent writes and an orchestrator reads. No TUI scraping. No “it said done in the chat.” Just files, exit codes, and a few commands.
The job
Typical loop:
- An orchestrator (cron job, bot, CI step, shell watchdog) starts a coding agent on one milestone.
- The agent calls
stage-signal startwhen it begins that milestone. - While working, it may
heartbeat. - When finished it calls
stage-signal done(orblocked/failif it cannot finish cleanly). - The orchestrator polls
stage-signal statusorwaiton a timer — then enqueues the next milestone or stops.
So: agents produce machine-readable stage signals; orchestrators consume them.
This is intentionally not a full multi-agent cockpit, not a test proof system, and not tied to one coding product. It is a filesystem API with a thin CLI.
States
| State | Meaning |
|---|---|
queued |
Stage reserved, process not started |
running |
Agent claimed the stage |
done |
Stage completed successfully |
blocked |
Cannot proceed without an external fix (auth, quota, human decision, missing secret, …) |
failed |
Hard failure (crash, red tests, broken invariant) |
Terminal states for a given attempt: done, blocked, failed.
Install
From PyPI (once 0.1.0 is published):
python3 -m venv .venv
source .venv/bin/activate
pip install stage-signal
stage-signal --help
System Python on macOS refuses bare pip install (PEP 668, "externally
managed") — always use a venv as above.
From source (contributors):
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]" # installs the `stage-signal` entry point + tests
stage-signal --help
python -m pytest # all green
python3.11+ with stdlib only — no third-party runtime dependencies.
python -m stage_signal … works as an alias for the stage-signal command.
Quick start
# in your project
stage-signal init
# agent side
stage-signal start --stage impact-clarity --session "$SESSION_ID" --pid $$
stage-signal heartbeat
stage-signal done --summary "merged abc123" --git-head abc123
# or: stage-signal blocked --reason "..." / stage-signal fail --reason "..."
# orchestrator side
stage-signal status --json
stage-signal wait --state terminal --timeout 900
On-disk layout (default):
.stage-signal/
STATUS.json # current snapshot (normative)
STATUS.md # human mirror (best-effort, never normative)
events.jsonl # append-only history
locks/stage.lock # fcntl lock for read-modify-write cycles
Exact schema and exit codes: see docs/SPEC.md (normative) and
docs/PRIOR_ART.md (background).
status / wait exit codes are part of the contract: 0 done/OK,
1 generic/corrupt, 10 running, 11 blocked, 12 failed, 13 queued,
14 wait timeout, 15 not initialized, 2 bad args, 3 illegal transition.
start --meta is repeatable and accepts two forms per entry (merged in
order, later wins):
stage-signal start --stage demo --meta owner=OpenLoop --meta '{"ticket": 42, "flag": true}'
K=V— value kept as a string (value may contain=;K=is empty).- A raw JSON object string — JSON types (numbers, bools, null, nested objects/arrays) are preserved.
- Bare words, malformed JSON, and non-object JSON exit
2with no mutation.
Minimal orchestrator loop (cron, bot, CI step, shell): see
examples/orchestrator-watchdog.sh — it only calls
stage-signal status --json / stage-signal wait and exits with the
observed-state code above. Acceptance sequence: examples/orchestrator-smoke.sh.
Multi-stage queues (same contract, one dir walked against a queue file):
examples/queue-orchestrator.sh --queue examples/sample-queue.md [--dir PATH] [--once]
— done advances (exit 0), blocked/failed stop with 11/12,
running/queued wait (or exit 10/13 with --once for cron).
Smoke: examples/queue-orchestrator-smoke.sh.
What this is / isn’t
Is
- A clear stage lifecycle for overnight or unattended agent loops
- Readable by any language that can open a JSON file
- Usable from cron, bots, CI, or a human shell
Is not
- A replacement for git, CI, or issue trackers
- A multi-agent worktree / DAG orchestrator (use tools like ruah / similar if you need that)
- A proof-of-test gate (compose with something like agent-done-or-not if you need tamper-evident receipts before declaring success)
Why not scrape the agent UI?
Agent UIs and chat transcripts are for humans. Orchestrators need a stable, boring interface:
- Did this stage end?
- How did it end?
- Is the process still alive (heartbeat)?
- What git head / artifacts should the next stage assume?
stage-signal answers those without depending on one vendor’s session format.
Status
0.1.0: library (src/stage_signal/), full CLI (init, start,
heartbeat, note, artifact, done, blocked, fail, status,
wait, clear-terminal, doctor), unit + concurrency tests,
examples/orchestrator-watchdog.sh (+ examples/orchestrator-smoke.sh),
examples/queue-orchestrator.sh (+ examples/sample-queue.md,
examples/queue-orchestrator-smoke.sh), CI (.github/workflows/ci.yml:
pytest + both smokes + packaging check via python -m build /
twine check, no upload). Contract: SPEC v1.
Docs
docs/SPEC.md— normative contract (schema, CLI, exit codes)docs/COMPOSE.md— proof interop (--proof-ref/--require-proof)docs/RELEASE.md— release procedure (manual; no upload from agent loops)docs/PRIOR_ART.md— background researchCHANGELOG.md— release notes
Prior art
We researched existing tools before writing this. Short version: several systems solve adjacent problems (verification receipts, process presence, full multi-agent orchestration). The niche here is a small stage lifecycle aimed at external watchdogs. Details: docs/PRIOR_ART.md.
License
MIT — see LICENSE.
Contributing
Issues and PRs welcome. Keep the scope small: lifecycle signals, not a platform.
Release files for stage-signal 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| stage_signal-0.1.0.tar.gz | 25.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| stage_signal-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 45.3 kB
Release files / stage_signal-0.1.0.tar.gz
| Download URL | stage_signal-0.1.0.tar.gz |
|---|---|
| Size | 25.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cd19248d2ca329c716803cc1a3f82e92c91bca0f9b63c3bc8256854ffb3ade95
|
|
BLAKE2b-256 checksum How to use checksums |
dc651b7b30964c774ab802863be25a17e6157df18c1d2bdd131bf8f5561fcf32
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.
Transparency logRelease files / stage_signal-0.1.0-py3-none-any.whl
| Download URL | stage_signal-0.1.0-py3-none-any.whl |
|---|---|
| Size | 19.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4d7bca7d95cbdb99dc4826fbbea6d8cfbf846b1ff22c18a73591c917000349df
|
|
BLAKE2b-256 checksum How to use checksums |
f4c25da20e1c444072cb5b2511dc97e911560fee316e8ed3246cc069463e76ab
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.
Transparency log