Skip to main content

docket

Docket banner

Test PyPI

Markdown tickets that live in your repo. You read them in a text editor or CLI. Your agent reads them over MCP.


Demo

Docket demo

Start Here

uv tool install ticket-docket  # or: pipx install ticket-docket
cd my-project
docket deploy .

This installs two commands: docket for you and docket-mcp for your agent.

Then add at least one project key to .docket.toml for your future tickets:

docket key add "CORE" "tactical-sim core"

Make your first ticket:

docket new CORE "Skirmish setup"

A Ticket

File: docs/tickets/todo/CORE-14_skirmishSetup.md

---
id: CORE-14
title: Skirmish Setup
status: todo
priority: 1
requires: [CORE-9, GEN-3]
metadata: {}
---

Goal: a screen where the player sets up one battle and plays it.
Field Notes
id <KEY>-<NUM>. Must match the filename prefix.
title Free text, converted to title case on write. Changing it does not rename the file.
status todo, wip, or done. Fixed vocabulary.
priority Integer, 0 most urgent. Ceiling configurable.
requires Ids this depends on. Never lists what it blocks.
metadata Additional freeform key:value pairs handled first-party.

Unknown fields are round-tripped untouched. Filenames are frozen at creation so prose cross-references never break.

CLI

A ticket id is the command:

docket CORE-14         # show it, dependency context and all, with the body rendered as Markdown
docket CORE-14 show --plain  # the same content as bare text, body left raw
docket CORE-14 done    # todo, wip, or done. The file follows
docket CORE-14 set [-t TEXT] [-p N] [-r A,B|none] [-ra A,B] [-rr A,B]
docket CORE-14 meta [KEY [VALUE]] [-c]

Every frontmatter field has an accessor that prints the value and nothing else, for a pipe:

docket CORE-14 title        # the title
docket CORE-14 status       # todo, wip, or done
docket CORE-14 priority     # the number
docket CORE-14 requires     # one id per line, nothing when empty
docket CORE-14 required-by  # the reverse direction, same shape
docket CORE-14 key          # CORE
docket CORE-14 ready        # true or false. Every dependency done?
docket CORE-14 body         # the raw Markdown body, no frontmatter
docket CORE-14 meta         # the whole map as JSON
docket CORE-14 meta KEY     # one value, bare, or JSON when it has structure

JSON is highlighted in a terminal and plain when piped, so docket CORE-14 meta | jq works as written.

Everything else works on the set:

docket new CORE "Skirmish setup" [-r CORE-9,GEN-3] [-p 1] [-b TEXT]
docket list [-s todo] [-k CORE] [-m 2] [-r]
docket graph [-i CORE-14 | -k GEN | -s todo] [-o FILE]
docket key list | add KEY "desc" [-r TEXT] | remove KEY
docket validate | deploy PATH | upgrade PATH
docket docs handoff [-p] [-o FILE]
docket docs roadmap [CORE-14 | GEN | todo] [-m N] [-p] [-o FILE]

docs writes a file: handoff.md and roadmap.md at the repo root. -p/--print sends it to stdout instead, -o picks another path, and passing both writes the file and prints it. graph is the exception, printing unless you ask for a file, because its output is usually piped.

docket docs roadmap is the committable picture of the graph: a markdown file wrapping a mermaid diagram, plus the legend a renderer that ignores styling would otherwise leave you without. Past maxRoadmapNodes it drops the completed tickets furthest from the work still open, and never drops an open ticket, so the diagram stays readable without losing what is ahead.

-r replaces the dependency list. -ra and -rr edit the one already there. Both in one call is refused.

A ticket is ready when every id in its requires names a ticket that is done. A missing dependency blocks, and a done ticket is never ready, so docket list -r is the set you can pick up right now.

Every short flag has a long form (-k/--key, -p/--priority, -m/--priority-max, and so on). --help lists your actual keys and priority range.

MCP

docket-mcp is a stdio server. Eleven tools, each returning JSON as text.

Tool Purpose
list_tickets(status?, key?, priority_max?) Summaries only, never bodies.
read_ticket(id) Full body plus both dependency directions.
check_ready(id) Whether every dependency is done, and what is blocking.
create_ticket(key, title, body?, requires?, priority?) Allocates the id, writes the file.
update_ticket(id, title?, priority?, requires?, requires_add?, requires_remove?) Those three fields only.
set_status(id, status) Writes frontmatter and moves the file together.
graph(id?, key?, status?) Mermaid source.
list_keys() The registered keys.
add_key(key, description, rationale) After the agent has asked the user.
validate() Structured findings.
set_metadata(id, key, value?) One entry at a time, leaving every other key alone.

Writing Tickets Elsewhere

docket docs handoff > brief.md

Prints a brief written for a chat system that has no access to your repository. Paste it in, describe the project, and it writes ticket files by hand.

The brief is rendered against this repository, so it names your registered keys, the first free number under each, your priority band, and the directory the files belong in. Nothing is left for it to guess.

Save what comes back into your todo directory and run docket validate. That is the whole import step, because every rule an importer would need already lives there. Tickets written somewhere else are checked by the same code as the ones written here.

Key Ticket Rules

  1. Dependencies point one way. A ticket declares requires and nothing else. Reverse edges are derived, so a one-sided edge is impossible rather than merely detectable.
  2. Status is the truth, the directory follows. Only done moves a file, and nothing writes one without the other. validate catches a file moved by hand.
  3. Keys are a whitelist. An unregistered key is refused, so a typo cannot spawn an orphan group. A key must be added explicitly before it can be used.

Configuration

.docket.toml at the repo root. Read and written with tomlkit, so comments, spacing, and key order survive every write like:

root = "docs/tickets"
todoDir = "todo"
doneDir = "done"
defaultPriority = 2
maxPriority = 4
lockTimeout = 5.0
maxRoadmapNodes = 200

[keys]
# Primary arch
CORE = "tactical-sim core"
# The strategic layer is a distinct area.
META = "campaign and progression"

A key's rationale becomes the comment above it, and removing the key takes the comment with it. The status vocabulary is deliberately not configurable.

maxRoadmapNodes is how many nodes docket docs roadmap aims to draw, and 0 turns the ceiling off.

docket deploy never rewrites an existing .docket.toml. Run docket upgrade . later to refresh the template and repair the server entry without touching your config or tickets.

Concurrent Access

Writes are serialized across processes through .docket.lock at the repo root, which deploy adds to your .gitignore.

  • Readers share the lock, writers take it exclusively.
  • The whole read-modify-write is held, not just the write. Two processes cannot mint the same id.
  • Files are replaced atomically.

Config value lockTimeout is how long a process waits before giving up. Hitting it raises an error that changed nothing, so the call is always safe to retry.

Validation

docket validate presents an error or warning when:

  • A requires entry naming an id that does not exist, or a dependency cycle.
  • Two tickets sharing an id, or an unregistered key.
  • An id disagreeing with its filename prefix, or a status disagreeing with its directory.
  • A priority outside the band, or a status outside the vocabulary.
  • A file under a status directory that cannot be read as a ticket.
  • A ticket's title is not in the valid title format.

Docket Runs on Docket

This repo is its own first consumer. Every feature above arrived as a ticket, committed in docs/tickets/. done/ is the history of how the tool got built, todo/ is what is next.

Development

uv sync
uv run pytest
uv run docket --help
uv tool install --editable --force .  # install your working copy

The core library holds every rule. The CLI and MCP server are thin shells with no logic of their own, which is what keeps the two surfaces from disagreeing.

See CONTRIBUTING.md for the full details.

License

GNU GPL v3.0 or later, with an output exception.

Anything Docket writes into your repository is yours under whatever terms you choose: deployed templates, ticket files, generated artifacts. Running Docket against a repository places no license obligation on that repository. The exception reaches only what Docket produces, never Docket's own source.

Release files for ticket-docket 1.8.0

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

Source distribution (sdist)

Source distribution for ticket-docket 1.8.0
File Size Uploaded
ticket_docket-1.8.0.tar.gz 147.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ticket-docket 1.8.0
File Interpreter ABI Platform
ticket_docket-1.8.0-py3-none-any.whl Python 3 none any Details

Total release size: 250.2 kB

Release files / ticket_docket-1.8.0.tar.gz

Download URL ticket_docket-1.8.0.tar.gz
Size 147.0 kB
Tags Source
SHA-256 checksum
How to use checksums
6d4f8f18695c25ce2de6c7ce7e7b51fc820f32ac94ab3979a86c3e29584e23c6
BLAKE2b-256 checksum
How to use checksums
13d2bc3409f1d811c2fca952e263c9bb58cc91fb15fe2dbe4360ee350a4cf70d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / ticket_docket-1.8.0-py3-none-any.whl

Download URL ticket_docket-1.8.0-py3-none-any.whl
Size 103.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d0cd81c2233426229f94b23bcd5b08ebf296d91e03a1e92fe03289e2251e13d6
BLAKE2b-256 checksum
How to use checksums
6c4967c5f1100335a97dce07e2b17e3b9639fb3998ce0089cd598ee276dc4997
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

1.8.0 This release

2 release files

1.5.0

2 release files

1.3.0

2 release files

1.0.1

2 release files

1.0.0

2 release files

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