todoSetup
The configuration wizard for Prompt TODO: seven steps (todo file + title, tags, rules check, ticket tracker, app navigation, permissions, summary), each one skippable and re-runnable on its own, --yes
SKILL.mdtemplate/.claude/skills/todoSetup/SKILL.md
GitHub/todoSetup
Guided setup of Prompt TODO, run inside the project after install.sh. Nothing here is
required: the flow works with the defaults install.sh wrote. Each step explains why it
exists, shows the current value, asks, and writes. The user can skip any step, and re-run any
step later by name.
/todoSetup # all steps in order
/todoSetup tags # one step
/todoSetup --yes # all steps, every default, no questions
/todoSetup tracker --yes # one step with its default
Ground rules
- Config first. Read
.claude/prompt-todo/config.jsonat the start (Readtool). Every step shows the current value as its default. If the file is missing, sayinstall.shhas not been run here and stop. - Ask with
AskUserQuestion, one question at a time, and every question has aSkipoption (keeps the current value; acknowledge in one line:Skipped — tags unchanged). With--yes, ask nothing: take the default of every step and print one line per step. - Write with the
Edittool, never the shell, then re-render:bash .claude/prompt-todo/bin/py.sh render_rules.py. Show its one-line output. If it fails, show the error and revert the edit. - Never touch the user's todo file except where a step says so (step 1 creates it; step 7's smoke test appends and removes one line, with permission).
- Unknown step name → list the seven step ids and stop.
- Finish every run (single step or all) with the summary of what changed and what is still off, unless the run was only the summary step.
Step 1 — todo: project title and your todo file
Intro (print before asking):
Every person on the project gets their own todo file, named after their git user name, so files never collide in git and Claude never touches a teammate's items. The same name becomes the marker Claude leaves in code comments,
[jd#12], which is how a change is traced back to the prompt that caused it (/todoMarkCode offswitches the markers off). The project title only appears in the file headers.For
git config user.name=jdand the titleMy App:TODO.jd.md your items header: # My App — TODO TODO.jd.archive.md done items, moved by header: # My App — TODO archive /todoArchive; ids live on there, so numbers are never reused# My App — TODO - [ ] #12 Add a retry button to the upload error dialog - [x] #11 Fix the crash when the photo list is empty// Retry re-enqueues the same upload id, see UploadQueue. [jd#12]
Ask:
- Project title — default: the current
projectTitleif it is notMy App, else the repository directory name (basename "$(git rev-parse --show-toplevel)"). - Git user name — run
git config user.name. If set, show it and ask to confirm (or change:git config user.name <name>, run only after the user typed the name). If empty, say the todo file cannot be named without it and offer to set one; skipping leaves no file, and the first#newprompt will ask again. - Create
TODO.<name>.mdnow? Default yes when the file does not exist. Create it with theWritetool: the# <title> — TODOheader and one empty line, nothing else. If it exists, say so and do not touch it.
Writes: projectTitle; the todo file. Re-render.
--yes: title = directory name if the config still says My App, keep the git name, create
the file if the name is set and the file is missing.
Step 2 — tags: the tag table
Tags tell platforms apart inside one repo: a tag goes right after the id (- [ ] #19 IOS: …)
and scopes the item. The table is built from what the repo contains, so this step normally
asks nothing. There is no All tag and no default tag: an untagged item is simply about this
project.
- Run
bash .claude/prompt-todo/bin/py.sh detect_platforms.pyand print its lines as they are (Android app/src/main/AndroidManifest.xml), one per detected platform. - Run it again with
--tags: that is the newtagsobject. Its rule: one row per detected platform (Web also bringsMobileWeband the four browser rows),<P>+rows only when two or more platforms were found,DocsandInfraalways, ignore rowsQAandAdmin,defaultempty. - Something detected: replace the whole
"tags": { … }block ofconfig.jsonwith that output (Edittool), re-render, and print the result as a short table (tag, meaning) plus one line:Tags: Android, Docs, Infra — change with /todoSetup tags add|remove. No question.--yes: the same. - Nothing detected: one question,
Which platform is this?— multi-select over Android, iOS, Web, Backend, Desktop, plus Skip. Build the object withdetect_platforms.py --tags <Platform> …from the answer (iOS isIOS) and continue as in 3.--yesor Skip: write the object from--tagswith no platform (Docs,Infraonly), say so in one line.
Sub-commands, for the rare manual change (never offered as a question in the main flow):
/todoSetup tags add <Tag>: <meaning>— append a row (tag: letters, digits,+, no colon)./todoSetup tags remove <Tag>— drop a row./todoSetup tags detect— re-run the detection and rebuild the table (same as step 2).
Validate before writing: a tag cannot be in both lists and no tag may repeat;
render_rules.py --check says so too.
Writes: tags. Re-render.
Step 3 — rules: render and verify
No question. Do, and print a checklist with ✓/✗ per line:
bash .claude/prompt-todo/bin/py.sh render_rules.py→RULES.mdrendered.CLAUDE.mdcontains the line@.claude/prompt-todo/RULES.md(Grep). Missing → offer to append it (Edit)..claude/settings.jsonhas the hook:bash .claude/prompt-todo/bin/py.sh merge_settings.py .claude/settings.json --check. Missing → offer to run it without--check.command -v jq, else the Python the wrapper found (bash .claude/prompt-todo/bin/py.shwith no argument prints its usage;python3,pythonorpy -3— on Windows usually notpython3) — which one the hook will use.- Pipe-test:
echo '{"prompt":"works"}' | bash .claude/hooks/todo-confirm.shmust print JSON containingTODO CONFIRM TRIGGER;echo '{"prompt":"hello"}' | …must print nothing.
Any ✗ that could not be fixed: say what to do by hand.
Step 4 — tracker: where tickets come from
Intro (print before asking):
/todoFromTicketturns a ticket into numbered first prompts in your todo file, and — when an app-navigation skill is connected — the item that opens the app where the bug lives. To read tickets Claude needs a connection to your tracker: for Jira that is the Atlassian MCP server (OAuth, logged in once with/mcp) plus, for the attachments — screenshots, logs — a personal API token in a gitignored file (the MCP server carries no file bytes); for GitHub Issues theghCLI. Nothing else in the flow needs it. Without it,/todoFromTicketonly works with the ticket text pasted in, and the ticket-key input of app navigation is unavailable; everything else works.Example — the sample app BestPizza, ticket PROJ-321 "Order total wrong after removing a topping" (Add a Margherita, add olives, remove olives: the total still includes the topping. Server: stage, Restaurant: Downtown, Pizza: Margherita, Topping: Olives. Attachment:
order.log):/todoFromTicket PROJ-321appends to
TODO.jd.md:## PROJ-321 — Order total wrong after removing a topping > Add a Margherita, add olives, remove olives: the total still includes the topping. Attachments: todoAttachments/PROJ-321/order.log - [ ] #32 PROJ-321 /appNavigation ← only when an app-navigation skill is connected - Server: stage - Restaurant: Downtown - Pizza: Margherita - Topping: Olives - [ ] #33 PROJ-321 Android+: Recompute the order total from the current toppings whenever one is removed. - [ ] #34 PROJ-321 Show the topping's price next to its remove button so a wrong total is visible at once. - [ ] #35 PROJ-321 QA: on the #32 screen, add olives, remove them: the total goes back to the pizza price - [ ] #36 PROJ-321 QA: on the #32 screen, add olives: the olives row shows its price, the total is pizza + that priceThen
#33works the item,worksticks it and rewrites it to its ideal prompt; theQA:rows are yours to tick once the checks pass.
Ask: Jira (Atlassian MCP), GitHub Issues (gh), None, Skip. Default: the current
tracker.kind.
Jira:
- Host (
yourcompany.atlassian.net) and project keys (comma-separated, e.g.PROJ, OPS). claude mcp list— is a server namedatlassianthere? If not, print the exact command and ask before running it:claude mcp add --transport http --scope user atlassian https://mcp.atlassian.com/v1/mcp/authv2then tell the user to run/mcpin Claude Code, pickatlassian, and log in (OAuth in the browser). This step cannot complete the login itself; say so.- Test: ask for one ticket key the user knows; call
mcp__atlassian__getJiraIssueon it and show its summary line, or the error. A failed test still saves the config (the login may happen later). - Attachments: if
.claude/prompt-todo/credentials.jsonalready holds an email and a token, say so and keep it. Otherwise ask withAskUserQuestion— Enter email + API token now (a personal token from id.atlassian.com → Security → API tokens) or Skip — attachments will not download. On enter: ask for the two values (the token as free text via Other; never print it back), write the file withWriteas{"email": "…", "token": "…"}, and check.gitignorelists.claude/prompt-todo/credentials.json(add the line withEditifinstall.shdid not). On skip: say the prompts still come, the files don't, and that this step can be re-run. - Write
tracker.kind = "jira",tracker.jira.host,tracker.jira.projectKeys.
GitHub:
- Repository
owner/repo— default: parsed fromgit config remote.origin.urlwhen it is a GitHub URL. gh auth status— missinggh→ print the install hint (brew install gh/ the GitHub CLI page) and how to log in (gh auth login); not logged in → saygh auth login.- Test:
gh issue list --repo <repo> --limit 1, show the result or the error. - Write
tracker.kind = "github",tracker.github.repo.
None / Skip: write tracker.kind = "none" (Skip: leave the value as it was) and say
plainly: /todoFromTicket works only with pasted ticket text, and the ticket-key input of app
navigation is unavailable, until /todoSetup tracker is run again. Print the two-line short
form of the intro (what the connection is for) if the intro was not printed.
Re-render. --yes: unchanged.
Step 5 — appNavigation: opening the app where a ticket points
Explain in three lines: a ticket's context block (Server: plus the lines naming the screen)
can become an item that opens the app right there on a device; that needs a skill that knows
your app's build, login and screens. The package ships only a description of it,
.claude/skills/appNavigation/SKILL.md — implementing it is the user's work, for their app.
Ask — two options only:
- Skip (default) — "you can do this later": implement the skill for your app (the
description says what it must do), or use a skill you already have, then run
/todoSetup appNavigationagain to connect it. WritesappNavigation.mode = "none". - Connect an existing skill — list the directories in
.claude/skills/(ls), the shippedappNavigationincluded, and ask which one. Confirm in one question that the skill takes a spec as sub-bullets (the lines a ticket's context block carries). If the pick is the shippedappNavigationand itsSKILL.mdstill says it is not implemented, say so — it stays a placeholder until implemented — but still record it. WritesappNavigation.mode = "existing",appNavigation.skill = "<name>".
Re-render — the rules gain (or lose) the App-navigation items paragraph, and
/todoFromTicket starts (or stops) writing the /<skill> item. --yes: unchanged.
Step 6 — permissions: allow rules
Explain: the skills run git config user.name and the render script; allow rules in
.claude/settings.local.json (personal, not committed) spare a prompt on each.
Propose the list, ask Add / Skip:
- always:
Bash(git config user.name),Bash(bash .claude/prompt-todo/bin/py.sh:*)(the render and detect scripts run through that wrapper); - with
tracker.kind = github:Bash(gh issue view:*),Bash(gh issue list:*).
Write with Edit (create the file with {"permissions":{"allow":[…]}} if missing; merge into
an existing permissions.allow, no duplicates). --yes: add the always-on rules only.
Step 7 — summary
No question, unless the smoke test is offered. Print:
- The effective config as a short table: title, git name → todo file (exists / missing), tags (the rows, "no default", ignore rows), confirm words, tracker (Jira: attachments token present / missing), app navigation, code markers (on / off), prompt scores (on / off), line width (N characters / off), attachments directory.
- Disabled by skipped steps, one line each: no tracker →
/todoFromTicketpaste-only; Jira without a token → attachments are not downloaded; no app navigation → context blocks stay as sub-bullets; no git name → no todo file yet. - Smoke test (ask, default yes;
--yesruns it): append- [ ] #new Smoke test itemto the todo file withEdit, run the Autoincrement rule, show the line with its id, then remove that line again (Edit) and say the id is now taken — the next item gets the one after it, which is how ids are meant to behave. - Next steps:
#newan item and type its id;/todoFromTicket <KEY>; the human readme.claude/prompt-todo/README.md.