This page gives the steps and the GitHub facts to file issues, blocked-by links and milestones on GitHub. Before a post covers each session that posts an issue, except where a sentence names the planner. A recurrence covers each session. The rest of the page is for the planner, but The blocked-by links also serves each session that decides links before a post. planner.md defines the terms "planner" and "blocked-by link", and docs/sessions.md defines the term "user". planner.md also holds the rules for what an issue says and where it goes. This page holds only how to do it on GitHub.
-
Each session that posts an issue, or changes the title or the body of an open issue, drafts the text first. The session shows the draft to the user who works with that session. A request of the user such as "file an issue" or "draft a ticket" gets a draft first. For a change to an open issue, the draft shows the changed text. The session posts only after the user approves that draft, for example with "file it" or "post it". The follow-up planner posts a reviewed draft with no approval of the user, as The review loop of a draft of planner.md says. The approval of the user still covers a draft of the initial planner and a comment. For a draft of the follow-up planner that waits for a decision of the user, The escape hatch of planner.md says what the answer of the item does. The planner also makes sure of the kinds of GitHub objects to make, as The order of the work of planner.md says.
-
For a change of the title or the body of an open issue, the session reads both at the start of the draft. The draft starts from that read, not from an older draft file. The same read gives the start hash, the output of
sha256sumover the JSON of the read. An example of such a read isjson=$(gh issue view <number> --json title,body) && printf '%s\n' "$json" | sha256sum && printf '%s\n' "$json" | jq -r '.title, .body'. If the read fails, the session does not start the draft, and it tells the user. The read in the write call compares the start hash with a new hash of the issue right before the write.Other sessions can change an open issue after a post, and a post of an older text undoes their change. On 2026-11-04, the body of #766 changed about 15 minutes after its post, while the draft file of the planner still held the older paragraph.
-
Right before each post, the session that posts the issue searches all the issues of the repo, open and closed, by title and by body, for the same change. Other sessions file issues at the same time, so the list changes between two turns. An example search is
gh issue list --state all --search "<words> in:title,body" --limit 1000. The session runs the search in its own command and reads the result. Then the session posts the issue in a later command. A search and a post in one command post the issue before the session sees a match. For example, on 2026-10-18, orchestrator-m13 ran the search andgh issue createin one command and posted #307. The search had found #285, which already covered one item of #307. A later edit of both issues moved the item. -
If an issue already covers the change, the session that posts the issue offers the user an extension of that issue (its body or its links) instead of a new issue. That session tells the user what each draft has that the other one does not have. For a match of the follow-up planner, The review loop of a draft of planner.md gives the steps.
-
Each session that posts an issue and is not a planner, also a session with no role, decides the blocked-by links of its draft. The session finds the open issues and the tasks in flight that edit the same files as the draft. The session also finds the issues that the draft needs. The session uses the rules of The blocked-by links of planner.md.
The session shows the result with the draft: each link to add and its reason, or the words "no links" and the reason. The session names each file of the check. After the post, the session adds each approved link, as The blocked-by links and The read in the write call say.
-
The text of each post follows the simple-english bullet of Docs of rules.md. Before a session shows a draft to the user, the session runs the self-check of the simple-english skill over the file of the draft. The ticket subagent of a planner runs the check over its draft file before the first loop of The review loop of a draft of planner.md. The check counts the words of each sentence. It also searches the draft for the banned words and for an
ifor awheninside a sentence. The session fixes each hit before it shows the draft. For example, on 2026-10-15, a draft had four sentences over the limit, and one search and one word count over the draft file found them. -
For the priority of an issue, see The body of an issue of planner.md and The project board.
-
Right after each post of the body of an issue, the session compares the posted body with the body of its draft file. The body of a draft file is the file with its title line and the blank line after it taken out. An example of the compare is
diff <(gh issue view <number> --json body -q .body) <body of the draft>. The compare ignores blank lines at the end, because the read adds one.A difference is a failed post. The session then posts the body again, as The read in the write call says, and compares again. If the read fails, or the second compare also fails, the session stops and tells the user. On 2026-10-26, a script left an old second design after the Docs section of #604, and only a review agent saw it.
This rule covers each session that adds a blocked-by link to an issue, or changes the title or the body of an issue. The session runs one Bash call with these steps, in this order:
- Run
tasker status. - Read the state of the issue, for example with
gh issue view <number> --json state -q .state. - For a change of the title or the body, run
json=$(gh issue view <number> --json title,body) && printf '%s\n' "$json" | sha256sum. If the command prints a hash that is not the start hash, skip step 4. - If
tasker statuslists no task for the full key of the issue and the state isOPEN, do the write.
If the issue is in flight or closed, the call skips the write, and the session tells the user. The issue is in flight
when tasker status lists a task for the full key of the issue. If tasker status or a read of the issue fails, the
call skips the write, and the session tells the user.
If step 3 prints a hash that is not the start hash, the call skips the write, and the session tells the user. In that case, the issue changed after the start of the draft. The session starts the draft again from the new title and body, as Before a post says. A second post after a failed compare of Before a post skips step 3, because the issue then holds the text of the failed post. A change of both the title and the body goes in one write, because a first write changes the hash for a second write.
Before this call for a new blocked-by link, the session does a walk of the open blockers. The walk starts at the blocker
of the new link. The session reads the blockers of each issue with --paginate and the read command of
The blocked-by links. It follows only blockers with the state open, in lowercase, and it
reads each issue one time. If the walk reaches the blocked issue of the new link, the link closes a cycle. A cycle is a
chain of blocked-by links that comes back to its first issue.
If the walk finds a cycle, the session skips the write. It tells the user each issue of the cycle. If a read of the walk fails, the session skips the write and tells the user. If the session reverses a link, it removes the old link before the walk.
While no ticket of a cycle is in flight, a cycle stops each ticket of the cycle and each ticket that waits for one of them. A walk in an earlier call can be old at the write, and this rule accepts that. On 2026-10-26, the link "#477 waits for #572" closed a cycle of four issues, and GitHub took the link.
A read in an earlier call can be old, because a task can start or the issue can close between the read and the write. On 2026-10-18, a new link of the relinked Docs chains landed on #302, which started after the planning session read the tasks in flight. The same day, a script changed the body of #288 after #288 closed, because its check covered only the tasks in flight.
A link can still land on a task that started between the read and the write. Then the session removes the link with the command of The blocked-by links. The session tells the user that the link was a race. In that case, the orchestrator did not skip a blocker.
For a blocked-by link, the skip of an issue in flight covers only a soft blocker. A soft blocker is a link with no need of the work of the other ticket, for example for two tickets that edit one file. A hard blocker is a link for a ticket that needs the work of the other ticket. The session adds a hard blocker to an issue in flight, and it tells the user. A direct word of the user to add a soft blocker overrides the skip for that link. The session does not remove a hard blocker or a link of such a word as a race.
The paragraph before this one does not cover a closed issue, a failed read or a change of a title or a body.
A recurrence is a problem that shows again while an open issue already covers its fix. A recurrence comment is a comment on that open issue that gives the new case. This section covers each session, also during the work.
- A session that finds a recurrence and is not the planner sends the recurrence to the planner, as each lesson goes. The message names the open issue. For the orchestrator, the planner bullet of The prompt of a task subagent of pick-the-tickets.md gives the message.
- The planner drafts the recurrence comment. The comment gives the ticket, the date and the facts of the new case. The planner shows the draft to the user, as Before a post says. The planner posts the comment after the approval.
- With the draft, the planner gives the user one recommendation for the issue: no change, a priority, another milestone, or new blocked-by links. The user decides. After the approval, the planner makes the change in the same post round.
- A change of the milestone follows The milestone of an issue of planner.md. A
change of the links follows The blocked-by links of planner.md, as for any issue.
That also covers the read of
tasker statusbefore a link.
On 2026-10-24, #406 showed the problem of #391 again during the work, not in a /session-review. The user said: "if we
see a recurrence we can bump up its priority and adjust the milestone and blockers."
The rules for the links are in The blocked-by links of planner.md. The commands below work with gh 2.101.0:
- To add a link:
gh issue edit <blocked number> --add-blocked-by <blocker number>. - To remove a link:
gh issue edit <blocked number> --remove-blocked-by <blocker number>. - Both commands take issue numbers.
- To read the links of an issue:
gh api repos/<owner>/<repo>/issues/<number>/dependencies/blocked_by.
- The board is the user project "tasker": https://github.com/users/codeguru42/projects/3 (number 3, id
PVT_kwHOACGSlc4BmiTL). It is linked tocodeguru42/tasker. - The Status field has the id
PVTSSF_lAHOACGSlc4BmiTLzhlK7j4. Its options are Todo (f75ad846), In progress (47fc9ee4) and Done (98236657). - The field
Priorityhas the idPVTSSF_lAHOACGSlc4BmiTLzhlK7oI. Its options areP0(79628723),P1(0a877460) andP2(da944a9c).P0is the highest priority, andP2is the lowest. The priority of an issue is the value of this field on the card of the issue. A card with no value has no priority. - To set the priority of an issue:
gh project item-edit 3 --owner codeguru42 --url https://github.com/codeguru42/tasker/issues/<number> --field Priority --value <option>.<option>is the name of an option of the fieldPriority, for exampleP0. This form and the form of the bullet "To move a card" need gh 2.97.0 or later. - To read the priority of an issue:
gh project item-list 3 --owner codeguru42 --limit 1000 --format json --jq '.items[] | select(.content.type == "Issue" and .content.number == <number>) | .priority'. The command prints the option, for exampleP0. If the card has no priority, it prints an empty line. If the issue has no card, the command prints nothing. gh project item-listlists at most 30 items by default. So eachgh project item-listcommand of the docs gives--limit 1000.- The list of
gh project item-listcan miss the card of an issue. On 2026-11-04, the list missed the card of the open issue #765, whilegh issue view 765 --json projectItemsshowed the card in Todo. No one measured the cause. So the commands of the docs that change a card find the card from the issue, not from the list. - A workflow of the board adds each new issue with the status Todo within a minute. The planner does not run
gh project item-addfor a new issue. The workflow sets no priority, so a new issue has no priority. - The board moves an issue to Done when the issue closes. The board archives a closed item 7 days after its last update.
- To move a card:
gh project item-edit 3 --owner codeguru42 --url https://github.com/codeguru42/tasker/issues/<number> --field Status --value "<option>".<option>is the name of an option of the Status field, for exampleIn progress. - The gh token needs the scopes
projectandread:project. Ifgh project item-editfails with "missing required scopes [project read:project]", the user runsgh auth refresh -s project,read:project. - A fine-grained token cannot open a project of a user, because its Projects permission applies only to an organization.
The milestone of an issue of planner.md gives the milestone of each issue. The
planner closes a milestone only when the user says so. Then it runs
gh api -X PATCH repos/codeguru42/tasker/milestones/<number> -f state=closed.
Pick the tickets of pick-the-tickets.md gives the report of an orchestrator when
its milestone is done.
Before the command, the planner reads the open issues of the milestone. If the read or the command fails, the planner tells the user, and the milestone stays open. If the milestone has an open issue, the planner tells the user. It then runs the command only on a new word of the user. After the command, the planner deletes each memory note whose delete condition is the close of that milestone. Then the planner tells the user the result.