Skip to main content

docket

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

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. 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

[!IMPORTANT] In Windows PowerShell, the ` character can be treated as an escape character. Typing "Use `argparse` instead" produces \x07. For code blocks in a body, use the MCP surface or a text editor.

A ticket id is the command:

docket CORE-14         # show it, dependency context and all
docket CORE-14 status  # bare word, for a pipe
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]

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]
docket graph [-i CORE-14 | -k GEN] [-o FILE]
docket key list | add KEY "desc" [-r TEXT] | remove KEY
docket validate | deploy PATH | upgrade PATH

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

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. Ten 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.
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?) 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.

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

[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.

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 errors on:

  • 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

validate has no warnings of its own. That severity exists for create_ticket, which downgrades a dangling requires entry so a batch written out of order is not stranded halfway.

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.

The version lives in exactly one place, src/docket/__init__.py. Bump it with the script, never by hand, then run uv sync:

python scripts/bumpVersion.py patch
python scripts/bumpVersion.py 0.2.0
python scripts/bumpVersion.py minor --dry-run

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.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ticket_docket-1.0.0.tar.gz (113.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ticket_docket-1.0.0-py3-none-any.whl (79.1 kB view details)

Uploaded Python 3

File details

Details for the file ticket_docket-1.0.0.tar.gz.

File metadata

  • Download URL: ticket_docket-1.0.0.tar.gz
  • Upload date:
  • Size: 113.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.21 {"installer":{"name":"uv","version":"0.9.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for ticket_docket-1.0.0.tar.gz
Algorithm Hash digest
SHA256 0ff5f68f9a66b6aafc0811f5bb773bdb343a077867578b9cc3765322a5c09836
MD5 748f8dce6eb9cf9a296ad15530311d80
BLAKE2b-256 6f684375fb226c229e39e843a4821f27610f1a830d1707cb55e96b744d98c029

See more details on using hashes here.

File details

Details for the file ticket_docket-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: ticket_docket-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 79.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.21 {"installer":{"name":"uv","version":"0.9.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for ticket_docket-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d2a6ee89674dc5f9e5ea916400c1afac9b7a7ad8ec3683e2148607d8563bf2af
MD5 7838bc0ffb475c261b7989b1828c83ab
BLAKE2b-256 61bc21a4bcba8ae966ecb154f7dd9830f759181dd023c548a2b5005802dacf7e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page