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.