Reference
The CLI
taskr is an HTTP client and nothing else. It holds no domain logic, never opens a
database, and never shells out to git — it reads git's own files to know which checkout you are
standing in. taskr help prints this same surface, and is the authority if the two ever
disagree.
The loop
Five verbs carry a working day, and the two that matter most are the ones at the edges: context when you arrive, park when you leave.
- taskr context Where am I, what was I doing, and what name do my writes carry.
- taskr next [--untriaged] [--held] The ranked ready queue. Triage gates it, so a freshly imported project can have plenty of open work and an empty queue; --untriaged ranks it anyway. Issues a teammate is live on are subtracted; --held lists them, annotated with who.
- taskr start <ref> [--join] Start or resume work on an issue and print the resume packet — the prior park note, the tree state it was left at, and the plan. Refused when a teammate is live on it, naming who to ask; --join works alongside them.
- taskr park -m <note> [-r reason] Stop, naming the next concrete action. The note is the first thing the next reader sees.
- taskr end [-r reason] Close the work session and leave the issue where it is.
close finishes the issue. end closes the work session and leaves the issue where it is. triage records whether a
report was real, which is not the same question as whether the work is done.
Issues
- taskr ls [-s status] [-q query] [--all] List and search. -s repeats; --all widens past the project you are standing in. A query climbs a ladder — ref, exact, prefix, fuzzy, then meaning — and each row says which rung found it.
- taskr show <ref> [--context] Issue detail. --context adds the notes agents wrote to themselves.
- taskr new <title> [-k kind] [-p priority] [-m description] [--parent GROUP] [--project SLUG] Open an issue against the repo you are standing in. The answer carries any open issue that already says the same thing, scored, so a twin is caught before it becomes two records.
- taskr comment <ref> -m <text> Leave a note on the record as you go.
- taskr close <ref> [-r resolution] [--despite-checks] Finish the issue. It hands back every unfinished step rather than swallowing it, and refuses while a check is pending.
- taskr timeline <ref> The event ledger: every state change, comment and session, in order.
Intake and triage
- taskr offload <title> -m <brief> [-k kind] [-s severity] [--project SLUG] File something you found without leaving what you are doing. The brief is read cold — say what is wrong, why it matters, which file, and how to tell when it is done. Like new, it answers with any open issue that already says the same thing.
- taskr triage [--all] What needs a verdict, and why: new (never triaged), rot (the branch moved under it), or expired (its verdict aged out). This is the triage surface — ls shows no verdicts, and next --untriaged is the ready pool. Each row also marks its closest open issue in a TWIN column when one comes close, so a duplicate pair reads as a pair before either is opened.
- taskr triage <ref> Does this one issue need a verdict. Says so in words when its verdict is fresh, and lists the open issues that say the same thing, scored — the input the duplicate verdict needs.
- taskr triage <ref> <verdict> [-e evidence] [-d duplicate-of] Record whether a report is still real. A verdict keeps an issue out of the triage queue for a fortnight, and only an actionable one reaches next.
Nothing enforces a good brief, which is why it is worth saying out loud: an offloaded issue is read
cold, by someone with none of your context, possibly days later. "Login is broken sometimes, might
be a race" costs the next reader more than it saved you. A file:line, a repro, what
you already ruled out, and a definition of done is the whole difference.
Triage answers one question per issue: is this report still real? Bare taskr triage lists what needs that answer and why; show it, check the claim against the tree you
are standing in, then record the verdict with -e naming where you looked. An actionable verdict is the only thing that puts an issue into next.
The other half of intake is not filing what already exists. Every issue's title and description is
embedded by a small model running beside the database — no third-party model API — and kept
current by a sweep every two minutes, so new and offload can answer with
the open issues that say the same thing, however differently they say it:
These are suggestions, not edges: nothing is ever blocked, a closed issue is never offered, and
neither is anything already linked to the one you filed. The same block rides on taskr show --context, taskr triage <ref> lists the twins the duplicate verdict needs, and the bare queue marks pairs in a TWIN column
so a duplicate is visible before either row is opened.
Plans
An issue's steps are its working plan, and the part a resume packet can carry — a plan in your head does not survive the session that wrote it. A step is what you can finish before you stop. Work that spans pull requests or can only be verified after something lands is not a step: it is a child issue, or it is a check.
- taskr step ls <ref> The issue's ordered working plan.
- taskr step add <ref> "title" ["title" …] [--after <pos|id>] [--body <text>] Add steps, in order.
- taskr step start|done <ref> <pos|id> [-m <note>] Move a step. Both record the commit you were at, which is what lets a resume packet say "step 3 of 6, in progress since abc123".
- taskr step mv <ref> <pos|id> --after <pos|id>|--front Reorder.
- taskr step edit <ref> <pos|id> [--title T] [--body T] Reword.
- taskr step drop <ref> <pos|id> -m <reason> Drop a step on the record — the reason is how the next reader knows it was considered, not forgotten.
- taskr step promote <ref> <pos|id> [--child|--check] [--no-block] A step that turned out to be its own issue. --child wires a BLOCKS edge so this issue leaves the ready queue; --check makes it a close gate instead.
Checks
A check is a done-when: a constraint that gates close. taskr never runs the procedure
itself — someone carries it out and records what happened — which is what makes it honest about the
things a tracker cannot verify: a deploy, a production run, a switchover only a person may perform.
- taskr check add <ref> -m <procedure> [--expect <text>] [--human] Register a done-when. --human names who should carry the procedure out, not who records it.
- taskr check ls <ref> An issue's checks, their state, and the ids check run needs.
- taskr check run <id> --pass|--fail [--measure metric=value[unit]] Record what happened. --measure takes typed numbers rather than prose, so two runs can be compared.
taskr next prints pending human-run checks as their own block — that is how a person
finds what only they can move. Closing anyway is --despite-checks, and each pending
check is recorded as skipped rather than quietly dropped.
Links and groups
- taskr relate <ref> <type> <target-ref> BLOCKS, BLOCKED_BY, RELATES_TO, DUPLICATE_OF, DISCOVERED_DURING, DISCOVERED. Refused against a closed issue, so record the ordering while the work is live.
- taskr unrelate <ref> <type> <target-ref> Remove one.
- taskr group add|rm <group> <child> Membership of a group issue — the parent/child edge has its own verbs rather than riding on relate.
Working with other people
Most installs are one person, and everything in this section is silent for them — which is the
rule rather than an exception to it. Every surface answers in the first person. next subtracts what a teammate is live on, context describes your
session, and neither turns into a status board.
An active session is a claim on its issue. Not a lock and not a field somebody sets: a
live session, meaning one seen recently. A session that goes quiet stops holding its issue with no
event, no reaper and nothing to clean up — decay is a predicate, read when somebody asks. That is
what touch is for, and why a harness fires it rather than you.
- taskr team [--all] Who is on what, who went quiet, and what is waiting for pickup — the one surface here written for a person rather than an agent. --all widens past the project you are standing in.
- taskr touch Say this session is still alive. Fired by a harness hook on every turn, never run by hand; it is what stops an hour of reading a diff looking like a dead process.
- taskr park --auto The park a harness makes on the way out, with a note composed mechanically from the tree. A floor under park, not a replacement for it — the note says where the work was and never why.
- taskr skill enforce [--dry-run] Plant the session-start nudge in each harness, and in Claude Code the three lifecycle hooks: touch on Stop and UserPromptSubmit, park --auto on SessionEnd. They never print and never fail.
A Similar open issues: row that says · held by … means somebody is
writing that issue right now: relate DUPLICATE_OF and comment on theirs, do not
start yours. A refused start means report the holder to your human — --join is the answer to a conversation two people already had, never a way past an
obstacle. A handoff is park -r handoff with a note naming the next action and branch @ sha; team lists those as what is waiting for pickup.
People join an org by link. An owner mints one under settings → members and sends it however the team already talks; opening it joins, and opening it without an account lands on signup and joins from there. taskr sends no mail. A link works once and expires in fourteen days.
Documents
A spec that lives only in your checkout is invisible to everyone else working through taskr: show does not surface it and next cannot rank by it, so the next agent
re-derives a design that was already settled and paid for. Committing it to git is not attaching
it.
- taskr doc <ref> The documents linked to an issue.
- taskr doc add <ref> -f <path> [-t spec|plan|note] [--title T] Attach a spec, plan or note. The body is sent, not the path — a reader on another machine has your issue and not your checkout.
- taskr doc show <id> Print one document's body.
- taskr doc history <id> A document's revision history: every body kept, with the --diff summaries, oldest first.
Projects
- taskr project ls Every registered project, with its repos, its directories, and its conventions.
- taskr project init <slug> --key KEY [--name N] [--branch-format F] [--commit-style S] [--pr-target BRANCH] Create a project, or set conventions on one that exists. Idempotent on the slug; a convention you do not name is left alone.
- taskr project attach [--project S] [--repo URL] [--dir SUBPATH] Register this checkout, or a directory inside it, as the project’s territory. Both arguments default to what taskr reads from .git.
- taskr project rename <slug> <new-slug> [--name N] Rename a project.
Auth and skills
- taskr auth login Print a code and a URL, wait for browser approval, and store the key. A piped key still works for CI.
- taskr auth status Which name your writes will carry, without making one.
- taskr skill install [--dir D] [--dry-run] Write the agent skills where Claude Code, Codex, Cursor and opencode read them.
- taskr skill ls Where the skills are, and whether they still match this binary.
- taskr version Which commit this binary was built from, and whether it matches the checkout you are standing in.
A key carries the identity of whoever holds it: a write is recorded as that key's actor, whatever the request body claims. Give an agent its own key, labelled as an agent, and the record tells the two of you apart forever after — which is the one thing the app spends colour on.
Output and environment
Every command takes --json. The default is prose, which matters most for taskr start: the resume packet is the product, not a data dump.
Credentials live in $XDG_CONFIG_HOME/taskr/hosts.json (falling back to ~/.config), keyed by host. Delete that file to make the CLI forget you.
- TASKR_API Selects the host, and defaults to https://api.aitaskr.com — the only one today. It exists so a key can be pointed somewhere else without rebuilding anything.
- TASKR_KEY Overrides whatever is stored for the selected host.
- TASKR_SESSION Names this invocation context, so two terminals — or a terminal and an agent — do not share one work session. Defaults to a session id the harness published (CLAUDE_CODE_SESSION_ID, OPENCODE_PID), and failing that to the parent process id.
- TASKR_REMOTE, TASKR_ROOT, TASKR_HEAD, TASKR_BRANCH Read out of .git and needing no export. Set one only to override it — to file work against a repo you are not standing in.
- TASKR_MERGE_BASE, TASKR_DIRTY The two parts of the tree state taskr cannot read for itself, since a merge base needs a commit-graph walk and a dirty list needs the index diffed against the worktree.
- TASKR_INSTALL_DIR, TASKR_SKILLS Read by the install script only: where the binary lands, and whether the skills are written.
The last pair is the only one worth exporting by hand, and only when the tree state matters to the next reader:
A head is the gate: with no commit to anchor it, no snapshot is sent at all, because a block of
blank fields is worse than an honest "no git snapshot was recorded". The rest are best-effort — a
detached HEAD records as (detached) rather than costing you the snapshot.
The vocabularies
Every enum the flags accept, in one place.
| Flag | Values |
|---|---|
| -k kind | bug, feature, task, chore, spike, question, group |
| -p priority | critical, high, medium, low |
| -s status | open, in_progress, parked, blocked, closed |
| -r reason (park) | done_for_now, blocked, interrupted, context_exhausted, handoff |
| verdict (triage) | actionable, already_fixed, duplicate, stale, needs_info |
| type (relate) | BLOCKS, BLOCKED_BY, RELATES_TO, DUPLICATE_OF, DISCOVERED_DURING, DISCOVERED |