Text mode (workflow.text_mode: true in config or --text flag): Set TEXT_MODE=true if --text is present in $ARGUMENTS OR text_mode from init JSON is true. When TEXT_MODE is active, replace every AskUserQuestion call with a plain-text numbered list and ask the user to type their choice number. This is required for non-Claude runtimes (OpenAI Codex, Gemini CLI, etc.) where AskUserQuestion is not available.
Runs inline — no Task, no AskUserQuestion, no Bash.
Notes are stored as individual markdown files:
- Project scope:
.planning/notes/{YYYY-MM-DD}-{slug}.md— used when.planning/exists in cwd - Global scope:
~/.claude/notes/{YYYY-MM-DD}-{slug}.md— fallback when no.planning/, or when--globalflag is present
Each note file:
---
date: "YYYY-MM-DD HH:mm"
promoted: false
---
{note text verbatim}
--global flag: Strip --global from anywhere in $ARGUMENTS before parsing. When present, force global scope regardless of whether .planning/ exists.
Important: Do NOT create .planning/ if it doesn't exist. Fall back to global scope silently.
| Condition | Subcommand |
|---|---|
Arguments are exactly list (case-insensitive) |
list |
Arguments are exactly promote <N> where N is a number |
promote |
| Arguments are empty (no text at all) | list |
| Anything else | append (the text IS the note) |
Critical: list is only a subcommand when it's the ENTIRE argument. /gsd-note list of groceries saves a note with text "list of groceries". Same for promote — only a subcommand when followed by exactly one number.
- Determine scope (project or global) per storage format above
- Ensure the notes directory exists (
.planning/notes/or~/.claude/notes/) - Generate slug: first ~4 meaningful words of the note text, lowercase, hyphen-separated (strip articles/prepositions from the start)
- Generate filename:
{YYYY-MM-DD}-{slug}.md- If a file with that name already exists, append
-2,-3, etc.
- If a file with that name already exists, append
- Write the file with frontmatter and note text (see storage format)
- Confirm with exactly one line:
Noted ({scope}): {note text}- Where
{scope}is "project" or "global"
- Where
Constraints:
- Never modify the note text — capture verbatim, including typos
- Never ask questions — just write and confirm
- Timestamp format: Use local time,
YYYY-MM-DD HH:mm(24-hour, no seconds)
- Glob
.planning/notes/*.md(if directory exists) — project notes - Glob
~/.claude/notes/*.md(if directory exists) — global notes - For each file, read frontmatter to get
dateandpromotedstatus - Exclude files where
promoted: truefrom active counts (but still show them, dimmed) - Sort by date, number all active entries sequentially starting at 1
- If total active entries > 20, show only the last 10 with a note about how many were omitted
Display format:
Notes:
Project (.planning/notes/):
1. [2026-02-08 14:32] refactor the hook system to support async validators
2. [promoted] [2026-02-08 14:40] add rate limiting to the API endpoints
3. [2026-02-08 15:10] consider adding a --dry-run flag to build
Global (~/.claude/notes/):
4. [2026-02-08 10:00] cross-project idea about shared config
{count} active note(s). Use `/gsd-note promote <N>` to convert to a todo.
If a scope has no directory or no entries, show: (no notes)
- Run the list logic to build the numbered index (both scopes)
- Find entry N from the numbered list
- If N is invalid or refers to an already-promoted note, tell the user and stop
- Requires
.planning/directory — if it doesn't exist, warn: "Todos require a Open-workspace project. Run/gsd-new-projectto initialize one." - Ensure
.planning/todos/pending/directory exists - Generate todo ID:
{NNN}-{slug}where NNN is the next sequential number (scan both.planning/todos/pending/and.planning/todos/completed/for the highest existing number, increment by 1, zero-pad to 3 digits) and slug is the first ~4 meaningful words of the note text - Extract the note text from the source file (body after frontmatter)
- Create
.planning/todos/pending/{id}.md:
---
title: "{note text}"
status: pending
priority: P2
source: "promoted from /gsd-note"
created: {YYYY-MM-DD}
theme: general
---
## Goal
{note text}
## Context
Promoted from quick note captured on {original date}.
## Acceptance Criteria
- [ ] {primary criterion derived from note text}
- Mark the source note file as promoted: update its frontmatter to
promoted: true - Confirm:
Promoted note {N} to todo {id}: {note text}