Guide

Yes! Did It is a CLI-first todo tracker designed for developers. Capture tasks from your terminal or AI assistant, query them, and mark them done — without leaving your workflow.

Core Concepts

  • CLI-first — all mutations (add, complete, update) happen via the CLI or API. The web dashboard is for viewing and deleting.
  • MCP-ready — Claude can manage your todos through the MCP server integration.
  • Time filters — query todos by time: today, tomorrow, this-week, overdue, upcoming, next-hour.
  • Tags — organize todos with tags for grouping and filtering.

CLI Commands

Adding Todos

ydi add "Ship the API" --due "today 5pm"
ydi add "Review PR" --due "tomorrow 10am" --tag work --tag review
ydi add "Buy groceries"

Due dates support natural language. Tags are comma-separated.

Listing Todos

ydi list                          # All pending todos
ydi list --filter today           # Due today
ydi list --filter overdue         # Past due
ydi list --filter this-week       # Due this week
ydi list --all                    # Include completed
ydi list --tag work               # Filter by tag
ydi list --current-branch         # Todos on current git branch
ydi list --branch feat/auth       # Todos on a specific branch
ydi list --here                   # Todos in current repo
ydi list --active                 # Todos on branches with recent commits
ydi list --verbose                # Show full git context

Updating Todos

ydi update abc123 --text "New text"   # Change text
ydi update abc123 --due "friday 5pm"  # Change due date
ydi update abc123 --clear-due         # Remove due date
ydi update abc123 --tag work --tag v2 # Replace tags
ydi update abc123 --clear-tags        # Remove all tags
ydi update                            # Interactive picker

Combine multiple flags in one command to update several fields at once.

Completing Todos

ydi done abc123                   # By ID (short prefix works)
ydi done                          # Interactive picker

When you run ydi done without an ID, an interactive picker lets you search and select from your pending todos.

Deleting Todos

ydi delete abc123                 # By ID
ydi delete                        # Interactive picker

Managing API Keys

ydi keys create --name "CI"       # Generate a new key
ydi keys list                     # List active keys

Git Context

When you create a todo inside a git repository, the CLI automatically captures the current branch, commit SHA, and repository URL. This context links your todos to the code you're working on.

ydi add "Fix auth token refresh"
# Added: abc123  [feat/auth-fix]

ydi context                    # See what would be captured
# Branch:  feat/auth-fix
# Commit:  a1b2c3d
# Repo:    https://github.com/you/project.git
# Slug:    you/project

ydi add "Unrelated task" --no-context   # Skip capture

Context powers branch-based filtering (ydi list --current-branch), verbose display (-v), stale todo detection, and more.

Stale Todo Detection

When a branch is deleted (usually after a PR merge), its todos become stale. The sweep command finds and cleans them up:

ydi sweep                # Interactive — select which stale todos to complete
ydi sweep --dry-run      # Preview stale todos without acting
ydi sweep --auto         # Mark all stale todos as done
ydi list --stale         # List stale todos without completing them

A todo is considered stale when its branch no longer exists on the remote (i.e., the branch was deleted after a PR merge). Local-only branches are not considered stale.

Standup Reports

Generate a standup report showing recently completed todos grouped by branch, plus your current in-progress work:

ydi standup                      # Last 24 hours (default)
ydi standup --since "yesterday 9am"  # Custom lookback
ydi standup --since 48h          # Duration format
ydi standup --json               # Structured output

Configuration

Customize CLI behavior with persistent settings stored in ~/.config/yesdidit/settings.json:

ydi config list                  # Show all settings
ydi config set context.auto false  # Disable auto git context
ydi config set default_filter today  # Default list filter
ydi config set standup.since 48h   # Default standup lookback
ydi config get verbose           # Check a setting

Using with Claude (MCP)

Once the MCP server is configured, you can ask Claude to manage your todos conversationally:

  • "Add a todo to deploy the staging server by Friday"
  • "What's due today?"
  • "What todos are on this branch?"
  • "Give me a standup report"
  • "Are there any stale todos to clean up?"
  • "Mark the deploy todo as done"
  • "Show me everything tagged 'urgent'"
  • "Delete the grocery todo"

API Overview

The full API is available at https://api.yesdidit.com/api. Authenticate with a Bearer JWT or API key.

# List todos due today
curl -H "Authorization: ApiKey ydi_live_..." \
  "https://api.yesdidit.com/api/todos?filter=today"

# Create a todo
curl -X POST \
  -H "Authorization: ApiKey ydi_live_..." \
  -H "Content-Type: application/json" \
  -d '{"text": "Deploy v2", "due_at": "2026-03-23T17:00:00Z"}' \
  https://api.yesdidit.com/api/todos

# Mark complete
curl -X POST \
  -H "Authorization: ApiKey ydi_live_..." \
  https://api.yesdidit.com/api/todos/ID/done

For the complete API specification, see the GitHub repository.

Agent Integration

Every ydi command supports --agent, which returns a markdown envelope (## Status / ## Result / ## Errors / ## Meta) plus semantic exit codes designed for tools shelling out to the CLI — Claude Code, Cursor, custom scripts. The MCP server returns the same envelope from every tool.

The canonical references live next to the code: packages/cli/AGENT.md and packages/mcp/AGENT.md. Point your agent at those files; the highlights are below.

Confirm-to-mutate

With --agent alone, mutating commands (add, done, delete, update, sweep --auto, keys create, config set, hooks install/uninstall) dry-run by default — they print "Would do X" and exit 0 without touching state. Add --confirm to execute. Same pattern over MCP: pass confirm: true in tool args.

ydi add "Refactor auth" --agent           # dry-run (no mutation)
ydi add "Refactor auth" --agent --confirm # actually create

Compact mode and column projection

For list-heavy commands (list, standup), --compact drops the Errors/Warnings/Actions sections and inlines Meta on one line — roughly 30% smaller for typical pages. --fields projects the table down to the columns you actually need.

ydi list --agent --compact
ydi list --agent --fields id,text,branch,pr

Cursor pagination

Long result sets paginate with a stable cursor. The Meta line surfaces next_cursor, and the Actions section prints the exact next-page command verbatim.

ydi list --agent --limit 50
# Meta: ... next_cursor: 50
ydi list --agent --limit 50 --cursor 50

Runtime schema discovery

Rather than hard-coding flag names, agents can ask the binary for its own schema. describe returns a markdown index of every command and per-command flags, args, examples, and related commands.

ydi --agent describe            # top-level command index
ydi list --agent describe       # flags, args, examples for one command

Exit codes

With --agent, exit codes carry meaning: NOT_FOUND=3, PERMISSION_DENIED=4, RATE_LIMITED=6, VALIDATION_FAILED=8. The Errors section also includes **Code:**, **Message:**, **Retryable:**, and often **Suggestion:** lines — parse those rather than the free-text status summary.

Scripting & Automation

Every ydi command supports --json for machine-readable output, making it easy to chain with other tools in shell scripts. Use an API key for headless environments where interactive login isn't possible.

Piping & Filtering

# Print just the text of today's todos
ydi list --filter today --json | jq -r '.[].text'

# Count overdue items
ydi list --filter overdue --json | jq length

# Get IDs of todos tagged "release"
ydi list --tag release --json | jq -r '.[].id'

Bulk Operations

# Add multiple todos from a file (one per line)
while IFS= read -r line; do
  ydi add "$line" --tag sprint
done < backlog.txt

# Mark all overdue todos as done
ydi list --filter overdue --json \
  | jq -r '.[].id' \
  | xargs -I{} ydi done {}

CI / Deploy Gates

# Fail a CI build if release todos are still open
export YDI_API_KEY="ydi_live_..."
open_count=$(ydi list --tag release --json | jq length)
if [ "$open_count" -gt 0 ]; then
  echo "❌ $open_count release todo(s) still open"
  ydi list --tag release
  exit 1
fi

# Log a deploy as a completed todo
ydi add "Deploy v$VERSION to prod" --tag deploy
ydi done $(ydi list --tag deploy --json | jq -r '.[-1].id')

Cron & Notifications

# Daily digest via cron (add to crontab)
# 0 9 * * * /path/to/daily-digest.sh

#!/bin/bash
todos=$(ydi list --filter today --json)
count=$(echo "$todos" | jq length)
if [ "$count" -gt 0 ]; then
  echo "$count todo(s) due today:" | mail -s "YDI Daily Digest" you@example.com
  echo "$todos" | jq -r '.[].text' | mail -s "YDI Daily Digest" you@example.com
fi

Troubleshooting

Token expired

The CLI automatically refreshes tokens. If you see auth errors, run ydi login to re-authenticate.

API unreachable

For local development, make sure the API server is running (pnpm turbo dev). To point the CLI at a local API:

YDI_API_URL=http://localhost:3000 ydi list

MCP not responding

Ensure you're signed in via the CLI first (ydi login). The MCP server reads credentials from the same config file.