A git-native task manager. Tasks live inside the repo as git objects under refs/tasks/* —
event-sourced, no working-tree files, full history, synced with push/pull like any other ref.
Homebrew (macOS arm64 / Apple Silicon, Linux arm64+x86_64):
brew tap imohsenb/tap
brew install git-taskFrom source (fallback — any platform, requires a Rust toolchain):
git clone https://github.com/<you>/git-task && cd git-task && ./install.sh
# or: cargo install --locked --path .Both install two binaries from the same codebase — git-task (so git task ... works) and
gtask (a standalone alias, e.g. gtask new "title"). Pick whichever fits how you invoke it.
Then, inside any repo:
git task new "Fix login timeout" --kind bug --priority high
git task ls
git task show <id> # id is printed by `new`/`ls`, e.g. SRV-9057e58a
git task status <id> doing
git task comment <id> "found the root cause"That's the core loop. Everything below is reference for when you need more.
git task new "title" --kind bug --priority high --label auth --parent SRV-epic
git task show <id> # boxed detail view
git task show <id> --markdown # markdown instead
git task show <id> --format json # single JSON document (see "JSON output" below)
git task edit <id> --priority critical --assignee alice@example.com
git task edit <id> # no flags: interactive prompts
git task label <id> add urgent
git task label <id> rm urgent
git task log <id> # full audit trail
git task delete <id> # soft delete (syncs, hidden from ls by default)
git task export --all --format md # dump every task
git task whoami # identity a write would be attributed to<id> accepts either the display form (SRV-9057e58a) or a bare hash prefix (9057e58a) — the
KEY- part is cosmetic and stripped before lookup.
git task epic SRV-epic add SRV-child # make a task a child of an epic
git task epic SRV-epic rm SRV-child
git task link SRV-1 add blocks SRV-2 # blocks | relates | dup
git task link SRV-1 rm blocks SRV-2
git task ls --parent SRV-epic # an epic's same-repo children
git task show SRV-epic # full detail, incl. every childBoth also work across repos with --repo <name|path|url> (e.g.
git task link SRV-1 add blocks LB-abc123 --repo backend) — the target repo doesn't need to
share git history. epic --repo additionally requires both repos registered under the same
project (see below) and opens the target to confirm the epic exists; link --repo just records
the reference without validating it (except a URL, stored verbatim).
Register repos so git task ls aggregates across all of them without cd-ing:
git task register # default project "main"
git task register --project web
git task repos # list registered repos
git task projects # repos grouped by project
git task ls # aggregates every registered repo
git task ls --project backend # only one project
git task ls --mine --status doing # filters composegit task clone <url> [dir] # tasks only, no source checkout
git task push # push refs/tasks/* to "origin" (or a named remote)
git task pull # fetch + reconcilepull handles each task independently: new tasks are created, remote-ahead tasks fast-forward,
and tasks edited on both sides get a real two-parent merge commit — no data is lost, everyone
converges on the same result regardless of which side merged. If your side has diverged, push
is rejected until you pull first, same as a normal git branch.
git task clone fetches only refs/tasks/* into a fresh repo — handy for a PM or stakeholder who
just wants to read/triage tasks without the source checkout. It sets up origin, so push/pull
work right away.
git task delete <id>— soft delete. Recorded as an event, syncs to every peer on their nextpull.lshides deleted tasks by default (--deletedto include them). Norestore.git task drop <id> --force— hard delete. Removes the local ref outright, no history entry, local-only (a peer'spullbrings the task right back). Add--remote [name]to also delete it on that remote.
Two layers:
- User-level (personal, not shared):
~/.config/git-task/config.toml— registered repos, their project grouping, default field requirements. - Per-repo (shared, travels with every clone): event-sourced under
refs/tasks/config, edited only viagit task config, never by hand.
git task config show # key, resolved required fields, rules
git task config key SRV # pin the address key
git task config field priority required # this repo only; also: assignee, dueRules run after every mutation and can auto-set fields, add labels, or comment based on conditions:
git task config rule add \
--name auto-triage-bugs \
--on task.created \
--when 'kind == "bug"' \
--do 'set_priority high' --do 'add_label triage'
git task config rule add --global # save to ~/.config/git-task/automation.toml instead
git task config rule list # global + per-repo, resolved--on: task.created | status.changed | comment.added | label.added | task.updated. --when is
an evalexpr condition over kind/status/priority/assignee/title. --do (repeatable):
set_<field> <value>, add_label/remove_label <value>, add_comment "text", and similar for
versions. A rule fires at most once per command; its ops can cascade into other rules but never
back into itself.
Every command accepts --format json. Output is a single JSON document on stdout — safe to pipe
into serde_json/JSON.parse/etc:
error.kind: not_a_repo, identity_missing, not_found, ambiguous_id, validation,
conflict, rejected, remote, io, internal. Tasks in JSON responses are enriched with
display_id/key and resolved *_name fields (assignee_name, etc.) beyond the plain domain
model.
git task skills install teaches a coding agent (e.g. Claude Code) this CLI — addressing,
--format json, task CRUD, config/automation, cross-repo sync — from SKILL.md files embedded in
the binary:
git task skills install # best-effort install into known agent dirs (e.g. ~/.claude/skills)
git task skills install --project # + this repo's .claude/skills, so it travels with the repo via gitcargo build
cargo test # unit + integration tests (real temp repos, real binary)
git task completions bash > ... # also: zsh, fish, powershell, elvishgit task --help (bare) is intercepted by git itself and runs man git-task — without a man page
installed that just prints an error. git task -h / git task help / git task <cmd> --help all
work regardless. Run git task man --install once to fix the bare form too.
