A file-based task manager
1# tsk for agents
2
3`tsk` is the task tracker maintained alongside this codebase. Use it to
4discover what to work on, record TODOs you spawn, and mark work done.
5
6## Quick reference
7
8```
9tsk list # active queue, top first
10tsk show -T tsk-N # render one task (rich text)
11tsk show -T tsk-N -x # also dump properties as YAML front-matter
12tsk push -- "title" # new task at top of active queue, status=open
13tsk push -- "title
14body" # multi-line title gets split at first newline
15tsk push -- "title" -b - # read body from stdin
16tsk drop -T tsk-N # remove from queue, flip status=done
17tsk edit -T tsk-N # open $EDITOR on the task body
18```
19
20## Properties
21
22Every task has zero or more text values per property. Status is auto-managed
23(`open` on push, `done` on drop). Anything else is set by hand:
24
25```
26tsk prop add -T tsk-N <key> <value> # append a value
27tsk prop set -T tsk-N <key> <values...> # replace the whole list
28tsk prop unset -T tsk-N <key> [<value>] # drop one value, or the whole key
29tsk prop list -T tsk-N # all (key, value) lines on a task
30tsk prop find <key> [<value>] # tasks with that key (= value)
31tsk prop find status open # all in-progress tasks
32```
33
34## Namespaces and queues
35
36The repo has two of each by convention:
37
38| Kind | `tsk` | `claude` |
39|-------------|--------------------|----------------------------|
40| Namespace | user-owned task ids| agent-owned task ids |
41| Queue | user's backlog | agent's backlog (TODOs) |
42
43Both are pushed/shared at `refs/tsk/{namespaces,queues,tasks,properties}/*`.
44The active selection is per-clone (lives in `<git-dir>/tsk/`):
45
46```
47tsk namespace current # what you're reading/writing as
48tsk namespace tasks # every (id, title) bound here, ignoring queue
49tsk queue current # what your push/list/drop affect
50tsk switch <name> # switch namespace (no arg = fzf-pick)
51tsk queue switch <name>
52```
53
54## When you spawn a TODO
55
56If you find scope-creep or follow-up work, push it to the `claude` queue
57rather than expanding the current task or dropping a `// TODO:` in code:
58
59```
60tsk queue switch claude
61tsk push -- "<short title>
62<body explaining why and what to do>"
63tsk queue switch tsk # switch back when done
64```
65
66This keeps the user's `tsk` queue free of agent-internal bookkeeping while
67still surfacing the work for later.
68
69## History
70
71Every task and namespace is a commit chain in git, so edits are
72auditable:
73
74```
75tsk log task -T tsk-N # all commits on a task's tree
76tsk log namespace [<name>] # id assignments / drops in a namespace
77tsk log queue [<name>] # pushes / drops / inbox moves in a queue
78```
79
80## Migrations
81
82Storage and conventions evolve. A single command runs every known one-shot
83fix-up against the active workspace; safe to re-run (each migration is
84idempotent):
85
86```
87tsk fix-up
88```
89
90## Sync with the user
91
92```
93tsk git-setup [-r <remote>] # one-time per clone: configure refspecs so plain
94 # git push/fetch will carry refs/tsk/* (default remote
95 # is "origin"). Mutates .git/config; opt-in.
96tsk remote set-default <name> # use this git remote for git-push/pull and the auto-push paths
97tsk git-push # push refs/tsk/* to default remote (also runs after assign/reject)
98tsk git-pull # fetch + reconcile divergent task histories (with merge driver)
99tsk git-pull --rebase # replay local commits on the remote tip instead of merging
100tsk inbox # auto-pulls then lists pending inbox items
101```
102
103Use `tsk git-pull` (not plain `git fetch`) when local task / queue /
104namespace refs may have diverged from the remote — only the tsk command
105runs the 3-way merge driver. Plain `git fetch` force-overwrites them.
106
107Note: `tsk git-setup` adds `remote.<name>.push = refs/tsk/*:refs/tsk/*`
108which OVERRIDES `push.default`. After running it, `git push` with no
109args pushes the configured refspecs only (i.e. tsk refs) — branches
110need an explicit `git push <remote> <branch>`. If that's not what you
111want, just keep using `tsk git-push` and skip the setup.
112
113## Offline transfer (email, etc.)
114
115Export a task as an mbox-format patch series and pipe it anywhere:
116
117```
118tsk export -T tsk-N [--bind] > task.mbox # one mbox entry per commit
119tsk import [--bind] < task.mbox # rebuild + verify on receiver
120```
121
122`--bind` on export embeds your namespace+human-id; `--bind` on import binds
123the task into the receiver's active namespace. Stable ids are content-
124addressed, so the receiver verifies the SHA on import — tampered patches
125are rejected.
126
127## Conventions for agents working this repo
128
129- Always `tsk list` first. Don't invent work; pick the top task or ask.
130- Run from `./target/release/tsk` after any rebuild (the user's installed
131 `tsk` may lag behind your changes).
132- Drop a task only when the work is committed (or the user has confirmed).
133- Properties you set are pushed; treat them as user-visible state, not
134 scratch space.
135- Markup in task bodies: `!bold!`, `*italic*`, `_under_`, `~strike~`,
136 `=highlight=`, `` `code` ``, `[text](url)`, `[[tsk-N]]`. Stripped on
137 `tsk show -R`.