From 348e6c0a4f37b7402201cca9ee840bf0b313de0e Mon Sep 17 00:00:00 2001 From: Dustin VanKrimpen Date: Fri, 3 Jul 2026 22:48:35 -0400 Subject: [PATCH] Give question files scannable slugs (Q-NNN-short-slug.md) Question files move from Q-NNN.md to Q-NNN-short-slug.md, matching the scannable naming that log entries already use. The Q-NNN prefix keeps files ID-sorted and greppable by number; the slug is for human scanning. The id: frontmatter field stays the authoritative ID (the dashboard keys off it, not the filename), so nothing downstream breaks. Skills: - capture: create questions with a log-style slug; next-ID sed regex made slug-tolerant, still filename-based. - resolve: find the file by globbing Q-NNN-*.md (with a Q-NNN.md legacy fallback) instead of opening a fixed name; examples updated. - ask: layout diagram updated (its Q-*.md globs already worked). - supersede: unchanged; it never references question files. Specs/docs updated to match: AGENTS.md, CLAUDE.md, README.md. Migrate this repo's own tracked questions Q-001..Q-007 to slugged names (git mv, no frontmatter change). Co-Authored-By: Claude Opus 4.8 (1M context) --- AGENTS.md | 8 ++++-- CLAUDE.md | 8 +++--- README.md | 6 ++--- plugins/wherefore/skills/ask/SKILL.md | 2 +- plugins/wherefore/skills/capture/SKILL.md | 8 +++--- plugins/wherefore/skills/resolve/SKILL.md | 26 +++++++++++-------- ....md => Q-001-astro-build-external-dirs.md} | 0 ...-002.md => Q-002-prefixed-release-tags.md} | 0 ...3.md => Q-003-build-tool-plan-location.md} | 0 ...=> Q-004-path-filter-branch-protection.md} | 0 .../{Q-005.md => Q-005-file-url-viewing.md} | 0 .../{Q-006.md => Q-006-mcp-server-wrapper.md} | 0 ...7.md => Q-007-schema-writer-mismatches.md} | 0 13 files changed, 33 insertions(+), 25 deletions(-) rename wherefore/questions/{Q-001.md => Q-001-astro-build-external-dirs.md} (100%) rename wherefore/questions/{Q-002.md => Q-002-prefixed-release-tags.md} (100%) rename wherefore/questions/{Q-003.md => Q-003-build-tool-plan-location.md} (100%) rename wherefore/questions/{Q-004.md => Q-004-path-filter-branch-protection.md} (100%) rename wherefore/questions/{Q-005.md => Q-005-file-url-viewing.md} (100%) rename wherefore/questions/{Q-006.md => Q-006-mcp-server-wrapper.md} (100%) rename wherefore/questions/{Q-007.md => Q-007-schema-writer-mismatches.md} (100%) diff --git a/AGENTS.md b/AGENTS.md index 6989bb4..3af8459 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,7 +11,7 @@ location; if `wherefore/` exists, use it. wherefore/ topics.md controlled tag vocabulary: Areas and Topics log/YYYY-MM-DD-short-slug.md one decision per file - questions/Q-NNN.md one question per file + questions/Q-NNN-short-slug.md one question per file (ID prefix + scannable slug) ``` There is no index file. The frontmatter in each `log/` and `questions/` file is the @@ -96,7 +96,11 @@ For an abandoned decision with no replacement: `status: obsolete`, a When a decision leaves something unresolved, register it. Next Q-ID = (highest `id:` across the existing `wherefore/questions/Q-*.md` files) + 1; IDs are sequential and -never reused. Create `wherefore/questions/Q-NNN.md` with this EXACT frontmatter: +never reused. Create `wherefore/questions/Q-NNN-short-slug.md` (the `Q-NNN` prefix is +the zero-padded ID; the slug is a short, lowercase, hyphenated summary distilled from +the question, same style as a log slug). The `id:` frontmatter field remains the +authoritative ID; the filename slug is only for human scanning. Use this EXACT +frontmatter: ```markdown --- diff --git a/CLAUDE.md b/CLAUDE.md index 263eaa6..4f57ad9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -48,7 +48,7 @@ plugins/wherefore/ skills/capture/ SKILL.md # captures a discussion into wherefore/ as one or # more tagged Markdown entries; registers any open - # questions as questions/Q-NNN.md files + # questions as questions/Q-NNN-short-slug.md files topics.seed.md # starter vocabulary copied on first use if no # topics.md exists yet skills/ask/ @@ -57,7 +57,7 @@ plugins/wherefore/ # also surfaces open questions in the same area skills/resolve/ SKILL.md # closes an open question by editing its - # questions/Q-NNN.md file (answer, rationale, back-link) + # questions/Q-NNN-short-slug.md file (answer, rationale, back-link) skills/supersede/ SKILL.md # marks an entry superseded (with pointer to # replacement) or obsolete via its frontmatter @@ -71,6 +71,6 @@ The `wherefore/` directory itself is **not** in this repo -- it lives in each co - **Command `.md`** front matter: `description`, `argument-hint`, `allowed-tools`. - All skills use a two-facet tag system: **areas** (feature slices: WHAT) and **topics** (cross-cutting concerns: HOW), drawn from the consuming project's `wherefore/topics.md`. Keep this separation consistent if extending the skills. - There is no hand-maintained index. INDEX.md and QUESTIONS.md are gone: entry and question frontmatter is the single source of truth, and `ask` derives its shortlist by reading only the leading frontmatter block of each file. Do not reintroduce a generated index in any skill or command; if extending the skills, derive on read instead. -- `capture` is write-heavy (creates/edits files); a single discussion may produce multiple entry files when it covers independently-queryable threads. `ask` is read-only. `resolve` edits only the `questions/Q-NNN.md` file (and optionally the source entry). `supersede` edits an existing entry file's frontmatter and adds a banner. `seed` is read-first, write-only-after-confirmation -- preserve this ask-before-write pattern for any new commands. +- `capture` is write-heavy (creates/edits files); a single discussion may produce multiple entry files when it covers independently-queryable threads. `ask` is read-only. `resolve` edits only the `questions/Q-NNN-short-slug.md` file (and optionally the source entry). `supersede` edits an existing entry file's frontmatter and adds a banner. `seed` is read-first, write-only-after-confirmation -- preserve this ask-before-write pattern for any new commands. - Entry filenames: `YYYY-MM-DD-short-slug.md`; the entry frontmatter (`date`, `title`, `areas`, `topics`, `stories`, `status`, `supersedes`, `superseded_by`, `superseded_date`) is what readers shortlist on. -- Question files: `questions/Q-NNN.md`, one per question, with `id`, `question`, `status`, `areas`, `asked_date`, `asked_slug`, `resolution`, `resolution_slug` frontmatter. IDs are sequential and never reused; the next ID is (highest existing `id:`) + 1. +- Question files: `questions/Q-NNN-short-slug.md` (the `Q-NNN` prefix is the zero-padded ID; the slug is a short, lowercase, hyphenated summary of the question, same style as a log slug and only for human scanning). One per question, with `id`, `question`, `status`, `areas`, `asked_date`, `asked_slug`, `resolution`, `resolution_slug` frontmatter. The `id:` field is the authoritative ID (the dashboard keys off it, not the filename). IDs are sequential and never reused; the next ID is (highest existing `id:`) + 1. diff --git a/README.md b/README.md index 8346d64..8d37c9d 100644 --- a/README.md +++ b/README.md @@ -78,8 +78,8 @@ maintained. It shortlists from entry frontmatter, then reads only the matching files. After answering, it surfaces any still-open questions in the same area. - **`resolve`** -- closes out an open question by updating its - `wherefore/questions/Q-NNN.md` file, recording the answer, the rationale, and a - link to the discussion that settled it. + `wherefore/questions/Q-NNN-short-slug.md` file, recording the answer, the rationale, + and a link to the discussion that settled it. - **`supersede`** -- marks a past decision superseded (with a pointer to its replacement) or obsolete, without requiring a new discussion to be captured. Updates the entry file and adds a visible banner so both the `ask` skill and @@ -240,7 +240,7 @@ Each consuming project's log lives in its own repo, not here: └── wherefore/ ├── topics.md # controlled tag vocabulary (areas + topics) ├── questions/ - │ └── Q-NNN.md # one file per question + │ └── Q-NNN-short-slug.md # one file per question (ID prefix + scannable slug) └── log/ └── YYYY-MM-DD-short-slug.md # one file per independently-queryable thread ``` diff --git a/plugins/wherefore/skills/ask/SKILL.md b/plugins/wherefore/skills/ask/SKILL.md index f4f07fd..78fdf61 100644 --- a/plugins/wherefore/skills/ask/SKILL.md +++ b/plugins/wherefore/skills/ask/SKILL.md @@ -27,7 +27,7 @@ The wherefore lives under a repo-relative `wherefore/` directory: wherefore/ ├── topics.md # controlled topic vocabulary ├── questions/ -│ └── Q-NNN.md # one file per question +│ └── Q-NNN-short-slug.md # one file per question (ID prefix + scannable slug) └── log/ └── YYYY-MM-DD-short-slug.md # one file per discussion ``` diff --git a/plugins/wherefore/skills/capture/SKILL.md b/plugins/wherefore/skills/capture/SKILL.md index 4336772..4faee4c 100644 --- a/plugins/wherefore/skills/capture/SKILL.md +++ b/plugins/wherefore/skills/capture/SKILL.md @@ -44,7 +44,7 @@ wherefore/ ├── README.md # what this directory is + link to the plugin ├── topics.md # controlled tag vocabulary (areas + topics) ├── questions/ -│ └── Q-NNN.md # one file per question +│ └── Q-NNN-short-slug.md # one file per question (ID prefix + scannable slug) └── log/ └── YYYY-MM-DD-short-slug.md # one file per discussion ``` @@ -149,9 +149,9 @@ scalar to a one-line summary and move the detail into a body section. 8. Write `wherefore/log/YYYY-MM-DD-short-slug.md`. Slug short, lowercase, hyphenated, recognizable (`oauth-token-refresh`, not `discussion-about-the-auth-stuff`). If the name exists, add a short suffix; never overwrite. 9. Register open questions. For each genuine unresolved item: - - Next Q-ID = (highest `id:` across `wherefore/questions/Q-*.md`) + 1. Derive it from the files, e.g. `ls wherefore/questions/Q-*.md 2>/dev/null | sed -E 's|.*/Q-0*([0-9]+)\.md|\1|' | sort -n | tail -1`. If the directory is empty or absent, start at Q-001. IDs are sequential and never reused. + - Next Q-ID = (highest `id:` across `wherefore/questions/Q-*.md`) + 1. Derive it from the files, e.g. `ls wherefore/questions/Q-*.md 2>/dev/null | sed -E 's|.*/Q-0*([0-9]+).*|\1|' | sort -n | tail -1`. If the directory is empty or absent, start at Q-001. IDs are sequential and never reused. (The regex tolerates both the legacy `Q-NNN.md` and the current `Q-NNN-slug.md` naming.) - Prefix the entry's item with the ID: `- Q-001: How should we ...` - - Create `wherefore/questions/Q-NNN.md`, leaving `resolution` and `resolution_slug` blank: + - Create `wherefore/questions/Q-NNN-short-slug.md`, leaving `resolution` and `resolution_slug` blank. Name it like a log entry: `Q-` + the zero-padded ID + a short, lowercase, hyphenated slug distilled from the question (`Q-001-eu-buyer-tax`, not `Q-001-question-about-tax-stuff`). The `Q-NNN` prefix keeps questions sorted and greppable by number; the slug is for human scanning; the authoritative ID is always the `id:` frontmatter field. ``` --- id: Q-001 @@ -178,6 +178,6 @@ scalar to a one-line summary and move the detail into a body section. Reversal. Input: "We're dropping RLS and going schema-per-tenant after the perf testing." Before writing, dump entry frontmatter and scan for active entries sharing `multi-tenancy` or `postgres`, surface the RLS entry, and confirm the reversal. On confirmation, write the new entry with `supersedes: 2026-06-23-rls-tenant-isolation`, mutate the old entry's frontmatter (`status: superseded`, `superseded_by`, `superseded_date`) and add its banner line, and report every file touched. -No decision. Input: a long thread weighing GraphQL caching with no conclusion. The Decisions section reads "No decision, see Open questions"; the contenders go under Open questions, each becoming a `Q-NNN.md` so a later discussion can close them out explicitly. +No decision. Input: a long thread weighing GraphQL caching with no conclusion. The Decisions section reads "No decision, see Open questions"; the contenders go under Open questions, each becoming a `Q-NNN-short-slug.md` so a later discussion can close them out explicitly. Two threads in one discussion. Input: a thread covering both an order PDF renderer swap and a separate cart price-suggestion feature, which share no causal link. Write two files (`2026-06-24-order-pdf-renderer.md`, `2026-06-24-buyer-price-suggestion.md`), each with its own tags. Report: "Split into 2 entries; the two decisions are unrelated and would be retrieved separately." \ No newline at end of file diff --git a/plugins/wherefore/skills/resolve/SKILL.md b/plugins/wherefore/skills/resolve/SKILL.md index e59849d..dfd2a3c 100644 --- a/plugins/wherefore/skills/resolve/SKILL.md +++ b/plugins/wherefore/skills/resolve/SKILL.md @@ -26,8 +26,11 @@ summary and move detail into a `## Resolution` body section. `status` and ## Workflow -1. **Find the question.** Open `wherefore/questions/Q-NNN.md` directly (the file is - named by its ID). If it doesn't exist, say so clearly. To list what is open, +1. **Find the question.** Files are named `Q-NNN-short-slug.md` (ID prefix plus a + scannable slug), so glob by the ID rather than assuming the exact name: + `ls wherefore/questions/Q-042-*.md wherefore/questions/Q-042.md 2>/dev/null` + (the second path catches any legacy file still named `Q-NNN.md`). Expect exactly + one match; open it. If nothing matches, say so clearly. To list what is open, dump the question frontmatter and filter `status: open`: ```bash for f in wherefore/questions/Q-*.md; do @@ -49,7 +52,7 @@ summary and move detail into a `## Resolution` body section. `status` and ran the `capture` skill and a fresh entry exists. If no wherefore entry captures it, the resolution is standalone. -3. **Update `wherefore/questions/Q-NNN.md`.** Edit the frontmatter in place: +3. **Update the question file** (`wherefore/questions/Q-NNN-short-slug.md`). Edit the frontmatter in place: - Set `status: resolved` - Fill in `resolution` with a one-sentence answer (and the why, if concise enough to fit; otherwise put it in a `## Resolution` body section below the @@ -60,7 +63,7 @@ summary and move detail into a `## Resolution` body section. `status` and 4. **Update the source wherefore entry (if applicable).** If the resolution came from a specific wherefore entry, open `wherefore/log/.md` and add a note in its "Open questions / follow-ups" section next to the relevant item: - `- Q-042: (resolved, see wherefore/questions/Q-042.md)` + `- Q-042: (resolved, see wherefore/questions/Q-042-.md)` 5. **Report back.** Show: - The question text and its ID @@ -74,22 +77,23 @@ summary and move detail into a `## Resolution` body section. `status` and **Example 1: resolution from a new discussion** User: "Mark Q-001 resolved: we decided to use zero-rated VAT for EU digital goods. We discussed it in the entry we just logged, 2026-07-01-eu-vat-strategy." -Action: edit `wherefore/questions/Q-001.md` (status -> resolved, resolution filled, -resolution_slug set), update that wherefore entry to note the question is resolved. -Report both files touched. +Action: find the file (`ls wherefore/questions/Q-001-*.md`) and edit it (status -> +resolved, resolution filled, resolution_slug set), update that wherefore entry to +note the question is resolved. Report both files touched. **Example 2: standalone resolution** User: "Close Q-007. We're not doing offline sync this quarter, pushed to Q3." -Action: edit `wherefore/questions/Q-007.md` (status -> resolved, resolution filled, -resolution_slug left blank). No wherefore entry to update. Report the file touched. +Action: edit the Q-007 file (`wherefore/questions/Q-007-*.md`) (status -> resolved, +resolution filled, resolution_slug left blank). No wherefore entry to update. Report +the file touched. **Example 3: question not found** User: "Resolve Q-099" -Action: `wherefore/questions/Q-099.md` doesn't exist. Respond: "Q-099 wasn't found +Action: no `wherefore/questions/Q-099-*.md` matches. Respond: "Q-099 wasn't found in wherefore/questions/. Check the ID; I can list the open questions if that helps." **Example 4: already resolved** User: "Mark Q-002 resolved" -Action: open `wherefore/questions/Q-002.md`; status is already resolved. Show the +Action: open the Q-002 file (`wherefore/questions/Q-002-*.md`); status is already resolved. Show the recorded resolution date and text and make no changes, e.g. "Q-002 was resolved on 2026-06-24: zero-rated VAT for EU digital goods. No changes made." \ No newline at end of file diff --git a/wherefore/questions/Q-001.md b/wherefore/questions/Q-001-astro-build-external-dirs.md similarity index 100% rename from wherefore/questions/Q-001.md rename to wherefore/questions/Q-001-astro-build-external-dirs.md diff --git a/wherefore/questions/Q-002.md b/wherefore/questions/Q-002-prefixed-release-tags.md similarity index 100% rename from wherefore/questions/Q-002.md rename to wherefore/questions/Q-002-prefixed-release-tags.md diff --git a/wherefore/questions/Q-003.md b/wherefore/questions/Q-003-build-tool-plan-location.md similarity index 100% rename from wherefore/questions/Q-003.md rename to wherefore/questions/Q-003-build-tool-plan-location.md diff --git a/wherefore/questions/Q-004.md b/wherefore/questions/Q-004-path-filter-branch-protection.md similarity index 100% rename from wherefore/questions/Q-004.md rename to wherefore/questions/Q-004-path-filter-branch-protection.md diff --git a/wherefore/questions/Q-005.md b/wherefore/questions/Q-005-file-url-viewing.md similarity index 100% rename from wherefore/questions/Q-005.md rename to wherefore/questions/Q-005-file-url-viewing.md diff --git a/wherefore/questions/Q-006.md b/wherefore/questions/Q-006-mcp-server-wrapper.md similarity index 100% rename from wherefore/questions/Q-006.md rename to wherefore/questions/Q-006-mcp-server-wrapper.md diff --git a/wherefore/questions/Q-007.md b/wherefore/questions/Q-007-schema-writer-mismatches.md similarity index 100% rename from wherefore/questions/Q-007.md rename to wherefore/questions/Q-007-schema-writer-mismatches.md