Metadata-Version: 2.4
Name: mdtodo
Version: 0.2.0
Summary: A todo list manager that keeps projects and tasks in a plain markdown file.
Keywords: todo,markdown,cli
Author: mjws4oss
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Utilities
Classifier: Typing :: Typed
Requires-Python: >=3.14
Description-Content-Type: text/markdown

# mdtodo

`mdtodo` is a command-line todo manager that keeps everything in one plain markdown file.
`mdtodo` is a command-line todo manager that keeps everything in one plain markdown file.
Headings are projects and checkbox items are tasks. You can edit the file in any editor, or
use the `mdtodo` commands. Either way, it stays readable markdown.
use the `mdtodo` commands. Either way, it stays readable markdown.

```markdown
- [ ] Call the bank due:2026-10-20

## Website
- [ ] Write landing copy @active due:2026-10-18
- [ ] Pick a color palette @next
  - [ ] Shortlist 3 palettes
- [x] Buy domain
```

- `[ ]` means open, and `[x]` means completed.
- `@active` marks a task you're working on now. `@next` adds a task to the pool of tasks
  you plan to pick up next.
- `due:YYYY-MM-DD` sets a deadline. Open tasks are flagged as overdue, or as due soon
  (today through the next 3 days).
- Tasks above the first heading go into the `Inbox` project. Prose, notes, and code blocks
  are ignored.

Listings show each task with its reference. A subtask is labelled with its parent's name, as
`<parent>: <task>`, so you can tell which task it belongs to:

```text
$ mdtodo list --project Website
## Website
bbdb3a  Write landing copy  (due 2026-10-18, overdue)
b1b77f  Pick a color palette
  aa0d81  Pick a color palette: Shortlist 3 palettes
```

The full syntax is in
[specs/001-markdown-todo-manager/contracts/file-format.md](specs/001-markdown-todo-manager/contracts/file-format.md).

## Install

With [uv](https://docs.astral.sh/uv/) installed:

```bash
uv tool install mdtodo   # puts `mdtodo` on your PATH (~/.local/bin)
mdtodo --version
```

If you don't have a suitable Python, uv downloads one for you.

```bash
uv tool install mdtodo==X.Y.Z   # install a specific version
uv tool upgrade mdtodo          # move to the latest release
uv tool uninstall mdtodo        # remove the command
```

Uninstalling removes only the command. Your todo file (`~/tracker.md`, or whatever `--file`
or `MDTODO_FILE` points at) is left untouched.

**Switching from an editable install**: if you installed with `uv tool install --editable .`,
run `uv tool uninstall mdtodo` first, or replace it in one step with
`uv tool install --force mdtodo`.

## Which file is used

The first match wins:

1. `--file PATH`, which can go before or after the command;
2. the `MDTODO_FILE` environment variable;
3. `~/tracker.md`.

If you used an earlier version that read `~/TODO.md`, rename that file to `~/tracker.md`, or
point `--file` or `MDTODO_FILE` at it.
2. the `MDTODO_FILE` environment variable;
3. `~/tracker.md`.

If you used an earlier version that read `~/TODO.md`, rename that file to `~/tracker.md`, or
point `--file` or `MDTODO_FILE` at it.

`mdtodo init` creates a starter file. Nothing else ever creates the file.
`mdtodo init` creates a starter file. Nothing else ever creates the file.

## Commands

| Command | What it does |
|---------|--------------|
| `mdtodo` / `mdtodo summary` | Active, Next, Overdue, and Due soon tasks, plus counts per project |
| `mdtodo list [--all] [--project NAME]` | Tasks grouped by project, each with its reference |
| `mdtodo next` | The next pool, ordered by deadline |
| `mdtodo due` | Open tasks ordered by deadline |
| `mdtodo start REF` / `mdtodo stop REF` | Add or remove `@active` |
| `mdtodo next add REF` / `mdtodo next rm REF` | Add or remove `@next` |
| `mdtodo done REF` | Check the box, and remove `@active` and `@next` |
| `mdtodo init` | Create a starter file |
| `mdtodo` / `mdtodo summary` | Active, Next, Overdue, and Due soon tasks, plus counts per project |
| `mdtodo list [--all] [--project NAME]` | Tasks grouped by project, each with its reference |
| `mdtodo next` | The next pool, ordered by deadline |
| `mdtodo due` | Open tasks ordered by deadline |
| `mdtodo start REF` / `mdtodo stop REF` | Add or remove `@active` |
| `mdtodo next add REF` / `mdtodo next rm REF` | Add or remove `@next` |
| `mdtodo done REF` | Check the box, and remove `@active` and `@next` |
| `mdtodo init` | Create a starter file |

`REF` is the 6-character reference shown in every listing. It stays the same when markers
change. If you edit a task's text, its reference changes, and the old one is refused rather
than applied to the wrong task. Each command changes only the task's own line. If the file
changed while the command was running, nothing is written.

Details, including output formats and exit codes, are in
[contracts/cli.md](specs/001-markdown-todo-manager/contracts/cli.md).

## Development

```bash
uv sync
uv tool install --editable .       # installs this working tree as the `mdtodo` command
scripts/check.sh                   # format, lint, mypy --strict, tests (coverage ≥ 80%)
uv run pytest -m perf --no-cov     # timing checks (SC-002), kept out of the default run
```

The design documents are in [specs/001-markdown-todo-manager/](specs/001-markdown-todo-manager/),
and the project principles are in [.specify/memory/constitution.md](.specify/memory/constitution.md).

## Releasing

Releases go to PyPI with `scripts/release.sh`. See [docs/releasing.md](docs/releasing.md).
