plan-creator

star 3

Creates structured planning documents for new features or tasks in the @plans directory. Use when the user asks to create, write, or draft a plan for a feature, task, or implementation. Performs deep codebase research using parallel subagents before writing the plan to ensure accuracy.

4IRL By 4IRL schedule Updated 6/13/2026

name: plan-creator description: Creates structured planning documents for new features or tasks in the @plans directory. Use when the user asks to create, write, or draft a plan for a feature, task, or implementation. Performs deep codebase research using parallel subagents before writing the plan to ensure accuracy.

Step 0: Sub-Plan Detection

Before Branch Guard, check whether this is a sub-plan of an existing master plan. A sub-plan inherits its branch and topic folder from a specific step in the master — it does NOT get inferred or asked about.

Triggers (any one is sufficient)

  • User's request contains patterns like step N of <master>, sub-plan (of|for) <master>, phase N of <master>, next step of <master>, or explicitly references a file path matching plans/*/*-master.md.
  • The current branch matches a **Branch:** value in any plans/*/*-master.md. Grep for ^\*\*Branch:\*\* \`` across master files.

If triggered

  1. Locate the master. Glob plans/*/*-master.md. Disambiguate by filename match to user's reference first, then by branch match; if still ambiguous use AskUserQuestion to let the user pick.
  2. Resolve the target step. If the user said "Step N", extract the number. Else match by description or by **Branch:** equal to the current branch.
  3. Require a **Branch:** field on that step (backtick-quoted). If missing, error out:

    "Master plan <path> Step N has no **Branch:** field. Regenerate with /master-plan-creator or add the field manually before creating the sub-plan."

  4. Extract <target-branch> from the backticks.
  5. Derive <topic> — the last path segment of <target-branch> (e.g., ts/feature-splashfeature-splash, infra/openapi-typescript-codegenopenapi-typescript-codegen).
  6. Store <sub-plan-mode>=true, <target-branch>, <topic>, <master-path>, <step-number> for use in later steps.

When sub-plan mode is active, Branch Guard and Step 1 use the overrides below; otherwise follow the normal flow.

Branch Guard

Default behavior (not sub-plan mode):

  1. If on main or master:
    • Run gmas to ensure main is up to date with remote
    • Create and switch to a suggested feature branch based on the task context (e.g., refactor/splash-validation, fix/login-error) — do NOT ask for confirmation, just do it
    • Inform the user which branch was created, then proceed
  2. If on a different branch:
    • Use AskUserQuestion to ask whether to:
      • Switch to main first — run gmas to switch to main and pull latest from remote, then create a new feature branch from there
      • Stay on current branch — proceed with plan creation on the current working branch without switching
    • Follow the user's choice before proceeding

Sub-plan mode override (when Step 0 set <sub-plan-mode>=true):

  1. If already on <target-branch>: stay — proceed.
  2. If on main/master: run gmas, then git checkout -b <target-branch>. No confirmation needed.
  3. If on a different branch: use AskUserQuestion — "Switch to <target-branch> (checkout from main), or stay on current branch?"

Step 1: Determine Topic Folder

Default behavior (not sub-plan mode):

  • Infer <topic> from the user's request (e.g., request about URL model changes → urls, about API decorators → api-route, about OpenAPI → openapi).
  • If the topic is not obvious, ask: "Which topic folder should this plan go in? (api-route, urls, openapi, or a new name)".

Sub-plan mode override (when Step 0 set <sub-plan-mode>=true):

  • <topic> is already set (derived from <target-branch>). Do NOT infer or ask.
  • If plans/<topic>/ does not exist, run mkdir -p plans/<topic>/ (this folder should already exist if the master was generated via /master-plan-creator, but create it defensively).

Store the result as <topic> for use in all subsequent file paths.

Step 2: Deep Research via Parallel Subagents

Before writing any plan, perform deep codebase research using parallel subagents. This keeps source file reads out of the main context window and enables thorough, parallel investigation.

2a. Identify Research Targets

From the user's feature/task description, identify:

  • Affected modules: Which backend blueprints, frontend modules, templates, and test directories are involved?
  • Affected endpoints: Which routes will be created, modified, or deleted?
  • Affected symbols: Which functions, classes, schemas, or models will change?
  • Task type flags: Does this involve data validation or model changes? (determines whether Subagent #5 launches)

2b. Launch Research Subagents

Read references/research-prompts.md for the full prompt definitions and expected JSON response format.

Before launching subagents, create the plans/<topic>/tmp/ directory.

Launch subagents in parallel using the Agent tool with no subagent_type (defaults to general-purpose). NEVER use subagent_type: "Explore" — Explore agents cannot use the Write tool. Each subagent:

  • Receives the user's task description, the research targets from 2a, and the path it must write its output to
  • Reads source files independently (the main agent does NOT pre-read files)
  • Writes its full findings JSON to plans/<topic>/tmp/research-<focus>.md (where <focus> describes the research area, e.g., research-architecture.md, research-dependencies.md, research-request-chain.md, research-tests.md, research-schemas.md)
  • Returns only a one-line confirmation: Written to <path>

Include this preamble in every subagent prompt:

You are a research-only subagent exploring the codebase to inform a detailed implementation plan. Your job is to discover, read, and catalog code — not to edit or create application code.

How to explore: Use Glob to find files by pattern, Grep to search for symbols/usages/imports, and Read to examine file contents. Search broadly first (Glob/Grep), then read the specific files you find. Do NOT guess file paths — discover them.

Task: <user's task description>. Affected modules/files: <list from 2a>.

Read the source files relevant to your research area. Write your complete findings to plans/<topic>/tmp/research-<focus>.md using the Write tool (NEVER cat <<EOF, python3 << 'EOF', cat >, tee, printf >, echo >, or any Bash heredoc/redirect — any heredoc or inline script containing { and quotes trips the brace+quote security prompt). Then return only this one-line confirmation: Written to <path>. Every file path you cite must be one you actually read.

# Subagent Focus Launch condition
1 Architecture & Patterns Module structure, conventions, naming Always
2 Dependency & Impact Mapping Callers, callees, importers, cross-module effects Always
3 Request/Response Chain Per-endpoint full-stack trace Always (when endpoints are involved)
4 Test Infrastructure Markers, fixtures, coverage, test patterns Always
5 Schema & Data Shapes Pydantic schemas, DB models, form classes, frontend contracts Only when task involves data validation or model changes
6 UX & Interaction Analysis Page-level feature inventory, cross-feature conflicts, accessibility, empty/error states, mobile interactions Always (when task adds or modifies UI)

All applicable subagents must launch in a single message for true parallelism.

2c. Collect and Use Research Results

After all subagents return their one-line confirmations:

  1. Read each plans/<topic>/tmp/research-<focus>.md file to compile findings
  2. Parse each JSON response
  3. If any subagent fails or its file is missing/invalid, note the gap — do NOT skip the area; instead, read the minimum necessary files directly to fill the gap
  4. Use the structured findings to inform plan writing in Step 3 — the main agent should reference subagent findings (file paths, signatures, patterns) rather than re-reading those files

The research summaries are the foundation of the plan. Every file path, function signature, data shape, and pattern referenced in to-do items should trace back to a subagent finding.

Step 3: Plan Creation

  1. Create plans/<topic>/<feature-name>.md (create plans/<topic>/ if missing).
  2. Name the file after the feature/task (kebab-case).
  3. If research is written as a separate document, it goes to plans/<topic>/research/<doc-name>.md.
  4. Structure the plan as follows:
# <Feature Name>

## Summary
<2-4 sentence description of what this feature does and why.>

## Research Findings
<Brief summary of key discoveries from the research phase that shaped this plan. Include notable patterns, dependencies, or constraints discovered. Keep to 3-5 bullets — this is context for reviewers, not a full research dump.>

## Steps

### 1. <Phase Title>
<One sentence describing what this phase accomplishes.>

**To-do:**
- [ ] <Specific, actionable sub-task>
- [ ] <Specific, actionable sub-task>

### 2. <Phase Title>
...

## Status
finished: false

Rules:

  • Think like a staff engineer: anticipate edge cases, dependencies, and ordering constraints.
  • Each phase must have at least one actionable to-do checkbox.
  • To-do items must be detailed enough that a junior engineer can execute them without ambiguity — include file paths, function names, data shapes, or API contracts where relevant.
  • The to-do list carries the detail; phase descriptions should be brief overviews.
  • Ground to-dos in research findings. Every file path, function signature, constant name, or data shape referenced in a to-do must come from a research subagent's findings. If a subagent didn't cover it, read the file before writing the to-do.
  • Specify exact data structures. When a to-do item constructs or populates a dict, list, or object, name the exact keys and value types — e.g., errors["email"] = [USER_FAILURE.EMAIL_TAKEN], not "add EMAIL_TAKEN to the errors dict." Vague structure descriptions produce silent runtime failures when the implementer guesses the wrong key.
  • No forward references within a step. If a step's to-do item calls or imports a function, that function must either already exist in the codebase or have been created earlier in the same step. If a function is first defined in step N, no to-do in steps 1–(N-1) may reference it. Check this before finalising step order.
  • Mock every UI change. If the plan adds or modifies any user-visible UI, you MUST follow the UI Mockup Protocol below — produce styled HTML mockup(s) as the visual base before finalizing the plan, and link them from the plan. Skipping mockups on a UI plan is not allowed.

Cleanup: After the plan file is written, delete all files matching plans/<topic>/tmp/research-*.md. Never delete anything under plans/<topic>/mocks/ — mockups are permanent plan artifacts.

Sub-plan cross-link (sub-plan mode only): after writing the sub-plan file, perform two cross-link operations:

  1. Master → sub-plan link: Append a cross-link line to the master's Step N. Locate the step's **To-do:** block in <master-path> and insert a line immediately after the step header (before **Branch:**) of the form:

    **Sub-plan:** [<sub-plan-name>](../<topic>/<sub-plan-name>.md)
    

    This makes the master → sub-plan relationship navigable from the master file.

  2. Sub-plan → master backref: Insert a **Master plan:** field into the sub-plan file, immediately after the ## Summary heading (before the summary text). Derive <master-parent-topic> from the master file's parent directory (the directory the master lives in). Format:

    **Master plan:** [<master-name>](../<master-parent-topic>/<master-name>.md)
    

    Where <master-name> is the master file's basename without .md. This is the inverse of the forward-link in the master, and allows the plan-reviewer to auto-detect the master plan via primary signal.

Do not create either link in default (non-sub-plan) mode.

End-to-End Chain Tracing

For any plan that changes a request/response cycle (route, form, AJAX call, template), trace the full chain before writing to-dos and include a to-do item for every link that needs changing:

Client sends request
  → CSRF / auth middleware (where does the token come from?)
  → Route handler (method, decorators, request parsing)
  → Service layer (and its callees — one level deep)
  → Template rendering (values passed and their conditional guards)
  → Test fixtures (how does the test obtain CSRF tokens, session state, DB state?)
  → Frontend JS (request data format, field IDs, success/failure handler branches)

Subagent #3 (Request/Response Chain) provides this trace. Use its findings directly — do not re-trace manually unless the subagent missed an endpoint.

Skipping layers produces plans that break in the gaps between what's described. Common omissions:

  • A middleware or decorator that gates the flow (auth condition, CSRF guard) that is only satisfied in some contexts
  • A private helper inside a service that also holds the dependency being migrated
  • A test fixture that extracts a value (CSRF token, response field) from HTML that no longer contains it after a template change
  • A frontend handler branch that checks a status code or error code that changes after the migration

Verification Layer Matching

Every step must include a verification command. The test type must match the layer changed:

Change layer Required verification Why
Template / rendered HTML (meta tags, field IDs, conditional blocks) UI test marker (make test-marker-parallel-built m=<module>_ui) or Playwright smoke client.get()/client.post() never parse the DOM; template regressions are invisible to integration tests
Frontend JS (AJAX format, handlers, DOM reads) make test-js + UI test marker (built) or Playwright JS unit tests catch logic; UI tests catch integration with real DOM
Backend only (service, route, DB) make test-marker-parallel m=<marker> Integration tests are sufficient and faster
Cross-layer (backend format + JS handler in same step) Integration tests + make test-js + make vite-build All three layers must be green

If a step changes what the browser sees or reads but only runs integration tests, the plan is undertested — add the appropriate UI-level verification.

Dead Import Elimination Protocol

When any to-do item deletes a function, class, or helper, you must trace its import footprint within the same file and include cleanup of every import that becomes dead. This is a mechanical, exhaustive check — not a judgment call.

Procedure (for every deletion in a step):

  1. List the symbols the deleted code uses. Read the function body. Note every name it references that comes from an import at the top of the file — standard library types (Sequence, cast), framework functions (render_template, request), project utilities (build_form_errors), string constants (EMAILS, REGISTER_FORM), model classes, etc.
  2. For each such symbol, grep the file for other usages. Exclude the deleted function(s) and their internal helpers. If no remaining usage exists in the file after the deletion, that import is dead.
  3. Add an explicit removal to-do for every dead import found. Group them in the same bullet as the deletion (not in a later cleanup step) — F401 / no-unused-vars enforcement blocks the commit otherwise.

Also apply when changing a function's return expression (e.g., render_template(...)APIResponse(...).to_response()). The old return may have been the sole consumer of an import (render_template, a form class passed to the template, etc.).

Do not defer dead-import removal to a cleanup step. If a symbol becomes unused in Step N, it must be removed in Step N. Linters enforce this at commit time — a deferred removal blocks every commit between Step N and the cleanup.

Function Signature Change Protocol

When any to-do item changes a function's signature (parameter type, name, count, or structure), use Subagent #2's dependency mapping to enumerate:

  1. Every private helper inside it that receives or uses the changed parameter — add a separate to-do to update each one's signature and internal uses.
  2. Every direct call site in other files — add a to-do for each caller found in the dependency map.

A plan that says "update public_fn(form)public_fn(value: str)" without listing _private_helper(form) called inside it will produce an AttributeError at runtime. The callee enumeration must be explicit to-do items, not implied.

Frontend/Backend Colocation Rule

For every endpoint where the plan changes the request format, response codes, or wire contract, the frontend JS changes must appear in the same step as the backend change — never in a later "frontend" or "cleanup" step. This includes:

  • data: serialization format (serialize()JSON.stringify(...))
  • contentType: header
  • Failure handler status code checks (xhr.status === 401xhr.status === 400)
  • handleImproperFormErrors dispatch keys

Integration tests send the final format directly and will not catch a gap where the browser is silently broken between steps. Write the frontend to-do in the same step bullet block as the backend to-do it pairs with.

Accessibility Protocol

When a plan adds or modifies any interactive UI element (buttons, inputs, editable regions, expandable panels, modals), include to-do items for each applicable concern:

  1. Keyboard operability: Every interactive element must be reachable via Tab and activatable via Enter/Space. If a non-button element (e.g., a clickable <div> or <span>) is made interactive, add role="button", tabindex="0", and keydown handlers for Enter and Space.
  2. Focus management: After opening/closing an interactive widget (search panel, edit form, modal), specify where focus moves. After closing, focus should return to the element that opened it — track opener identity if needed (e.g., editOpenedViaKeyboard flag).
  3. ARIA labels and roles: Every input must have an aria-label or associated <label>. Dynamic content changes that the user needs to know about (filter counts, "no results" messages) must use aria-live="polite" with a visually-hidden announcement element.
  4. Touch targets: On mobile (< 992px), interactive elements must have minimum 44px touch targets (min-height: 2.75rem). Specify CSS rules with @media breakpoints.
  5. Focus visibility: Interactive elements must show a visible focus indicator. Use :focus-visible with outline-offset to avoid clipping.

If the plan has no UI changes, skip this protocol.

Cross-Feature Interaction Protocol

For any plan that adds or modifies an interactive UI feature on a page, Subagent #6 (UX & Interaction Analysis) inventories all other interactive features on the same page/view. Use its findings to add to-do items for each composition concern:

  1. State conflicts: If the new feature hides/shows elements (e.g., search filtering URLs), check every other feature that depends on those elements being visible (e.g., card selection, keyboard navigation, inline editing). Add to-do items to handle the conflict (e.g., auto-deselect when selected card is hidden, skip hidden elements in keyboard nav).
  2. Mutual exclusion: If two features cannot be active simultaneously (e.g., editing a title while search panel is open), specify which one takes priority and how the other is temporarily disabled or hidden. Add to-do items for the disable/re-enable lifecycle.
  3. Shared event handlers: If the new feature binds keyboard events (Escape, Enter, arrow keys) that other features also bind, specify precedence and event propagation behavior. Check for stopPropagation / preventDefault conflicts.
  4. Input performance: If the feature involves text input that triggers filtering, API calls, or DOM manipulation, add a debounce (typically 150-300ms) with timer cleanup on close/unmount.
  5. Empty/zero states: For any feature that hides content (search, filters), specify what the user sees when all content is hidden — a "no results" message, a prompt, etc. This must be distinct from the "no content exists" state.
  6. Discoverability: If the feature makes existing elements interactive in a non-obvious way (e.g., making headers clickable for inline editing), add visual affordances (icons, hover effects) and specify their show/hide rules per device (hover on desktop, persistent on mobile).

CSRF / Auth / Session specifics

When a plan touches form submission, authentication, or CSRF:

  1. Token rendering: Read the template. Note any {% if ... %} guards. Explicitly state whether the condition is satisfied for all relevant user states (authenticated, unauthenticated, unvalidated). If not, add a to-do to fix the guard.
  2. Test token acquisition: Read the fixture. State exactly which HTML element the fixture parses to get the CSRF token, and verify that element will exist in the response after the template changes.
  3. Frontend token consumption: Read the JS. Confirm the DOM element it targets (meta[name=csrf-token], hidden input, etc.) is present in the rendered page for all user states the form is shown to.

UI Mockup Protocol (Visual Base)

If the plan adds or modifies any user-visible UI — a new page, panel, modal, dropdown, button, layout shift, color/spacing change, or on-screen copy — you MUST produce one or more HTML mockups of the proposed result before finalizing the plan. The mockup is the visual base the plan is built on; reviewers and the user judge the design from the rendered mock, not from prose. A UI plan with no mockup is incomplete.

If the plan has no user-visible UI change (pure backend, refactor, infra, tests), skip this protocol entirely.

Where mockups live

  • Write each mockup to plans/<topic>/mocks/<descriptive-name>.html using the Write tool (create plans/<topic>/mocks/ first). Never use a Bash heredoc/redirect for HTML.
  • Mockups are permanent plan artifacts — they live alongside the plan, are referenced by it, and are never placed in plans/<topic>/tmp/ and never deleted during cleanup.

Fidelity — match the real app, not a generic wireframe

The mock must look like URLS4IRL, with the correct colors and styling:

  1. Pull real values from the codebase. Use Subagent #6's findings, or grep the project styles (CSS custom properties / theme variables, frontend/**/*.css, Bootstrap utility classes already in use, existing template markup) for the actual hex colors, font families, spacing, border-radius, and class names. Do NOT invent colors — every color in the mock must trace to a real value used by the app.
  2. Reuse existing class names and DOM structure where practical so the mock reads like the real rendered page and the implementer can map it directly to templates.
  3. Make each mock self-contained and standalone-renderable — inline <style> (or a <link> to the app stylesheet) so the file opens and screenshots on its own with no dev server.

Coverage — show the full picture

One static screenshot rarely conveys a design. Produce multiple mocks (separate files, or multiple labeled states stacked in one file), or a single interactive mock, whichever communicates the design best:

  • Distinct states that look different: default, populated/with-data, empty/zero-results, error, loading.
  • Distinct viewports when layout differs: desktop and mobile (<992px).
  • An interactive mock (inline <script> toggling states, opening the modal, filtering a list) when interaction — not a static frame — is the point of the feature.

State in the plan which mocks cover which states/viewports so nothing is silently unshown.

Reference from the plan

In the plan's ## Summary (or the relevant phase), link every mock — Mockup: [<name>](mocks/<name>.html) — and ground each UI to-do (colors, class names, layout, copy) in what the mock shows. The mock and the to-dos must agree.

Render to images for review

After writing the mock files, render each to a PNG so it can be shown to the user (HTML source alone is not "showing pictures"):

  1. For each mock file, use the Playwright MCP: browser_navigate to file://<absolute-path-to-mock>.html, then browser_take_screenshot saving to plans/<topic>/mocks/<name>.png. For interactive mocks, capture each meaningful state (click/toggle, then screenshot) so every state has an image. For responsive mocks, browser_resize to a mobile width (e.g. 390px) and capture that too.
  2. The generated PNGs are surfaced to the user in the Handoff Message (see below) via SendUserFile.

Package Pinning

Any plan step that adds a new Python package must:

  1. Pin it to the latest stable version (check PyPI: write a temp script to $TMPDIR/check_version.py using the Write tool, then run curl -s https://pypi.org/pypi/<package>/json | python3 $TMPDIR/check_version.py — NEVER use inline python3 -c with braces)
  2. If stable is incompatible with the existing stack, use the latest working version instead — document why in the to-do item.
  3. Pin all transitive dependencies introduced by the new package to exact versions as well. Run pip install <package>==<version> in the container, then pip show <package> and inspect the Requires: field. Add each unlisted dependency at its installed version.

When using a new feature of an already-pinned package (e.g., EmailStr requires email-validator >= 2.0, a new API method requires a minimum version), check the current pin in requirements-prod.txt before writing any to-do that depends on that feature. If the current pin is too old, add a pre-work to-do to update it — with a make build and container-level smoke test — before any to-do that uses the feature. Do not assume the existing pin is compatible.

Always use == (not >=, ~=, or ranges). Add the package and its transitive deps to the appropriate requirements file based on usage:

File Use when
requirements-prod.txt Needed at runtime in production
requirements-test.txt Only needed for running tests (includes prod via -r)
requirements-dev.txt Only needed for local dev tooling / pre-commit (includes test via -r)

Final Verification Step

For every plan that touches code or tests, the last phase must be:

### N. Verify All Tests Pass

Run the full test suites to confirm nothing is broken:

**To-do:**
- [ ] Run `make test-integration-parallel` and confirm all integration tests pass
- [ ] Run `make test-ui-parallel-built` and confirm all UI/functional tests pass
- [ ] Investigate and fix any failures before marking the plan finished

Do not omit this phase even if only one test file was touched.

TDD Enforcement

For any plan involving a new feature or bug fix (not pure refactoring or cleanup), the steps must follow a strict Red → Green → Refactor loop. Do not bulk-code then bulk-test.

The Loop (one requirement at a time):

  1. Red – Write a focused test for one specific requirement. Run it; confirm it fails with a relevant error.
  2. Green – Write the minimum code to make that test pass. Run it; confirm it passes.
  3. Refactor – Clean up for readability and project patterns. Confirm tests stay green.
  4. Repeat until the feature is complete.

Implementation standards:

  • Backend (Flask): Prioritize integration or unit tests. Match existing style and directory structure in tests/.
  • Frontend – logic/state: Use Vitest with JSDOM (fast, isolated).
  • Frontend – navigation/critical flows: Use Selenium (end-to-end verification).
  • Philosophy: Tests are the contract; code is the fulfillment. Never write tests to fit existing feature code.

Step 4: Create GitHub Issue

After the plan file is written, cross-linked, and tmp files cleaned up, create a corresponding GitHub issue and link it to the plan via YAML frontmatter. The issue is the publicly-visible WHY; the plan stays the source of truth for the HOW.

4a. Search for existing matches

Extract 2-4 distinguishing keywords from the plan title (drop stopwords like "the", "and", "for", "with"). Search open issues:

GH_TOKEN=$(~/.claude/generate-gh-token.sh) gh issue list \
  --state open --search "<keywords>" --limit 5 \
  --json number,title,labels \
  --repo 4IRL/urls4irl

If 1+ matches return, present up to the top 3 via AskUserQuestion with options labeled #<N>: <title> plus a "Create new" option.

  • User picks existing #N: capture <issue-number> and <issue-url>=https://github.com/4IRL/urls4irl/issues/<N>. Skip 4b and 4c. Proceed to 4d.
  • User picks "Create new": proceed to 4b.

If no matches return, skip the question and proceed to 4b directly.

4b. Generate issue body and labels

Derive a condensed WHY-focused body in this exact structure:

## Problem
<one paragraph: what's broken/missing/unclear today>

## Why
<one paragraph: why this matters now, what prompted it>

## Outcome
<one paragraph: what "done" looks like in observable terms>

---
Plan: `plans/<topic>/<feature-name>.md`

You (the main agent) just wrote the plan — synthesize Problem/Why/Outcome from the plan's ## Summary and ## Research Findings sections. Do not delegate this to a subagent.

Infer category labels from plan content. Use only existing labels (never invent new ones):

Signal in plan Label
Backend routes/services/models, Python files in backend/ backend
TS/JS files in frontend/, Jinja templates frontend
Docker, Vite, CI workflows, build/deploy Infrastructure
Alembic migrations, SQLAlchemy models, .sql files database
Test files in tests/ (any kind) testing
Mobile-specific UI (≤991px breakpoints, touch targets) mobile
Desktop-specific UI desktop
New user-visible capability enhancement
Defect fix (branch fix/... or plan describes a bug) bug

A plan typically gets 1-3 labels.

4c. Create the issue

GH_TOKEN=$(~/.claude/generate-gh-token.sh) gh issue create \
  --title "<plan-title-verbatim>" \
  --body "<generated-body>" \
  --label "<label1>" --label "<label2>" \
  --repo 4IRL/urls4irl

Capture the printed URL as <issue-url> and parse <issue-number>.

Add to project board + assign bot via GraphQL. Reuse the same project ID PVT_kwDOCEIbTM4Ai9RV ("URLS4IRL -> Real Life") and bot account that /git-push Step 9 uses for PRs. Fetch the issue's node ID first:

ISSUE_NODE_ID=$(GH_TOKEN=$(~/.claude/generate-gh-token.sh) gh issue view <N> --repo 4IRL/urls4irl --json id --jq .id)

Then run the addProjectV2ItemById mutation and the bot-assignee mutation. Copy the exact mutation structures from .claude/skills/git-push/SKILL.md Step 9.

4d. Detect master parent, attach as native sub-issue, and back-link

First, resolve which umbrella issue (if any) this sub-plan belongs to:

Sub-plan mode (Step 0 set <sub-plan-mode>=true): read <master-path> frontmatter for github_issue: (the umbrella number <umbrella>) and github_issue_node_id: (the umbrella's GraphQL node ID <umbrella-node-id>).

Default mode: glob plans/<topic>/*-master.md. If exactly one file exists and its frontmatter has github_issue:, use it. If multiple master files exist or none have a linked issue, skip this entire step.

When an umbrella is found, do BOTH of the following:

1. Attach as a native GitHub sub-issue (the structural parent/child link). This makes the phase issue a child of the umbrella in GitHub's sub-issue hierarchy. You captured the new phase issue's node ID as <issue-node-id> in Step 4c. Resolve <umbrella-node-id> from the master frontmatter github_issue_node_id:; if that key is absent (older / hand-written master), fetch it:

GH_TOKEN=$(~/.claude/generate-gh-token.sh) gh issue view <umbrella> --repo 4IRL/urls4irl --json id --jq .id

Write the mutation to a .graphql file (never inline — braces+quotes trip the security prompt) and run it via -F query=@file:

plans/<topic>/tmp/add-sub-issue.graphql:

mutation {
  addSubIssue(input: { issueId: "<umbrella-node-id>", subIssueId: "<issue-node-id>" }) {
    subIssue { number }
  }
}
GH_TOKEN=$(~/.claude/generate-gh-token.sh) gh api graphql -F query=@plans/<topic>/tmp/add-sub-issue.graphql

If the call errors with an unknown-field / schema error on addSubIssue, retry the same command with -H "GraphQL-Features: sub_issues" appended (the sub-issues schema was preview-gated behind that header before GA). If it still fails, surface the error and the manual command but do not block plan creation — the Part of #N text link below still records the relationship.

2. Append the Part of #N body backref (human-readable secondary link). Append \n\nPart of #<umbrella> to the new phase issue body via gh issue edit --body-file. This keeps a visible link in the issue body and timeline alongside the structural sub-issue relationship.

4e. Write issue link to plan frontmatter

Insert YAML frontmatter at the very top of plans/<topic>/<feature-name>.md (above the existing # <Feature Name> H1):

---
github_issue: <N>
github_issue_url: <url>
---

If frontmatter already exists, insert the two new keys preserving existing ones. This applies whether 4c created a new issue OR 4a linked to an existing one.

Failure handling

If gh issue create fails (rate limit, transient API error), DO NOT block the plan creation. Surface the error and the manual gh issue create command to the user, then exit Step 4. The plan file still exists; the issue can be created later and frontmatter added manually.

Handoff Message

After the plan file is written, cross-linked, the tmp/research-*.md files are cleaned up, and the GitHub issue is created, the final user-facing message must:

  • Show the mockups (UI plans only). If the UI Mockup Protocol produced any mocks, send every rendered PNG to the user with SendUserFile (status: "proactive"), one call listing all the mock images, with a caption naming which state/viewport each shows. The user judges the design from these images before review. Also note the source HTML path (plans/<topic>/mocks/<name>.html) in case they want to open it interactively.
  • Mention the issue: Created issue #<N>: <url> (or Linked to existing issue #<N>: <url> if 4a reused one)
  • Suggest /plan-reviewer as the next step — never /next-step-taker. A freshly-written plan must be reviewed before execution begins. Use phrasing like: "Ready for review with /plan-reviewer <plan-name>."
Install via CLI
npx skills add https://github.com/4IRL/urls4irl --skill plan-creator
Repository Details
star Stars 3
call_split Forks 1
navigation Branch main
article Path SKILL.md
More from Creator