Task management for agentic engineering
A Go CLI that gives AI agents deterministic, token-efficient task tracking,
without the complexity of full project management tools.
Install · Quick Start · Commands · Output Formats · Why Tick?
Tick is a lightweight CLI for tracking tasks, dependencies, and status transitions inside your project. It stores everything in a plain JSONL file (human-readable, git-friendly) with a SQLite cache for fast queries. Run tick init, and you're set.
It's built to be used by AI agents as much as by humans. Output auto-switches between a token-efficient format for agents and clean tables for terminals, so the same commands work in both contexts.
Claude, Cursor, and other AI coding agents need a way to track tasks across sessions. The built-in approaches have problems:
- TodoWrite / in-context lists — lost between sessions, no persistence, no dependency tracking
- Markdown files — no structure, agents parse them inconsistently, output is verbose
- Beads / full PM tools — too much complexity for a coding session, heavy overhead
Tick sits in between: structured enough for agents to reason about reliably, simple enough that it doesn't get in the way.
| Tick | TodoWrite | Markdown | Beads | |
|---|---|---|---|---|
| Persists across sessions | Yes | No | Yes | Yes |
| Dependencies & blockers | Yes | No | No | Yes |
| Token-efficient output | TOON (30-60% savings) | N/A | No | No |
| Deterministic format | Yes | Varies | No | Yes |
| Complexity | Low | Minimal | Minimal | High |
| Setup | tick init |
None | None | Config |
macOS
brew install leeovery/tools/tickLinux
curl -fsSL https://raw.githubusercontent.com/leeovery/tick/main/scripts/install.sh | bashGo
go install github.com/leeovery/tick/cmd/tick@latesttick init # create .tick/ in your project
tick create "Build auth module" # create a task
tick create "Write tests" --priority 1 --blocked-by tick-a1b2
tick list # see all tasks
tick ready # tasks with no blockers
tick start tick-a1b2 # open → in_progress
tick done tick-a1b2 # in_progress → doneInitialize a new tick project in the current directory. Creates a .tick/ directory with an empty tasks.jsonl file.
tick initCreate a new task. Returns the full task detail on success.
tick create <title> [flags]| Flag | Type | Default | Description |
|---|---|---|---|
--priority |
0-4 |
2 |
0 critical, 1 high, 2 medium, 3 low, 4 backlog |
--description |
string | Task description (supports multi-line) | |
--type |
string | Task type: bug, feature, task, chore |
|
--tags |
strings | Comma-separated tags (kebab-case, max 10) | |
--refs |
strings | Comma-separated external references (URLs, issue keys) | |
--parent |
ID | Make this a subtask of another task | |
--blocked-by |
IDs | Comma-separated list of tasks this depends on | |
--blocks |
IDs | Comma-separated list of tasks this blocks |
tick create "Build auth module"
tick create "Critical fix" --priority 0 --type bug
tick create "Write tests" --blocked-by tick-a1b2,tick-c3d4 --tags backend,testing
tick create "Login endpoint" --parent tick-a1b2 --refs https://github.com/org/repo/issues/42List tasks with optional filters. Results are sorted by priority (ascending), then creation date.
tick list [flags]| Flag | Type | Default | Description |
|---|---|---|---|
--status |
string | Filter by status: open, in_progress, done, cancelled |
|
--priority |
0-4 |
Filter by priority level | |
--type |
string | Filter by type: bug, feature, task, chore |
|
--tag |
string | Filter by tag (repeatable, see below) | |
--parent |
ID | Show descendants of a task | |
--ready |
bool | false |
Show only ready tasks (open, no unresolved blockers, no open children, no dependency-blocked ancestor) |
--blocked |
bool | false |
Show only blocked tasks (open with unresolved blockers, open children, or dependency-blocked ancestor) |
--count |
int | Limit results to N tasks |
--ready and --blocked are mutually exclusive.
Tag filtering supports AND/OR composition:
--tag ui,backend— AND: tasks must have both tags--tag ui --tag api— OR: tasks with either tag--tag ui,backend --tag api— mixed: (ui AND backend) OR api
tick list # all tasks
tick list --status open # filter by status
tick list --priority 0 # only critical tasks
tick list --type bug # only bugs
tick list --tag backend # tasks tagged "backend"
tick list --parent tick-a1b2 # descendants of a task
tick list --count 5 # first 5 resultsAlias for tick list --ready. Shows tasks that are open, have no unresolved blockers, no open children, and no dependency-blocked ancestor. Accepts the same filter flags as list (--status, --priority, --type, --tag, --parent, --count).
tick ready
tick ready --count 1 # next task to work on
tick ready --type bug --count 3Alias for tick list --blocked. Shows tasks that are open but waiting on dependencies, have open children, or have an ancestor with unresolved blockers. Accepts the same filter flags as list.
tick blocked
tick blocked --tag backendDisplay full detail for a single task, including type, tags, refs, notes, blockers, children, and description.
tick show <task-id>Modify one or more fields on an existing task. At least one flag is required.
tick update <task-id> [flags]| Flag | Type | Description |
|---|---|---|
--title |
string | Set a new title |
--description |
string | Set or replace the description |
--clear-description |
bool | Remove the description (mutually exclusive with --description) |
--priority |
0-4 |
Change priority level |
--type |
string | Set task type (bug, feature, task, chore) |
--clear-type |
bool | Remove the type |
--tags |
strings | Replace tags (comma-separated) |
--clear-tags |
bool | Remove all tags |
--refs |
strings | Replace refs (comma-separated) |
--clear-refs |
bool | Remove all refs |
--parent |
ID | Set or change the parent task (pass empty string to clear) |
--blocks |
IDs | Comma-separated list of tasks this blocks |
tick update tick-a1b2 --title "Revised title" --priority 1
tick update tick-a1b2 --type bug --tags critical,backend
tick update tick-a1b2 --parent tick-c3d4Transition a task between statuses.
tick start <task-id> # open → in_progress
tick done <task-id> # in_progress → done
tick cancel <task-id> # any → cancelled
tick reopen <task-id> # done/cancelled → opendone and cancel set a closed timestamp. reopen clears it.
Permanently delete one or more tasks. Removing a parent cascades to all descendants. Dependency references on surviving tasks are automatically cleaned up.
tick remove <id> [<id>...] [flags]| Flag | Type | Description |
|---|---|---|
--force, -f |
bool | Skip confirmation prompt |
tick remove tick-a1b2 # remove with confirmation
tick remove tick-a1b2 tick-c3d4 -f # remove multiple, skip promptSince tasks.jsonl is tracked in git, accidental removals can be recovered from history.
Add or remove timestamped notes on a task.
tick note add <task-id> <text>
tick note remove <task-id> <index>tick note add tick-a1b2 "Discussed approach with team"
tick note remove tick-a1b2 1 # remove note at index 1 (1-based)Manage task dependencies. Tick validates all dependency changes and prevents cycles, self-references, and children blocked by their own parent.
tick dep add <task-id> <blocked-by-id>
tick dep rm <task-id> <blocked-by-id>tick dep add tick-a1b2 tick-c3d4 # tick-a1b2 is now blocked by tick-c3d4
tick dep rm tick-a1b2 tick-c3d4 # remove that dependencyShow aggregate task counts grouped by status, workflow state (ready/blocked), and priority.
tick statsRun diagnostic checks against your task data. Read-only, never modifies data.
tick doctorChecks for: JSONL syntax errors, invalid IDs, duplicates, orphaned references, self-referential dependencies, dependency cycles, parent/child constraint violations, and cache staleness.
Force a full SQLite cache rebuild from the JSONL source file, bypassing the freshness check.
tick rebuildPrint the tick version and exit.
tick versionShow usage information. With no argument, lists all commands and global flags. With a command name, shows detailed help including flags.
tick help # list all commands
tick help create # detailed help for create
tick help --all # full reference of all commands and flags
tick create --help # same as tick help create
tick -h # same as tick helpImport tasks from external tools.
tick migrate --from <provider> [flags]| Flag | Type | Default | Description |
|---|---|---|---|
--from |
string | required | Provider to import from (currently: beads) |
--dry-run |
bool | false |
Preview what would be imported without persisting |
--pending-only |
bool | false |
Only import tasks not yet migrated |
tick migrate --from beads
tick migrate --from beads --dry-run --pending-onlyTick auto-detects the context and picks the right format:
| Context | Default format | Override |
|---|---|---|
| Terminal (TTY) | --pretty |
--toon, --json |
| Pipe / agent | --toon |
--pretty, --json |
|
Agent / pipe (TOON) |
Terminal (Pretty) |
Designed for AI consumption. Schema is declared once in the header; rows are compact CSV-like lines. Uses 30-60% fewer tokens than equivalent JSON.
tasks[2]{id,title,status,priority,type}:
tick-a1b2,Setup auth,done,1,feature
tick-c3d4,Login endpoint,open,1,task
task{id,title,status,priority,type,created,updated}:
tick-a1b2,Setup auth,in_progress,1,feature,"2026-01-19T10:00:00Z","2026-01-19T14:30:00Z"
tags[2]:
backend
auth
refs[1]:
https://github.com/org/repo/issues/42
blocked_by[1]{id,title,status}:
tick-c3d4,Database migrations,done
children[0]{id,title,status}:
notes[1]{text,created}:
Discussed approach with team,"2026-01-19T14:00:00Z"
description:
Full task description here.
Can be multiple lines.
Clean aligned columns for terminals. No borders, no colors, no icons.
ID STATUS PRI TYPE TITLE
tick-a1b2 in_progress 1 feature Setup auth
tick-c3d4 open 1 task Login endpoint
Standard 2-space indented JSON with snake_case keys.
[
{
"id": "tick-a1b2",
"title": "Setup auth",
"status": "in_progress",
"priority": 1
}
]Task IDs can be abbreviated to any unique prefix. If only one task matches, it resolves automatically. This works everywhere a task ID is accepted.
tick show tick-a1 # resolves to tick-a1b2c3 if unique
tick start a1b2 # tick- prefix is optional
tick dep add a1 c3 # both IDs resolvedTick stores data in a .tick/ directory at your project root:
tasks.jsonl— append-only source of truth (one JSON object per line, human-editable, git-friendly)cache.db— SQLite cache (auto-rebuilt when JSONL changes, do not commit)lock— file lock for safe concurrent access
Add to .gitignore:
.tick/cache.db
.tick/lock
--help, -h Show help (tick --help or tick <command> --help)
--quiet, -q Minimal output (IDs only where applicable)
--verbose, -v Debug logging to stderr
--toon Force TOON format
--pretty Force pretty format
--json Force JSON format
MIT