Set up
Install the binary. It is one file for Linux and macOS.
$ curl -fsSL sobanieca.github.io/todoer/install.sh | bash
todoer uses your git email to know who you are. Make sure that git has it:
$ git config user.email
you@example.com
In each project, write the agent skill once and commit it. Claude Code, Codex and Cursor read it, so your agent knows the workflow below. Run it outside a git repository to write the skill in your home folder, for all projects.
$ cd ~/code/my-project
$ todoer skill --init
wrote .agents/skills/todoer/SKILL.md (Codex, Cursor)
wrote .claude/skills/todoer/SKILL.md (Claude Code, Cursor)
The workflow
In this example, you work on main in ~/code/my-project. The same steps work on any branch.
1
Add todos
you
Add a todo with a name, labels and the text. The text can also come on stdin.
$ todoer add fix-the-login-crash -l auth "Steps to reproduce: sign in with an expired token."
.todoer/todos/fix-the-login-crash.md
$ todoer add add-rate-limiting -l auth -d fix-the-login-crash
$ todoer show add-rate-limiting
add-rate-limiting (blocked)
file: .todoer/todos/add-rate-limiting.md
assignee: none
labels: auth
depends on: fix-the-login-crash
waits for: fix-the-login-crash
needed by: none
pr: none
No commit. Commit the todos yourself, or let the claim in the next step commit the new todo file.
2
Claim
agent
youClaim fix-the-login-crash.
The agent runs todoer claim. It sets you as the assignee: the agent runs git with your email. You can also ask for a list of todos, or for all the todos of a label.
$ todoer claim fix-the-login-crash
claimed fix-the-login-crash for you@example.com
$ todoer claim --label auth
$ todoer claim fix-the-login-crash add-rate-limiting
Commit on main: todoer: claim fix-the-login-crash. Push it, so that other people see the claim.
- A claim stops for a todo of another person, and for a todo that waits for a todo that you do not claim. Claim the todos together, or use
--force.
--label skips the todos of other people.
- When your checkout has other changes that are not committed, the claim writes the files but does not commit. Commit them yourself.
--no-commit does the same.
todoer unclaim <name> removes the assignee, and commits too.
3
Implement in a worktree
agent
youImplement it in a worktree.
The agent makes a new branch from your branch in a git worktree, or uses the worktree of its tool. Your checkout does not change. The agent implements the todos in dependency order, runs the checks of the project and commits.
$ git worktree add -b fix-login ../my-project-fix-login main
# the agent writes the code and commits on fix-login
You can give one todo, a list of todos or a label in one request. One pull request can do many todos.
4
Submit into your branch
agent
youSubmit a pull request into main.
The agent runs one command in its worktree. --branch names the branch that the pull request goes into.
$ todoer pr submit --branch main -n fix-the-login-crash -m "Use the retry constant." --todo fix-the-login-crash
submitted fix-the-login-crash: 1 commit, 2 files, into main
.todoer/prs/fix-the-login-crash on main, in the checkout ~/code/my-project
todos: fix-the-login-crash
committed on main
Commit on main: todoer: submit fix-the-login-crash. The pull request is now on your branch. It does not need the branch of the agent: you can remove that worktree and branch.
- The patch has every commit since the work started from
--branch: the commits after the merge base. Commits that change only .todoer/ do not count.
- todoer squashes these commits into one commit in
pr.patch. The author is you. The message is todoer: merge fix-the-login-crash.
- The submit stops when the worktree has changes that are not committed.
-n gives the name. It is necessary: todoer does not make a name.
--todo names each todo of the pull request. The merge removes them.
- When
--branch is checked out, todoer writes the folder in that checkout and commits there. When that checkout has other changes, it does not commit, and you commit the folder yourself.
- When
--branch is not checked out, todoer commits the folder on it directly. See a pull request into another branch.
5
Review
you + agent
youExplain the pull request fix-the-login-crash.
Review in your checkout, where the pull request is. Talk with an agent about the change. Tell it which comments to add.
youOn line 2 of src/auth.rs, ask for a test of the retry path.
$ todoer pr ls
fix-the-login-crash no comments fix-login you@example.com
$ todoer pr summary fix-the-login-crash
$ todoer pr details fix-the-login-crash src/auth.rs
$ todoer pr comment fix-the-login-crash src/auth.rs:2 "Add a test for the retry path."
added the comment c1 on src/auth.rs:2 in fix-the-login-crash
A comment can target a line (src/auth.rs:2), lines (src/auth.rs:1-3), a removed line (src/auth.rs:old:2), a file, a folder (src/) or the whole pull request (no target). You can also read the review alone with todoer pr review <pr>.
pr comment writes review.md and does not commit it. When the review is done, commit it, or ask the agent to:
$ git add .todoer/prs/fix-the-login-crash/review.md
$ git commit -m "Review fix-the-login-crash" -- .todoer/prs/fix-the-login-crash/review.md
There is no approve and no request for changes. If the pull request is good,
merge it. If it needs changes, commit the review and give it to an agent.
6
Update
agent
youDo the review of fix-the-login-crash and update the pull request.
This can be a new agent. It reads the review in your checkout. Then it makes a new worktree and a new branch with its own tool, at the commit base of pr.md, and restores the commit of the pull request with git am. The branch of the first work is not necessary. It does the comments, commits and updates the pull request:
$ todoer pr review fix-the-login-crash
$ git worktree add -b fix-login-2 ../my-project-fix-login-2 <base>
$ cd ../my-project-fix-login-2
$ git am ~/code/my-project/.todoer/prs/fix-the-login-crash/pr.patch
# the agent does the comments and commits
$ todoer pr submit --branch main -n fix-the-login-crash --update -m "Use the retry constant. Add a test."
updated fix-the-login-crash: 2 commits squashed to 1, 2 files, into main
todos: fix-the-login-crash
kept the todos of the old pull request - give --todo to replace them
removed the review (1 comment) - git history keeps it
committed on main
Commit on main: todoer: update fix-the-login-crash. The patch is new and the review is empty. Review again from step 5, or merge.
- Without
--update, a submit does not change an open pull request. It stops and names -n <pr> --update.
--update writes the whole pull request again, as for a new one. -m replaces the description and --todo replaces the todos. Without them, the update copies the old ones and prints what it copied.
-n <pr> --update finds the pull request by its name, so the branch of the update can have any name.
- The patch always applies on
base. Do not apply it on the latest main: it can conflict.
- If the agent tool starts the worktree at another commit, the agent runs
git reset --hard <base> in it first. Files that the tool copies into the worktree, and that git does not track, stay.
7
Merge
you
On your branch, merge the pull request. A merge is the approval.
$ todoer pr merge fix-the-login-crash
merged fix-the-login-crash into main
done: fix-the-login-crash
Commit on main: todoer: merge fix-the-login-crash, one commit with the changes of the pull request. It also removes the pull request folder and its todos. git history keeps them.
- The merge runs
git am --3way. It adds the one squashed commit of the patch. The commits of the work stay only on the branch of the agent.
- The merge stops while the review has a comment.
- When the patch does not apply, nothing changes. Ask the agent to rebase its branch on your branch and to update the pull request.
--no-commit puts the changes in the working tree and the index.
- To drop a pull request, run
todoer pr close <pr>. The todos stay.
Other cases
A pull request into another branch
You work on feature-x, but the pull request must go into main:
$ todoer pr submit --branch main -n fix-the-login-crash --todo fix-the-login-crash
.todoer/prs/fix-the-login-crash on main
committed on main
When no checkout has main, todoer commits the folder on main directly. Your working tree does not change. Check out main to review and merge. --no-commit is not possible in this case.
Make sure that the work starts from main. The patch has every commit after the merge base with --branch.
Run or continue a pull request of another person
You see a pull request on main. To run its code, or to change it, make a new branch from main and apply the patch. It does not commit:
$ git switch -c try-login-fix
$ todoer pr apply fix-the-login-crash
applied fix-the-login-crash to the working tree of try-login-fix - not committed
to update the pull request, commit your changes, then run: todoer pr submit --branch <the branch that the pull request goes into> -n fix-the-login-crash --update -m "<what you changed>"
To update the pull request, commit your changes and run the command that apply printed. Use --branch main: todoer does not guess the branch. -n finds the pull request, so the name of your branch is not important.
When the patch does not apply on your branch, nothing changes. Ask the author to update the pull request.
Plan with labels and dependencies
$ todoer dep add add-rate-limiting fix-the-login-crash
$ todoer add new-login-page -D auth-backend-refactor
$ todoer ls --available
$ todoer dep show add-rate-limiting
$ todoer progress auth
auth 1 in progress, 0 in a pull request, 1 not started [=-]
A todo waits while a todo of its dependsOn exists. todoer refuses a dependency that makes a cycle.
A todo can also wait for a group of todos. -D auth-backend-refactor (or dep add <name> -l <label>) writes dependsOnLabels. The todo waits while another todo has the label, also a todo that gets the label later.
Let the agent add the labels
A label rule tells in plain words which todos must have a label. todoer stores the rule in .todoer/labels/<label>.md. It does not read the words.
$ todoer labels rule auth "Add this label to a todo that changes the login or the tokens."
.todoer/labels/auth.md
$ todoer labels
auth 2 todos
Add this label to a todo that changes the login or the tokens.
When an agent adds a todo, it reads the rules, adds the labels that match, and tells you why. Commit the rules as other files. labels rm and labels mv also remove and rename the rule.
Finish a todo without a pull request
$ todoer done fix-the-login-crash
done removes the file, and removes the name from each dependsOn. When no other todo has a label of a dependsOnLabels, it removes the label from it. It does not commit. To drop a todo, use done too.
See which areas a pull request changes
Name the areas of the code in .todoer/areas, one per line. The patterns use the gitignore rules. The last pattern that matches a path wins.
$ cat .todoer/areas
security: /src/api/auth
tests: /tests
e2e-tests: /tests/e2e
unit-tests: *.test.js
$ todoer pr summary add-rate-limiting
...
areas
security 2 files +48 -6
e2e-tests 1 file +31 -0
unit-tests 1 file +22 -0
(no area) 1 file +4 -1
The summary shows each area that the pull request changes, with the number of files and lines. A pattern with no /, such as *.test.js, matches the file name in each folder. To review only some areas, give their names with -a. To hide some areas, give their names with -x:
$ todoer pr details add-rate-limiting -a security,e2e-tests
$ todoer pr details add-rate-limiting -x e2e-tests,unit-tests
summary and review take -a and -x too.
All your projects
Outside a git repository, todoer ls lists the todos of each project in the current folder and in its subfolders, for example in ~/code. Above the todos of a project, it shows the path of the project and the branch that is checked out there. todoer does not look into a linked worktree.
$ cd ~/code && todoer ls
todoer main
available fix-login
work/api feat/rate-limit
in-progress add-rate-limit me@example.com
Only ls reads many projects. To use another command, go to the folder of the project.