Skip to main content

keepwatch

Keep work alive when the process that started it is not. A 300-line, zero-dependency ledger for agents that run unattended.

ci pypi python


The problem

An unattended pipeline does not fail loudly. It goes quiet:

  • a task sits in pending/ and nobody claims it
  • a worker dies mid-task and the task is stuck in processing/ forever
  • a worker finishes but never marks it done, so the next round re-dispatches it
  • the agent says "all tests pass" and you have nothing to check that against

All four look identical from the outside: nothing happened, and the logs are clean.

What it does

Three folders, one ledger, four verbs.

<root>/agents/<agent>/pending/      tasks a worker can pick up
<root>/agents/<agent>/processing/   tasks someone is holding (with a lease)
<root>/agents/<agent>/done/         closed tasks, never deleted
<root>/audit/YYYY-MM.jsonl          append-only record of everything
Verb Meaning
check what can I pick up
claim take one, and hold a lease on it
done close it — only if a passing verify record exists
verify record a check result (--rc 0) against a task
run claim → run a command → record its exit code → close or release
doctor deterministic self-check, exit 0 when healthy
checkpoint write a resume note: what is stuck, what to run next
pipeline open or close the gate for new work (exit 14 when closed)

Plus send, renew, release, reap, status.

The one command you actually need

keepwatch run --who builder -- python -m pytest

That does the whole loop in one go:

  1. claims the oldest pending task (or --id <id>)
  2. runs the command with inherited stdio, so you still see the output
  3. writes verify ... --rc <real exit code> into the ledger
  4. rc=0 → done; rc!=0 → back to pending for another try
  5. after --max-tries (default 3) failures → left in processing with a suspect record

If the process is killed mid-command, nothing is lost: the lease expires and reap puts the task back. You do not have to remember to write the ledger — the wrapper does it.

Why it matters

claim starts a lease. If the worker dies, the lease expires and reap puts the task back with a trail (tries, prev_owners). No task is ever stranded, and no task is silently done twice.

done refuses to close a task unless the ledger holds a verify ... rc=0 for it. That is the whole point: the model can say "it passed"; the ledger is what proves it.

$ keepwatch done --who builder --id 20261023T083729-8c4fae
keepwatch: refusing to close 20261023T083729-8c4fae: no verify record with rc=0.
Run `verify --id ... --name <check> --rc 0` first, or pass --force.
$ echo $?
13

Install

Python 3.9+, no dependencies.

pip install keepwatch

From a checkout instead:

pip install -e .
PYTHONPATH=src python -m keepwatch.cli --help

60-second demo

keepwatch --root /tmp/ns init builder reviewer

keepwatch --root /tmp/ns send \
  --from reviewer --to builder --subject "batch 3: add login page"

keepwatch --root /tmp/ns check --who builder
keepwatch --root /tmp/ns claim --who builder --id <id> --ttl 60

Now pretend the worker dies. Wait for the lease, then:

$ keepwatch --root /tmp/ns status
root: /tmp/ns
  builder        pending 0  processing 1  done 0  hb 61s (alive)
  reviewer       pending 0  processing 0  done 0  never seen (unknown)
next:
  - builder: 20261023T083750-ef2c5d held by builder, 1s past its lease - run `reap`

$ keepwatch --root /tmp/ns reap
reaped 1 task(s)
  20261023T083750-ef2c5d  back to pending (tries=1)

$ keepwatch --root /tmp/ns claim --who builder --id 20261023T083750-ef2c5d
claimed 20261023T083750-ef2c5d (try 2) lease until 2026-10-23T08:42:31Z

The task came back with tries=1 and the previous owner recorded. Close it, but only after proof:

keepwatch --root /tmp/ns verify --id <id> --name pytest --rc 0
keepwatch --root /tmp/ns done   --who builder --id <id> --note "e2e green"

Exit codes

Exit codes are the interface; agents read them instead of parsing prose.

Code Meaning
0 ok
1 bad arguments, IO error
2 task not found / already taken
3 task held by another worker (or busy)
13 blocked: no passing verify, or status found something that needs attention

Design notes

Files are the source of truth. No database, no daemon, no network. ls and cat are the debugging tools.

Exclusive create is the mutex, not rename. On at least one Windows filesystem two concurrent os.replace() calls on the same source both report success. Claiming is therefore guarded by O_CREAT|O_EXCL on a short-lived token file. This is documented in docs/PROTOCOL.md because it cost a real bug to find.

One worker per agent box. Leases are per agent directory, so builder running two processes is a configuration error, not a supported mode.

status exits 13 when something needs attention — so keepwatch status || alert works in cron.

What it is not

  • not a mailbox (see docs/COMPETITION.md for what exists)
  • not an orchestrator: it never decides what to do next
  • not an agent: it makes no model calls
  • not durable execution: it will not replay your side effects

Docs

File Contents
docs/PROTOCOL.md layout, task format, lease rules, exit codes
docs/COMPETITION.md why this exists next to agent-mailbox / A2A / Temporal
docs/ROADMAP.md v0.1 → v1.0 and the release checklist
docs/zh/ 中文原文 (Chinese originals)

Tests: PYTHONPATH=src python -m unittest discover -s tests -v

License

MIT. See LICENSE.

Metadata

Release files for keepwatch 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for keepwatch 0.2.1
File Size Uploaded Provenance Actions
keepwatch-0.2.1.tar.gz 24.5 kB With provenance Details for keepwatch-0.2.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for keepwatch 0.2.1
File Interpreter ABI Platform Actions
keepwatch-0.2.1-py3-none-any.whl Python 3 none any Details for keepwatch-0.2.1-py3-none-any.whl

Total release size: 41.8 kB

Release files / keepwatch-0.2.1.tar.gz

Download URL keepwatch-0.2.1.tar.gz
Size 24.5 kB
Tags Source
SHA-256 checksum
How to use checksums
a02ae0b474ed0d35da970f206e5e22c715b17d9701c29d545643ed64c0cab8fc
BLAKE2b-256 checksum
How to use checksums
4f8e5f4e7344ae2597d61535387727229af43bcd9eeaf0b4f6124eb8cdde1166
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 Oct 26, 2026.

Transparency log

Release files / keepwatch-0.2.1-py3-none-any.whl

Download URL keepwatch-0.2.1-py3-none-any.whl
Size 17.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fd3ed834e044df90c13101235d006b76df477542e39595c3ae609658202221b5
BLAKE2b-256 checksum
How to use checksums
aff3a7742274652e3326b4606461242be1a06ad0beb620d05e0b117813e8b1d6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 Oct 26, 2026.

Transparency log

Security for keepwatch 0.2.1

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for keepwatch-0.2.1.tar.gz

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 Oct 26, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page