Skip to main content

Cadence

There are thousands of todo CLIs. Cadence is the one built for an AI agent to run as a first-class user, not a bolted-on chat wrapper on top of a human tool — and it turns git, which you already have installed, into the undo/history/audit/sync layer instead of building a bespoke (and weaker) version of all four.

What that buys you, concretely:

  • Hand your agent a messy brain-dump and get tracked subtasks back. cadence decompose 12 --into "book flights" "book hotel" "pack" (or the decompose_task MCP tool) turns one vague task into real, independently completable children — no more one giant to-do that never gets checked off.
  • Ask "why did this get bumped to top priority" and get a real answer. Every reprioritise, schedule, and edit is a git commit under the hood, so the answer is git log/git blame on your own task store, not a guess or a feature nobody built.
  • Undo a bad agent action instantly, with the same guarantee git gives your code. cadence undo reverts the last change — yours or your agent's — because it is a git revert, not a bespoke undo stack that only covers some operations.
  • Keep two devices' task lists in sync without running a server. cadence sync pulls and pushes against a git remote you already control (a repo, a USB stick, anything git can reach) — no account, no hosted backend, no uptime to worry about.

The plan is to publish Cadence as a public, installable, open-source project by 6 November 2026. That date is a delivery commitment, not an estimate.

Status

Published on PyPI as cadence-todo — install with pip install cadence-todo. It builds, runs, and is tested from a fresh clone, and CI is green on a clean GitHub-hosted runner (see the finish-line checklist below for what's still outstanding). See docs/bakeoff.md for the five candidate concepts we researched, the evidence behind each, and which one we chose and why, and docs/human-surface.md for the CLI's binding design spec.

Install

pip install cadence-todo

Every line below is a real CLI command, run yourself, no agent required — this is the whole bet: every change to your list, yours or an agent's, comes with a legible reason and a clean undo, because it's backed by the same git you already trust for code, not a bespoke history feature Cadence invented and might get wrong. Real output, cadence-todo 0.2.9, NO_COLOR=1:

$ cadence add "Plan Mara's 30th birthday party"
Added #1: Plan Mara's 30th birthday party

$ cadence decompose 1 --into "Book a venue" "Order a cake" "Send invites"
Decomposed #1 into 3 subtasks: #2, #3, #4

$ cadence reprioritise 2 high --reason "venue books up fastest"
Reprioritised #2 (none → high): Book a venue

$ cadence why 2
#2 Book a venue — history (newest first):

  -  high     just now     Reprioritised (none → high)
                       "venue books up fastest" — you, via CLI

  -  none     just now     Created as subtask of #1 (Plan Mara's 30th birthday
                           party)

No reason was recorded for this change. Reasons are optional —
pass --reason "..." (CLI) or a `reason` argument (MCP tool call)
to leave one next time.

$ cadence undo
Undid: Reprioritised #2 (none → high) undone: Book a venue

That why line is the payoff: a straight answer to "why did this change," without you ever opening git, a hidden folder, or asking your agent to explain itself. cadence list and cadence done <id> work exactly the way you'd expect from any todo CLI — full command reference below.

By default tasks live in ~/.cadence/cadence.db (a local SQLite file) with a git-backed history alongside it. Set CADENCE_DB_PATH to point at a scratch file instead (used by the test suite and useful for an agent that wants an isolated store).

Start the MCP server (agent surface) over stdio, exposing tools such as add_task, list_tasks, complete_task, schedule_task, decompose_task, reprioritise_task, undo, and sync_tasks with structured JSON returns:

cadence mcp

Remote access (Claude web, Claude mobile, another machine)

cadence mcp (above) talks stdio, so only a local process on the same machine — e.g. Claude Code / VSCode — can reach it. If you also want Claude web or Claude on your phone to reach the same task store, run the HTTP transport instead:

cadence mcp --http

This is still local-first: it starts a server on your own machine (default 127.0.0.1:8765), backed by the exact same store as cadence mcp and the cadence CLI — there is no hosted backend, no account, no third party in the middle. It prints the port it's listening on and requires a bearer token on every request, generated once on first use and stored at ~/.config/cadence/mcp_http_token (owner-read/write only, same directory as the rest of Cadence's config). Get that token with:

cadence mcp --show-token

To use it from a remote client (Claude web/mobile, or an agent on another machine): expose the port to that client somehow — an SSH tunnel, Tailscale, or a TLS-terminating reverse proxy are all reasonable choices; Cadence does not add TLS itself — then configure the client with the resulting URL's /mcp path and an Authorization: Bearer <token> header carrying the token from cadence mcp --show-token. A request with a missing or wrong token gets a clean 401 with the same {"ok": false, "error", "message", "hint"} shape every other Cadence error uses, not a stack trace.

You can also pass --host, --port, or an explicit --token (or set CADENCE_MCP_TOKEN) to override the generated one, e.g. for a fixed token across restarts in a script.

Building from source

git clone https://github.com/dominicplouffe/Cadence.git
cd Cadence
pip install -e .
pip install pytest
pytest -q

Get Started

Three ways to point an agent at Cadence, depending on where that agent runs.

1. Claude Code / VSCode, running on the same machine (stdio)

This is the simplest path: the client starts cadence mcp itself as a subprocess, talks to it over stdio, and no network or token is involved.

pip install cadence-todo

Add it as a project-scoped MCP server, either with the CLI:

claude mcp add --transport stdio cadence -- cadence mcp

or by hand in .mcp.json at your project root:

{
  "mcpServers": {
    "cadence": {
      "type": "stdio",
      "command": "cadence",
      "args": ["mcp"]
    }
  }
}

Restart Claude Code (or reload the window) and it will list add_task, list_tasks, complete_task, schedule_task, decompose_task, reprioritise_task, why_task, undo, sync_tasks, export_tasks, and register_project as available tools.

2. Claude web or Claude on your phone (HTTP transport, over a tunnel)

Claude web and mobile can't spawn a local process on your machine, so they need to reach Cadence over HTTPS instead. Run the HTTP transport locally:

cadence mcp --http

This starts a server on 127.0.0.1:8765 — still on your own machine, still backed by the same store as the CLI and the stdio server, no hosted backend. It requires a bearer token on every request (cadence mcp --show-token to print it). By itself this is only reachable from localhost; you need a tunnel to get a real HTTPS URL a remote client can use. Do not run this with --host 0.0.0.0 — that exposes the port to your whole network with only the bearer token standing between it and anyone on that network; a tunnel keeps the port itself bound to 127.0.0.1 and only forwards over an authenticated HTTPS connection.

Cloudflare Quick Tunnel (no account needed, URL changes each run):

cloudflared tunnel --url http://127.0.0.1:8765

prints an HTTPS URL like https://some-random-words.trycloudflare.com. Configure the remote client with <that URL>/mcp and an Authorization: Bearer <token> header carrying the token from cadence mcp --show-token.

Tailscale Funnel is a reasonable alternative if you already run Tailscale on both machines and want a stable URL instead of a new one per run: tailscale funnel 8765 after cadence mcp --http is running.

Real transcript, cadence-todo 0.2.15, fresh install from PyPI, a live Cloudflare Quick Tunnel (not simulated):

$ pip install cadence-todo==0.2.15
$ cadence add "Verify README Get Started (0.2.15)"
Added #1: Verify README Get Started (0.2.15)
$ cadence mcp --http --port 8767
[cadence mcp --http] listening on http://127.0.0.1:8767/mcp -- bearer token required on every request
$ cloudflared tunnel --url http://127.0.0.1:8767
...
Your quick Tunnel has been created!
https://fastest-david-remedies-absent.trycloudflare.com

No token, over the tunnel — still a clean 401:

$ curl -sS -i https://fastest-david-remedies-absent.trycloudflare.com/mcp \
    -X POST -H "Content-Type: application/json" \
    -H "Accept: application/json, text/event-stream" \
    -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{...}}'

HTTP/2 401
{"ok":false,"error":"unauthorized","message":"Missing or wrong bearer token.","hint":"Send 'Authorization: Bearer <token>' matching the token this server was started with (see `cadence mcp --http --show-token`)."}

Correct token, over the tunnel — a real initialize response:

$ curl -sS -i https://fastest-david-remedies-absent.trycloudflare.com/mcp \
    -X POST -H "Content-Type: application/json" \
    -H "Accept: application/json, text/event-stream" \
    -H "Authorization: Bearer 29bd96fe9fd267b0f7cb33a188d947ce14267654be081e0d2ae44153dd660f9c" \
    -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"verify-client","version":"1.0"}}}'

HTTP/2 200
mcp-session-id: d77b4b16fe114b1eb85633a11f106834
content-type: text/event-stream

event: message
data: {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2025-06-18",
  "capabilities":{...},
  "serverInfo":{"name":"cadence","version":"1.29.1"},
  "instructions":"Cadence is a local-first todo store. ..."}}

A follow-up tool call over that same tunnel session lands in the real, local store — confirmed with a plain cadence list afterward, no difference between a task created locally and one created through the tunnel:

$ curl ... -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"add_task","arguments":{"title":"Confirmed via tunnel (README verify)"}}}'
HTTP/2 200
data: {"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"{\n  \"ok\": true,\n  \"task\": {\n    \"id\": 2,\n    \"title\": \"Confirmed via tunnel (README verify)\", ...}}"}],"isError":false}}

$ cadence list
  [ ]    1   Verify README Get Started (0.2.15)
  [ ]    2   Confirmed via tunnel (README verify)

3. More than one project

If you keep separate Cadence stores per project (separate CADENCE_DB_PATH values, e.g. one per git repo), register each one so the cross-project commands can find it:

$ cd ~/proj1 && cadence register
Registered /home/you/proj1/cadence.db (as 'proj1').

$ cd ~/proj2 && cadence add "File Q3 taxes"
Added #1: File Q3 taxes
$ cadence schedule 1 2026-01-01
Scheduled #1 for 2026-01-01: File Q3 taxes
$ cadence register
Registered /home/you/proj2/cadence.db (as 'proj2').

$ cadence overdue --all-projects
[!]  proj2       #1   File Q3 taxes                        |  overdue 242d
1 overdue across 2 registered projects. Run 'cadence register' in a project directory to add another.

cadence sync --all-projects works the same way — one call syncs every registered project's store against whatever remote it already has configured, instead of running cadence sync separately in each project directory. The MCP tool equivalents are register_project, overdue_tasks(all_projects=true), and sync_tasks(all_projects=true).

What "agentic-first" means here

  • Primary interface is agent-legible by design. An agent that has never read the docs should be able to work out what each tool does, what it returns, and what it did wrong, from the interface itself.
  • A human surface is not optional. A capability that exists only for agents is half-built, and so is one that exists only for humans.
  • Local-first bias. We prefer something a person installs with a single command and owns the data of, over a hosted multi-tenant web app.

The finish line

Three things must be true and independently checkable by someone outside this company, on or before the committed date:

  1. Published on a public package registry, installable with one command.
  2. CI on a clean GitHub-hosted runner goes green on the full suite, including an end-to-end test that installs the published artifact and drives it.
  3. A committed transcript exists of an agent with no access to this repository completing a fixed ten-step script using only the published package.

Contributing

Not yet open for external contributions — the project is pre-publication. Once published, this section will describe how to build from a fresh clone, run the test suite, and submit changes.

License

MIT — see LICENSE.

Metadata

Release files for cadence-todo 0.2.25

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

Source distribution (sdist)

Source distribution for cadence-todo 0.2.25
File Size Uploaded Provenance
cadence_todo-0.2.25.tar.gz 104.0 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for cadence-todo 0.2.25
File Interpreter ABI Platform
cadence_todo-0.2.25-py3-none-any.whl Python 3 none any Details

Total release size: 171.7 kB

Release files / cadence_todo-0.2.25.tar.gz

Download URL cadence_todo-0.2.25.tar.gz
Size 104.0 kB
Tags Source
SHA-256 checksum
How to use checksums
28a0e5e139ea5fb079a6ae92570e0ab35ee5e3f7a869d3b8e66d902afdd36c18
BLAKE2b-256 checksum
How to use checksums
a081eaaf7761f93475a6cf0c4683ac6be7d224a393efb74e20f0b46b8e19f2e0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.2

Release files / cadence_todo-0.2.25-py3-none-any.whl

Download URL cadence_todo-0.2.25-py3-none-any.whl
Size 67.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c1e0bd2722abd16cf5217fa997867b22189464334c834777eef604892f0fbaa2
BLAKE2b-256 checksum
How to use checksums
4764d7053b985e42a8df56a090e473c5b8c1d6967d3744772459b6e760d540d4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.2

Security for cadence-todo 0.2.25

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

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.

Release history Release notifications | RSS feed

This release

0.2.25 This release

2 release files No provenance

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