torudo 0.17.0

A terminal-based todo.txt viewer and manager with TUI interface
# Torudo

[![Crates.io](https://img.shields.io/crates/v/torudo.svg)](https://crates.io/crates/torudo)

A terminal-based todo.txt viewer and manager written in Rust with TUI interface.

## Features

- Project-based column view with priority sorting
- **Pick layout** (Todo mode, `v` to toggle): groups todos into `(A)` / `High` / `Low` / `No Energy` columns for GTD next-action pickup; composes with the `n` energy/time filter
- **GTD modes** (Inbox, Todo, Waiting, Ref, Someday) switchable with `Tab` / `Shift+Tab`
- **Vimium-like `f` jump**: press `f` to overlay short labels on every visible card and jump selection with one keystroke
- **External capture** via `torudo inbox add "..."` โ€” add items to the inbox from scripts, launchers, or editor bindings without the TUI running
- Vim integration and real-time file watching
- URL detection (๐Ÿ”—) and browser open (`o`)
- Self-update via GitHub Releases (`torudo update`)
- [crmux](https://github.com/maedana/crmux) / Claude Code integration

## Demo
![gif][1]

## Installation

### Quick install

```sh
curl -sSL https://raw.githubusercontent.com/maedana/torudo/main/install.sh | sh
```

### From crates.io

```sh
cargo install torudo --locked
```

### Build from source

```sh
git clone https://github.com/maedana/torudo.git
cd torudo
cargo build --release
```

## Configuration

### Command Line Options

- `--todotxt-dir <PATH>`: Directory containing your todo.txt file (default: `~/todotxt`, fallback: `TODOTXT_DIR` env var)
- `--nvim-listen <PATH>`: Neovim socket path set by `nvim --listen` (default: `/tmp/nvim.sock`, fallback: `NVIM_LISTEN_ADDRESS` env var)

## Usage

### First Time Setup

When you run Torudo for the first time, it will check for the required directory and files:

1. If `~/todotxt` directory doesn't exist, it will ask permission to create it
2. If `todo.txt` doesn't exist, it will ask permission to create an empty file
3. If you decline either creation, the application will exit

This ensures you have control over where your todo files are stored.

### Basic Usage

```bash
# Run torudo (looks for todo.txt in $TODOTXT_DIR or ~/todotxt)
torudo

# Specify todotxt directory
torudo --todotxt-dir ~/my-todos

# Run with debug mode for detailed logging
torudo -d

# Specify Neovim socket path
torudo --nvim-listen /tmp/my-nvim.sock
```

### Working with Modes from Outside the TUI

Every GTD mode is reachable from the CLI without the TUI running, which makes torudo usable from launchers, shell scripts, editor keybindings, and agents. `<mode>` is one of `inbox`, `todo`, `waiting`, `ref`, `someday`.

```bash
# Capture a new task into the inbox
torudo inbox add "(A) Buy milk +grocery @home"

# Pipe the output through jq to grab the generated id
torudo inbox add "Draft blog post +writing" | jq -r .id

# Preserve an explicit id (otherwise a UUID is generated)
torudo inbox add "Fix #123 id:my-custom-id"

# List a mode โ€” plain todo.txt lines, or JSON for scripting
torudo inbox list
torudo todo list --json

# Set GTD tags on an item (--time short|medium|long, --energy low|high)
torudo todo set <id> --time short --energy low

# Make an item recur on completion (see "Recurring Items" below)
torudo todo set <id> --rec 1w

# Stop an item recurring
torudo todo set <id> --rec none

# Move an item to another mode
torudo inbox promote <id> --to todo

# Complete an item โ€” moves it to done.txt with today's date (Todo / Waiting only)
# A recurring item also gets a "recurrence" field with the next occurrence's id/dates
torudo todo complete <id>

# Look at the archive, and undo a completion
torudo done list --json
torudo todo reopen <id>

# Search titles, +project / @context tags, and detail-md content across every mode
# (done.txt is never included)
torudo search "release" --json
torudo search "release" --mode todo

# Move the running TUI's cursor onto an item โ€” the TUI must already be running
torudo focus <id>

# Chain them: jump straight to the first search hit
torudo search "release" --json | jq -r '.[0].id' | xargs torudo focus
```

`add`, `set`, and `promote` print the resulting item as JSON in the same format as `torudo current`; `set` and `promote` exit non-zero on an unknown id. When a TUI session is running, the file watcher picks up the change and the affected tab updates automatically.

`search` matches case-insensitively against the item's title, its `+project` and `@context` tags, and the body of its detail md; `key:value` tags such as `id:` and `time:` are not searched. The `matched` field reports where the query landed โ€” `title` (title or tags), `md`, or `both`.

`search` is a stateless CLI command; `focus` is not โ€” it talks to a running TUI over its RPC socket and moves the cursor there, switching modes and clearing the Now filter automatically if the item is hidden. With no TUI running it prints `torudo is not running` and exits non-zero. Because the target is whichever session holds the socket, `focus` ignores `--todotxt-dir` and acts on the directory that TUI was started with.

### Driving torudo from Claude Code

This repository ships an [Agent Skill](skills/torudo/SKILL.md) that lets Claude Code run the
above for you in plain language โ€” "inboxใซ็‰›ไนณใ‚’่ฒทใ†ใ‚’่ฟฝๅŠ ใ—ใฆ", "็Ÿญๆ™‚้–“ใƒปไฝŽใ‚จใƒใƒซใ‚ฎใƒผใซใ—ใฆ
todoใซ็งปใ—ใฆ", or a bare URL, in which case Claude resolves a readable title (using a
host-specific CLI when one exists, otherwise fetching the page) and confirms the line before
adding it. It also writes the `- [ ]` checklist in `todos/{id}.md` for an item, and can start
work on a task โ€” creating the git worktree, opening a terminal tab there, and launching a
Claude session for it. That last part additionally needs
[git-wt](https://github.com/k1LoW/git-wt) and [herdr](https://herdr.dev); without them the
capture and triage parts still work.

```bash
# Install globally
npx skills add maedana/torudo --skill torudo -g
```

Or copy `skills/torudo/SKILL.md` to `~/.claude/skills/torudo/SKILL.md` by hand.

### Updating

```bash
# Check for updates
torudo update --check

# Update to latest version
torudo update

# Force re-download
torudo update --force
```

### Keyboard Controls

Press `?` in the TUI or run `torudo -h` to see all keyboard shortcuts.

### Todo.txt Format

Torudo supports the standard todo.txt format:

```
(A) Call Mom +family @phone
x 2024-01-15 2024-01-10 (B) Review quarterly report +work @office
(C) Buy groceries +personal @errands
Learn Rust programming +learning @coding id:abc123
```

Features supported:
- Priority levels: `(A)`, `(B)`, `(C)`
- Completion status: `x` prefix with completion date
- Creation date: `YYYY-MM-DD` format
- Projects: `+project_name`
- Contexts: `@context_name`
- Unique IDs: `id:unique_identifier` (automatically added if missing)
- Key/value tags: `key:value` pairs (e.g. `t:2026-05-30`, `due:2026-06-01`) are parsed into a dedicated field; URLs in the description are not misdetected as tags
- Recurring completion: `rec:1w` / `rec:+1m` โ€” completing the item spawns its next occurrence automatically (see "Recurring Items" below)

### Todo Sorting

Todos are automatically sorted within each project column using the following priority:

1. **Priority level**: (A) items first, then (B), then (C)
2. **File line number**: Within the same priority level, todos maintain their original file order

This ensures high-priority items are always visible at the top while preserving your intended ordering for items of the same priority.

### Display Features

- **Threshold dates** (`t:YYYY-MM-DD`): future items sort to bottom and render dimmed
- **Overdue highlighting** (`due:YYYY-MM-DD`): items past due render with a red border
- **Detail md preview** (Todo / Waiting tabs): top 3 unchecked `- [ ]` from `todos/{id}.md` shown inline on each card
- **Detail md badge** (Todo / Waiting tabs): right-aligned `{done}/{total} {elapsed}` (e.g. `2/7  5m`) on each card; updates live
- **Recurrence chip**: `โ†ป1w` / `โ†ป+1m` next to the GTD chips when `rec:` is set and its pattern parses
- **Dynamic text wrap** with per-item height calculation

### Recurring Items

Add `rec:<pattern>` to an item to spawn its next occurrence automatically when you complete it. A pattern is `<count><unit>`, where unit is `d` (day), `w` (week), `m` (month), or `y` (year) โ€” e.g. `rec:1w`, `rec:2m`. Prefixing the pattern with `+` switches what it counts from:

- **`rec:1w`** (no `+`) โ€” the next occurrence is due one week after the day you actually complete it. Good for "water the plants": however late you are, the next round starts fresh from today.
- **`rec:+1m`** (with `+`) โ€” the next occurrence is due one month after the item's *original* `due:` date, ignoring how late you completed it. Good for "pay rent": the schedule stays fixed even if you complete it a few days late.

A strict (`+`) pattern that has fallen a long way behind catches up in one go: the pattern is applied repeatedly until the next date lands *after* the day you completed it, so completing a `due:2025-01-01 rec:+1m` item on 2026-08-15 gives you 2026-09-01 rather than 2025-02-01. You never have to complete an item nineteen times to work off a backlog, and the schedule still lines up with the original day of the month. (This is a deliberate departure from topydo, which only ever advances one period.)

To stop an item repeating, clear the tag with `torudo <mode> set <id> --rec none`.

Completing a recurring item still moves the original line to `done.txt` as usual, and also appends a new line to the same mode file: a fresh `id:`, today as the creation date, `t:`/`due:` shifted by the pattern (the gap between them is preserved), and everything else โ€” priority, `+project`, `@context`, `rec:`, `time:`, `energy:` โ€” carried over unchanged. If the item has a `todos/{id}.md` detail file, it is copied to the new id with every `- [x]` checkbox reset to `- [ ]` (so a written-out procedure survives, just unchecked) and the frontmatter's `branch:` line dropped (`cwd:` is kept). An invalid `rec:` value never blocks completion โ€” it just skips creating a next occurrence and reports why, both on the TUI status line and (for `torudo todo complete`) as a warning on stderr.

### Vim Integration

If you have Neovim running with a socket, Torudo can automatically open todo detail files when navigating. Each todo item can have an associated markdown file in `$TODOTXT_DIR/todos/{id}.md`.

### Todo Detail Frontmatter

Todo detail files (`todos/{id}.md`) support YAML frontmatter with a `cwd` field to specify the working directory for `clp`/`cli` claude launch:

```markdown
---
cwd: /home/user/src/my-project
---
# Task details here
```

The `cwd` field is required for `clp`/`cli` โ€” an error is shown if it is not set.

## File Structure

Torudo keeps one todo.txt-format file per GTD mode plus a `done.txt` archive. Each file holds plain todo.txt lines; `todos/{id}.md` holds optional long-form detail for individual items.

```
~/todotxt/
โ”œโ”€โ”€ inbox.txt         # Inbox โ€” capture target (also `torudo inbox add`)
โ”œโ”€โ”€ todo.txt          # Todo / Next actions (`x` completes here)
โ”œโ”€โ”€ waiting.txt       # Waiting for (`x` also completes here)
โ”œโ”€โ”€ ref.txt           # Reference material
โ”œโ”€โ”€ someday.txt       # Someday / maybe
โ”œโ”€โ”€ done.txt          # Archive of items completed from todo.txt
โ””โ”€โ”€ todos/            # Individual todo detail files
    โ”œโ”€โ”€ abc123.md
    โ””โ”€โ”€ def456.md
```

Only `todo.txt` is created at first launch; the other mode files are created lazily the first time something lands in them (e.g. via the `s` send-to prefix or `torudo inbox add`). Completing an item with `x` works in Todo and Waiting modes (completed items are moved to `done.txt`); to complete an item from Inbox / Ref / Someday, send it to Todo first with `st`.

**If you prefer the classic todo.txt / done.txt workflow**, just stay in Todo mode and ignore the other tabs โ€” none of the GTD mode files are created until you write to them, and every existing key (`x`, `hjkl`, `o`, โ€ฆ) behaves exactly as before. GTD is opt-in, not required.

## Development

### Running in Development

```bash
cargo run

# With debug mode
cargo run -- -d
```

### Running Tests

```bash
cargo test
```

### Code Quality

```bash
cargo clippy
cargo fmt
```

## Roadmap

Ideas that are on the table but not yet implemented. Order does not imply priority.

- Show PR status for todos linked to a git working tree (new frontmatter field pointing at the working tree path)
- `torudo w sync` subcommand: when invoked from inside a git working tree, automatically fill the currently selected todo's frontmatter with that path (no more hand-editing)

## License

This project is licensed under the MIT License - see the LICENSE file for details.

## Contributing

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Run tests and linting
5. Submit a pull request

## Acknowledgments

- Inspired by the todo.txt format by Gina Trapani
- Built with [Ratatui](https://github.com/ratatui-org/ratatui) for the terminal UI
- Uses [crossterm](https://github.com/crossterm-rs/crossterm) for cross-platform terminal handling

[1]: https://raw.githubusercontent.com/maedana/torudo/main/docs/demo.gif