GitHub Plan
Apply task scope and authorization when using this workflow; it defines how existing approval and task boundaries apply.
Outcome
Use GitHub issues as the durable planning database. Keep chat planning ephemeral until the work should survive the current conversation.
Optional surfaces such as GitHub Projects, LaunchPlane, or other local planning views may make work easier to scan, prioritize, or recover, but they are not separate planning backends. GitHub issues remain canonical for plan prose, relationships, blockers, labels, validation, and completion state.
This skill supersedes local file-backed plans for normal GitHub-backed planning. Use local plan files only when the user explicitly asks for an offline/local plan or the work must not be written to GitHub.
Success means one canonical issue or issue graph has a concrete finish line, current recovery state, next action, and accurate dependencies. Optional Projects or local surfaces may improve visibility, but they do not become a second planning backend.
Operating Model
- Think in chat first; do not immediately create issues for fuzzy ideas.
- Search before creating; update an existing issue when intent overlaps.
- Promote durable work to one canonical issue with the configured planning
label, usually
plan. - Treat every human-authored title and body as immutable source material,
regardless of whether GitHub reports the author as
OWNER,MEMBER,COLLABORATOR, orCONTRIBUTOR. Repository role grants permissions, not automation ownership of authored words. Prefer a bot-authored planning comment or a linked maintainer-owned plan. If planning must remain in the contributor issue body, preserve the original request verbatim and update only the marker-delimited automation-owned plan block. Unknown authors and issues created by bots other than the acting planning bot fail closed into this preservation mode. Do not retitle human-authored issues as part of plan expansion. A managed-provenance marker alone never transfers a human-authored body to automation ownership. - Allow
showto read human-authored planning sections, but report their contributor-owned, unmanaged provenance and keep content writes fail-closed. Read permission never grants title or body ownership. - Treat generic GitHub operation comments such as
<!-- github-skill-operation:... -->only as retry/reconciliation evidence; they never establish ownership of an issue body. Association-based managed bodies establish ownership only when the issue was authored by the acting planning bot. Existing contributor envelopes remain contributor-owned even if the author's repository association changes later. - Keep issue bodies structured and current;
Current Statusis the recovery point for future sessions and the preferred durable handoff surface for GitHub-backed planning work. - Use native GitHub dependencies and sub-issues for relationships, including cross-repo relationships.
- Use Projects and other configured surfaces as view layers, not sources of truth.
- Use milestones as strict release, phase, or date gates under the contract below.
- Avoid ad hoc label taxonomies; ask before creating new labels. Generic labels
such as
waiting,blocked, orreadyare discouraged unless the repo explicitly documents a narrow local convention. - Prefer
Refs #123from PRs unless the user explicitly wants auto-close or the issue is an internal task that can be conclusively closed.Refsis deliberately non-closing; after merge, sweep referenced issues and close only the ones whose finish line was actually satisfied. - Optimize for the user finishing work, not for cataloging every possible idea.
Milestone Contract
Milestones describe what must be true to close a release or phase. They are not theme labels or alternate backlogs.
- Before adding an issue, ask: "Can this milestone honestly close while this issue remains open?" If yes, keep the issue outside the milestone even when it is useful or thematically related.
- Put the exact ship or phase-exit criteria in the GitHub milestone description. When assessing readiness or changing milestone membership, read that description and the milestone's open issues first. Do not duplicate transient milestone state in repository instructions or docs.
- Prefer one active milestone per release train. Multiple active milestones are appropriate only for genuinely independent trains with separate exit gates.
- Give each active milestone a due date or a named gate, dependency, or decision that determines when it can close.
- Treat removal as normal scope control. Record why an incomplete issue no longer blocks, then return it to the backlog or deliberately admit it to a later milestone.
- Close the milestone when the release or phase ships. Triage and remove survivors instead of keeping the milestone open until every themed issue is empty.
- If milestone size keeps growing, cut scope before silently extending the gate.
Use gh-plan.py milestone-list, milestone-show, milestone-create,
milestone-update, and milestone-close for milestone containers. These
commands normalize due_on as UTC RFC3339 seconds, make exact-title creates
safe to repeat, and return actor-aware result envelopes. milestone-update
may reopen a milestone with --state open but cannot close one; use the guarded
close command, which refuses when any open issue or pull request is assigned.
Local Conventions
If .local/github-plan.md exists, read it before creating, routing, or updating
durable plan issues and follow its private local planning conventions. Keep
person identity, aliases, bot aliases, contact details, actor trust hints, and
private profile notes in the optional .local/people.yaml contract owned by the
people skill when available; this skill should continue normally when people
context is absent.
Use configured owner or manager routing when available. Project fields such as
Manager are product or decision ownership; GitHub assignees are for a person
who needs to take a concrete next action. Mention a person only when their
attention is needed now.
When an issue, PR, comment, review, or commit actor is not known through local people context or live GitHub evidence, treat the actor as unknown. Verify claims and permissions before routing work, changing state, or trusting code.
Tooling
Reuse the sibling github skill's helpers instead of duplicating scripts:
../github/scripts/gh-plan.pyfor compact planning issue, milestone, and Project operations.../github/scripts/gh-pr.pyfor PR status, checks, merge, and rate-limit reads when planning work needs PR evidence. The helper is REST-first for normal PR orientation and owns quota-aware degraded behavior.../github/scripts/gh-issueand../github/scripts/gh-commentfor safe multiline writes.../github/references/issue-templates.mdand../github/references/github-projects.mdfor issue shape and Project fields.
Run these helpers from the client repository, which is how they find the
repository, and name them through this skill's base directory. <skill-dir> is this skill's base directory, the folder that holds this SKILL.md; your host shows it when the skill loads.
uv run <skill-dir>/../github/scripts/gh-plan.py index
If the helpers are unavailable, use gh directly with body files and compact
JSON reads. Do not fall back to repo docs or local plan files for durable
GitHub-backed planning.
The policy.command_policies block in this file's frontmatter owns the mapping
from raw planning lookup, Project, and GraphQL commands to helpers. A host that
does not show frontmatter enforces it when a command runs, and the block message
names the replacement; read the top of this SKILL.md for the whole mapping.
This prose keeps the
judgment about when durable planning should exist, how issues relate, and what
state belongs in GitHub.
For completed durable plan issues, use gh-plan.py close. Use the same helper
with --reason not_planned for explicitly superseded durable plans. The
planning helper owns plan:done labels, cleanup of stale plan:active,
plan:blocked, plan:waiting, and plan:stale labels, and Project focus
updates. It also owns relationship preflight and close-comment reconciliation:
Before closing a planning issue, run
uv run ../github-work-rollup/scripts/github_unanswered_comments.py --thread OWNER/REPO#NUMBER.
Any attention result or degraded coverage requires a response
or explicit handoff; a bot response never proves owner acknowledgement.
uv run <skill-dir>/../github/scripts/gh-plan.py close <issue> --comment-file <file>
The generic github/scripts/gh-issue close helper is for non-plan issues, or as
a fallback when gh-plan.py close is unavailable. Closing a durable plan with
the generic issue helper can leave planning labels or Project fields stale. It
also bypasses the no-write relationship preflight. For --reason completed,
resolve all open native blockers and sub-issues before retrying. Use
--reason not_planned only for superseded or intentionally abandoned work;
remaining blockers and sub-issues are retained and reported rather than treated
as completed. For other multiline writes, prefer body files or stdin. Do not
pass escaped \n through shell-quoted flags. Follow
../references/every-code-formatting.md when writing durable issue bodies,
planning comments, handoffs, or closeout evidence.
Broad Workstream Rule
Create a parent issue plus sub-issues when a plan has independent tracks. Do not hide broad work inside one checklist.
Use sub-issues when any two are true:
- touches three or more modules, repos, systems, or ownership areas
- has independent sequencing, blockers, or parallelizable tracks
- includes research, implementation, validation, and policy/design decisions
- has work that can finish or be reviewed independently
- needs roadmap/focus tracking beyond the current session
Parent issues should hold intent, finish line, dependency order, and recovery state. Child issues should each have one scoped finish line and one next action.
Plan Direction Checkpoints
Long-running work drifts when the agent keeps following local discoveries without reconnecting them to the durable plan. Treat the plan and issue graph as the navigation layer, not as paperwork.
At natural transition points, answer:
What is next?
How does it fit the current plan?
Did the plan or issue graph change?
What blocker, evidence, or decision explains the direction?
When durable GitHub plans exist, run gh-plan.py next before choosing roadmap
work. Treat its native blocked-by evidence as authoritative; milestone and
Project Focus fields explain context and ranking but do not override blockers.
The command is advisory and read-only, so update labels, Focus, or relationships
separately only after the direction is confirmed.
Run this checkpoint:
- after each implementation slice
- after surprising findings
- before starting adjacent work that was not already planned
- before creating, closing, or superseding issues
- before handoff or closeout
- when the user asks "what's next", "where are we", or "how does this fit"
If the next action still matches the plan, answer briefly and continue. A
passing checkpoint does not need a written artifact. Update Current Status
only when the durable recovery state materially changed. If reality changed the
plan, update the canonical parent issue, sub-issues, blockers, relationships,
labels, and Project focus before relying on chat memory. If a new thread of work
appears, classify it as current scope, sub-issue, blocker, related issue, or
later. Do not let it become an untracked pivot.
For broad workstreams, prefer issue graph changes over prose-only status:
- create a sub-issue for independently finishable work
- add
blocked-by/blocksfor real execution dependencies - use
relatedfor context that should not drive sequencing - mark stale or superseded plans clearly
- keep the parent issue's
Current Statusas the recovery point
When another repo workflow is waiting on CI, deploy, review, or post-merge health, keep the main checkout available for verification and parallelize safely: use read-only exploration or isolated work only for independent planning or implementation prep, then return to the waiting workflow before calling it done.
Use Focus lanes when configured:
Now: one thing the user and Code are actively trying to finish.Next: ready after Now or after the manager chooses it.Waiting: blocked or awaiting an external decision/event.Later: real but intentionally out of focus.
Prefer at most one Now item unless the user explicitly chooses parallel work.
Use planning status labels with narrow meanings:
plan:active: actionable now.plan:blocked: blocked by a real, current dependency, preferably represented by a native GitHubblocked-byrelationship to an open issue.plan:waiting: intentionally parked on non-issue evidence, a user/customer/maintainer decision, or a future real-world event. Use this only on durable planning issues labeledplan, not on ordinary bugs, PRs pending QA, preview review, reporter validation, deploy, or merge readiness.plan:stale: needs review before it should guide work.plan:done: completed or superseded.
Do not use plan:blocked merely because work is not currently in focus. If an
issue has no open native blocker, prefer plan:waiting and make Current Status say Waiting for: or Parked until: with the concrete condition.
If a non-issue condition truly blocks execution, include Blocked by: No native issue blocker; waiting for ... so future audits do not chase missing edges.
If LaunchPlane or another local context helper is configured and useful for
orientation, call it once before or alongside index. Treat unavailable,
unauthorized, invalid, or missing context as normal absence and continue with
GitHub-only planning. Use local surface output only as a hint for source links,
readiness, blockers, and next inspection targets; do not copy private context
payloads into public issues, PRs, or handoffs unless they have been reviewed for
public safety.
Token Discipline
Prefer the installed github/scripts/gh-plan.py helper for planning state. It
returns compact JSON and avoids loading issue bodies unless needed.
index uses paged repository-issue REST reads and explicitly excludes pull
requests. search uses paged REST issue search with repo: and is:issue
constraints plus the dedicated search quota bucket. Use show or deps when
relationship, dependency, or sub-issue details are required; index and search
intentionally preserve their smaller legacy result shape. Label maintenance
uses paged REST label reads and reconciles concurrent creates without retrying
the write blindly.
create performs exact-title dedupe through REST issue search, ensures labels
through REST, and delegates the non-idempotent issue write to the shared issue
helper so unknown outcomes carry reconciliation evidence. close first pages
native blocked_by dependencies and sub-issues through REST and fails before
mutation when a completed plan is incomplete or relationship reads are unsafe.
Configured Project synchronization remains the only GraphQL-backed phase and
runs before issue closure so the item stays discoverable. Confirmed or
read-reconciled issue closure is the commit point for planning labels and the
optional timeline comment. Re-running the same command reconciles partial
metadata and reuses an identical acting-user comment instead of duplicating it.
If closure fails after Project writes, report the helper's split project_state
and rerun the same close command; do not add completion labels or comments by
hand while the issue may still be open.
Project v2, native sub-issues, and native dependency operations may require GraphQL. Before batching those operations, check rate limits when failures look quota-related. If GraphQL is exhausted but REST/core is available, keep issue body/status updates moving through REST-backed helpers and record Project or native relationship updates as waiting rather than retrying until the LLM workflow stalls.
- Use
indexorsearchbefore creating. - Use
showfor selected sections; useshow --fullonly when broad prose is required. Inspect the returned provenance before attempting a body update;section_updates_allowed: falsemeans the current body shape must remain read-only. A plain contributor request without unmarked planning headings or reserved ownership markers may still be wrapped in the preservation envelope byupdate-section. - Treat
ownershipvalues asautomation_managed,contributor_envelope, orcontributor_unmanaged. If ownership markers are malformed,show --fullstill returns the raw body withownership: unknown, while section parsing and every body write remain fail-closed. - Use
update-sectioninstead of rewriting the whole body. - Use installed
github/scripts/gh-issueandgithub/scripts/gh-commentfor multiline Markdown bodies.
Issue Shape
Durable planning issues should use the headings in
../github/references/issue-templates.md.
Keep Current Status short and concrete:
State:
Next action:
Blocked by:
Waiting for:
Last verified:
Use Blocked by: for issue dependencies and Waiting for: or Parked until:
for non-issue conditions. Avoid listing completed work as a blocker; move it to
Relationships as completed or historical context.
Include decisive validation evidence only when it changes recovery state, such
as the current blocker, last verified environment, or proof needed to resume.
Keep raw logs, large check output, screenshots, and detailed run evidence in the
linked PR, workflow run, artifact, or comment instead of bloating Current Status.
Keep Finish Line observable. If the finish line is vague, narrow it before
creating sub-issues or Project fields.
Relationship Semantics
blocked-by: current issue cannot move until the target changes.blocks: current issue is holding up the target.subissue: target is part of the current workstream and can be tracked independently.related: useful context without execution dependency.
Use native relationships first when the helper/API supports them. Body
references are explanatory, not canonical.
Native blocked-by, blocks, and subissue operations do not require
ownership of either issue body because they update GitHub relationships without
rewriting source text. related remains a markdown body update and therefore
keeps the normal plan-body ownership checks.
Completed closure requires every native blocked-by target and sub-issue to be
closed. Issues that the plan itself blocks do not prevent closure. An unavailable
or malformed relationship read is a no-write failure, not permission to assume
the graph is clear. not_planned closure is intentionally different: it may
retain open blockers or sub-issues, reports them in the result, and preserves the
GitHub not_planned state reason as the durable supersession signal.
Missing Cross-Repository Gates
When another repository's maintainer must create or identify a prerequisite
issue before downstream blockers can be linked, include a return-and-link action
in the canonical waiting record. Use an automation-owned Current Status or a
bot-authored planning comment under the existing body-ownership rules:
- Name the gate maintainer, downstream coordinator, return thread, and affected downstream issues, using the existing actor routing.
- Explicitly ask the maintainer to reply/tag the coordinator in that thread with the canonical gate links and relevant completion criteria when ready.
- Name who will verify the returned gate's scope/status and add or reconcile the native blockers under existing authorization. Relationship updates do not require rewriting a protected issue body.
Use Waiting for: and, while no native blocker exists, Blocked by: No native issue blocker; waiting for .... Existing label and Focus rules still apply;
milestone membership or a mention alone does not establish a native dependency.
Do not claim the missing gate or link exists until verified. Once the gate is
known, use normal dependency tracking without an extra return round-trip.
Reuse applicable approval; when posting authority is missing, prepare the draft
and identify the remaining action. This rule does not authorize messages,
mentions, unrelated writes, or recurring notifications/monitoring.
Example draft: "Gate maintainer: create or identify the prerequisite for
OWNER/CLIENT#28, then reply to the client coordinator on that issue with its
canonical link and completion criteria. The coordinator will verify it and
reconcile the native blocker under existing authorization. Until then, the
client issue waits for gate identification and linkage."
Related Issue Sweep
Stale GitHub planning state is a regression source. Before closeout, handoff, or declaring a workstream done, search for related, duplicate, stale, parent, sub-issue, blocker, and PR-linked issues that might still describe the old state.
- Update every related issue whose
Current Status, labels, blockers, relationships, or acceptance criteria changed. - Close or relabel stale duplicate issues when they no longer represent current work.
- Prefer updating the canonical parent and linked sub-issues over leaving corrective context only in chat or PR comments.
- If an old issue might mislead a future agent, treat it as unfinished cleanup, not optional housekeeping.
After a canonical PR merges, inspect the issues it references with Refs,
Closes, Fixes, or Resolves. Refs should remain non-closing by default.
For each referenced issue, either close it with evidence when the merge
conclusively satisfies the finish line, or update/comment the remaining state
and leave it open. Use gh-plan.py close --comment-file for durable plan issues
so planning labels and Project fields stay synchronized. Use installed
github/scripts/gh-issue close with a multiline evidence comment for non-plan
issues.
Local handoff documents are not durable planning records unless the user asked
for offline/private handoff. If a session created handoff*.md or similar
scratch files, migrate recovery-critical content into the owning GitHub issue or
PR comment before closeout and then delete or explicitly preserve the file.
When repository cleanup finds valuable local work that needs parking, read the shared repository cleanup and preservation and parking and handoff procedures. Do not create planning state for routine disposable artifacts. For bulk cleanup or repository retirement, use a GitHub issue only after its capability, canonical ownership, publication authorization, and durable recovery contents satisfy those policies.
Projects And Surfaces
Planning surfaces are optional views over GitHub issue-backed plan data. They may help people choose work, inspect roadmap shape, or recover context, but they must not replace the GitHub issue as the durable record.
Add plans to Projects when repo/workspace config defines a default Project or
the user asks for Project tracking. Use only a few human-facing fields: Focus,
Manager, Finish Line, Roadmap Start, and Roadmap Target.
When issue create/close succeeds but the helper returns a non-blocking Project warning, mention it briefly and present the helper's human choices. Do not retry repeatedly or silently switch to active human auth. Project auth/config fixes are human decisions: grant automation Project access, use Project-capable auth, disable Project sync, or correct stale Project config.
Treat roadmap dates as planning anchors, not commitments. Keep them useful for LLM-assisted coding by using honest day, week, or month windows and moving or clearing stale dates when reality changes.
Closeout Check
Before saying a plan is captured, verify:
- existing issues were searched
- parent issue exists for a broad workstream
- sub-issues exist when the Broad Workstream Rule applies
- blockers/dependencies are represented
- stale, duplicate, related, and PR-linked issues were swept and reconciled
Current Statusand next action are concrete- the next action says how it fits the current plan
- issue graph changes caused by the session were applied or explicitly parked
- docs are not being used as active plan state
Workflow
- Decide whether the work is ephemeral or durable.
- Resolve the repo and read the active issue's finish line,
Current Status, next action, blockers, and comments; comments may supersede the original body. - Run
nextbefore selecting roadmap work, and useindexorsearchbefore creating anything; then draft or revise the issue shape with the user in chat when intent is unclear. - Create or update the canonical parent issue and choose one next action.
- For broad workstreams, create scoped sub-issues and represent blockers, dependencies, and related context in the issue graph.
- When discoveries change direction, run a Plan Direction Checkpoint and update durable state before pivoting.
- Add configured Project fields only as view/tracking layers; keep the user in maker mode instead of duplicating management state in prose.
- Before pausing, keep
Current Status, acceptance criteria, decisions, validation, and the next action current. Do not leave a local handoff file as the only recovery source for GitHub-backed work. - When work completes, update status and close durable plan issues with
gh-plan.py close; do not leave stale local plan files behind.