my skills

This commit is contained in:
Gabor Körber
2026-05-09 22:16:02 +02:00
parent 1397c5c1a6
commit f396984315
4 changed files with 450 additions and 0 deletions
@@ -0,0 +1,79 @@
---
name: implementation-orchestration
description: Orchestrate non-trivial implementation work across one or more agents — deciding what to do inline, what to delegate, in what order, and how to verify. Use this skill whenever the user asks you to "implement", "build", "ship", "fix this bug", "make this work", or hands you a plan / spec / ticket to execute. Trigger especially for multi-step changes, anything involving compilation or test failures, hard-to-reproduce bugs, or work that spans multiple files or subsystems. Composes with the `workpad` skill (for any plans / journals / reports produced) and runs alongside `superpowers` and similar orchestration helpers.
---
# Implementation Orchestration
This skill is about **how to drive implementation work**, not about how to write code. It covers: when to delegate to subagents vs. work inline, how to sequence agents, how to handle test/compile failures, and how to approach bugs without thrashing.
## Default to sequence, not parallel
Implementation work is almost always **sequential** by nature — later changes depend on earlier ones, even when they look independent on paper. Two agents editing the same file in parallel is a merge conflict; two agents touching adjacent abstractions in parallel is a subtle integration bug.
Run subagents in parallel only when the work is **genuinely** parallelizable:
- Touching disjoint files / modules with no behavioral coupling.
- Independent investigations or read-only exploration.
- Test runs across separate test suites.
If you have to think hard about whether two tasks are independent, they probably aren't. Default to sequencing.
## Delegate compile / test fixes — but verify
A common, useful pattern: when the build is broken or tests are failing after a change, dispatch a subagent to fix it. They're tight, well-scoped tasks with a clear pass/fail signal, and they free up the main thread for higher-level decisions.
But: **always verify the fix yourself before trusting it.** Subagents fixing tests have a strong incentive to make the test pass, and the easiest way to make a test pass is sometimes the wrong way (deleting the assertion, weakening the expected value, mocking out the thing being tested, catching-and-ignoring the failing path). When the agent reports green:
1. Read the diff they produced — not just the report.
2. Confirm the fix matches the intent of the original test, not just its letter.
3. Re-run the relevant tests yourself if there's any doubt.
If you can't tell from the diff whether the fix is real, push back. "Tests pass" from a subagent is a hypothesis, not a conclusion.
## Bugs: prove before fixing, explore before focusing
Two patterns that prevent the worst kinds of bug-fix thrash.
**Hard bugs should be proven by a test first.** Before changing production code to fix a bug, write the test that reproduces the bug and watch it fail. This does three things at once: it confirms you actually understand the bug, it gives you an unambiguous signal when the fix works, and it leaves a regression guard behind. If you cannot write a failing test, you do not yet understand the bug well enough to fix it — keep investigating.
For trivial / obvious bugs (typo, off-by-one in an unambiguous spot, missing null check), skip this. The test-first rule is for anything you'd describe as "I think the issue is…" rather than "the issue is…".
**Bugfixing starts with exploration, not focus.** When handed a bug, the temptation is to dive into the suspected file and start poking. Resist for a few minutes:
- Look at the surrounding code paths, not just the suspected one. Bugs often live one or two layers up from where the symptom manifests.
- Skim recent commits to that area — was something changed recently that might explain it?
- Check whether the same pattern appears elsewhere — if it does, the fix may need to be applied in multiple places, or the abstraction itself is the problem.
- Reproduce the bug yourself end-to-end before changing anything.
A short exploration phase pays for itself many times over against fixing-then-discovering-it-was-the-wrong-place.
## Sequencing implementation agents
When a task needs multiple implementation agents, plan the sequence before launching:
1. **One agent owns each coherent change.** Don't split a single logical change across two agents — they'll fight over the boundary.
2. **Each agent receives the changes from the previous one as committed code, not as a description.** Either commit between agents or hand the diff over explicitly.
3. **Run tests between agents, not just at the end.** Catching a regression at agent N+1 is much cheaper than catching it at agent N+5.
4. **The orchestrator (you) is responsible for keeping the high-level plan coherent.** Subagents see only their slice.
For changes small enough that a single agent could do the whole thing, just do it inline. The orchestration overhead is only worth paying when the work genuinely doesn't fit.
## When to write things down
Use the `workpad` skill for placement. The implementation-specific cases:
- **Plan first** for anything more than a few files or a few hours of work. Write it to `plans/` and confirm with the user before touching code. A wrong plan caught at planning time costs minutes; caught at code-review time costs days.
- **Journal a hard bug** — long bug hunts with multiple dead ends should be captured in `journals/` as you go (append-only). The journey is the value; the final fix alone won't tell future-you why obvious-looking alternatives didn't work.
- **Spec frozen contracts.** If implementation reveals an invariant that other code will need to rely on (an event shape, an error code, a state-machine transition), promote it to `specs/` so it doesn't quietly drift.
## Composition with other skills
- **`workpad`** governs where any markdown artifacts go. Defer to it.
- **`research-tree`** is the right tool when the question "how should I implement this" is itself unsettled and decomposes into multiple investigations. Run that first; come back to this skill once you have a plan to execute.
- **`superpowers`** and project-specific skills (e.g. ticket workflows, review skills) layer on top of this — they handle domain specifics; this skill handles the orchestration shape.
## What this skill does *not* govern
- Code style, language conventions, or framework choices — that's the project's call.
- Specific test frameworks, CI configuration, or branch strategy.
- The internal structure of a plan / journal / spec — see `workpad`.
@@ -0,0 +1,161 @@
---
name: markdown-embedded-svg
description: Use when authoring or editing a Markdown file that contains (or should contain) SVG diagrams, charts, or any graphical representation. Trigger whenever (1) writing a report/document/README in Markdown that needs a diagram, flowchart, chart, or other visual, (2) considering adding `<svg>` markup to a `.md` file, (3) editing existing SVG inside Markdown, (4) a user asks for a "diagram", "visual", "chart", or "flowchart" inside a Markdown document. Markdown renderers (GitHub, Gitea, Obsidian, VS Code preview) sanitize inline SVG very differently from each other — GitHub strips it entirely, Gitea allows only `<svg>` + `<path>`, Obsidian (via DOMPurify) allows most of it. Apply this skill proactively before producing the SVG, not after.
---
# SVG in Markdown
Markdown renderers diverge dramatically on what SVG they allow. The safe default is **not** to embed SVG inline — it's to **save the SVG as a separate `.svg` file and reference it with image-link syntax**. Inline SVG should be treated as a special case the user explicitly asks for, not as the default.
This skill encodes the reasoning behind that choice plus the per-renderer rules for when inline SVG is what's wanted.
## Default approach: external `.svg` file + image link
For any new diagram going into a Markdown document:
1. Generate the SVG as a standalone `.svg` file. Common conventions:
- `docs/images/<slug>.svg`, `assets/<slug>.svg`, or alongside the `.md` itself.
- Match the project's existing convention if there is one.
2. Reference it from the Markdown with image-link syntax:
```markdown
![Architecture overview](./images/architecture.svg)
```
3. The `.svg` file itself is a normal SVG document — `<style>`, `<circle>`, `<g>`, classes, gradients, animations, anything you'd write in any SVG. The renderer pipeline for standalone SVG files is much more permissive than the inline-Markdown sanitizer (especially on GitHub, where they're handled by entirely different code paths).
This recipe is the **only** approach that reliably produces a rendered diagram on **GitHub** (which strips inline SVG categorically — see below). It also works on Gitea and Obsidian and any other Markdown renderer that supports image links.
Use this default unless the user explicitly asks for inline SVG.
## Why not inline SVG by default
Inline SVG fails silently and inconsistently across renderers. From source-code analysis (see `research/2026-05-05-15-svg-sanitizer-allowlists/` if available locally):
- **GitHub Markdown** (`html-pipeline` + `rgrove/sanitize`): the allow-list contains **zero** SVG elements. `<svg>`, `<g>`, `<path>`, `<circle>` — all stripped. Inline SVG never renders in a `.md` file on github.com. The element is removed; only its bare text-node children leak through.
- **Gitea** (bluemonday default policy): allows only `<svg>` and `<path>`. No `<rect>`, no `<circle>`, no `<g>`, no `<text>`, no gradients, no fills or strokes (the `fill` and `stroke` attributes are also stripped). Self-hosted admins can extend the allow-list via `app.ini`'s `[markup.sanitizer.N]` rules, but defaults are the rule.
- **Obsidian** (DOMPurify defaults): allows most SVG — `<circle>`, `<rect>`, `<ellipse>`, `<g>`, `<text>`, `<defs>`, gradients, paths, filters. Empirically confirmed *not* working in Obsidian: `<use>`, `<style>` element, `<foreignObject>`, `<title>` element. `<script>`, event handlers, and `javascript:` URLs are stripped on every renderer including Obsidian.
- **VS Code Markdown preview** (uses markdown-it + DOMPurify-like sanitization): permissive, similar to Obsidian for most things.
The **strict cross-renderer intersection for inline SVG is effectively empty** — there is no inline-SVG recipe that produces a rendered diagram on GitHub, Gitea, and Obsidian alike. This is why the default has to be the external file.
## When the user does ask for inline SVG
If the user explicitly says "embed it inline", "put the SVG directly in the markdown", or similar, follow these rules. Pick the rule set that matches the target renderer. If the target is unknown, ask.
### Rule 1: Embed as a raw HTML block, never as a fenced code block
The two paths look similar but produce completely different output.
- **Embed SVG as a raw HTML block.** Place `<svg …>…</svg>` directly in the Markdown source, with a blank line before and after. CommonMark / GFM treat that as a raw HTML block and pass it through verbatim; the browser then parses what survives the sanitizer as real SVG.
- **Never wrap renderable content in ` ```svg ` (or ` ```html `, ` ```xml `) fences.** Fenced code blocks are *by definition* "display this as text". The renderer wraps the contents in `<pre><code>`, HTML-escapes every `<`, `>`, and `&`, and hands the escaped text to a syntax highlighter. The browser sees a string, not markup — no SVG ever gets parsed.
- **Don't assume non-standard "render this code block" extensions exist.** Some renderers (GitLab, certain Obsidian plugins, custom static-site setups) special-case ` ```mermaid ` or ` ```svg ` to render. This is non-standard. GitHub, VS Code's default preview, and CommonMark do not. Default to the raw-HTML-block path.
- **Same rule applies to other inline-renderable HTML.** `<details>`/`<summary>`, `<picture>`, `<video>`, raw `<table>` with attributes Markdown can't express — all use the raw-HTML-block path, never a fence.
Diagnostic: "I see SVG source code as text" → fence problem. "I see blank space or default-styled shapes" → sanitizer/styling problem (see Rule 2).
### Rule 2: Per-renderer element / attribute rules
| Element / feature | GitHub inline `.md` | Gitea (default) | Obsidian | Notes |
|---|---|---|---|---|
| `<svg>` | ❌ stripped | ✅ | ✅ | |
| `<path>` | ❌ | ✅ | ✅ | The most portable shape primitive. |
| `<rect>` | ❌ | ❌ | ✅ | Substitute with `<path>` rectangle on Gitea. |
| `<circle>` | ❌ | ❌ | ✅ | Substitute with `<ellipse rx=R ry=R>` (Obsidian only) or `<path>` arc circle. |
| `<ellipse>` | ❌ | ❌ | ✅ | |
| `<line>`, `<polyline>`, `<polygon>` | ❌ | ❌ | ✅ | |
| `<text>`, `<tspan>` | ❌ | ❌ | ✅ | |
| `<g>` | ❌ | ❌ | ✅ | Group inheritance dies on Gitea — repeat presentation attrs per element if cross-renderer matters. |
| `<defs>`, `<linearGradient>`, `<radialGradient>`, `<stop>` | ❌ | ❌ | ✅ | |
| `<marker>` | ❌ | ❌ | ✅ | Arrowheads only work on Obsidian inline. |
| `<use>` | ❌ | ❌ | ❌ (empirically confirmed) | Strip on Obsidian was unexpected; treat as not portable. |
| `<style>` element | ❌ | ❌ | ❌ (empirically confirmed) | Don't use it anywhere. CSS rules don't have a clear scope boundary so sanitizers strip them as injection risk. |
| `<title>` element | ❌ | ❌ | ❌ (empirically confirmed) | |
| `<foreignObject>` | ❌ | ❌ | ❌ (empirically confirmed) | |
| `<script>`, `on*` event handlers, `javascript:` URLs | ❌ | ❌ | ❌ | Always stripped, every renderer. Don't use. |
| `class=` attribute (for styling) | ❌ | ❌ | ✅ | Even when class survives, the `<style>` block defining the rules doesn't, so styling is lost — use inline presentation attributes. |
| Inline presentation attributes (`fill`, `stroke`, `stroke-width`, `font-size`, `font-family`, `text-anchor`, `stroke-dasharray`, etc.) | ❌ | ❌ | ✅ | These survive on Obsidian and any sanitizer that allows SVG at all. They never apply on GitHub-inline / Gitea because the elements themselves are stripped. |
Reading the table: an Obsidian-only target gives you most of SVG. A Gitea target restricts you to `<svg>` + `<path>` (no colors, no text, no groups). A GitHub-inline target gives you nothing — switch to the external-file recipe.
### Rule 3: Surviving the sanitizer where SVG is allowed
When the renderer allows SVG (Obsidian, VS Code preview, some self-hosted Gitea with extended `app.ini`, and the standalone-`.svg`-file path on GitHub), structure the SVG to survive its sanitizer:
- **Use SVG presentation attributes inline on every element.** `fill`, `stroke`, `stroke-width`, `stroke-dasharray`, `font-size`, `font-weight`, `font-family`, `text-anchor`. These can't escape the SVG and survive every sanitizer that allows SVG at all.
- **Don't rely on `<style>` blocks or `class=` for styling.** `<style>` is stripped on every renderer's inline sanitizer (including Obsidian, empirically). Even if `class=` survives, the rules are gone, so styling is lost.
- **Prefer longhand over CSS shorthand.** Use `font-size`, `font-weight`, `font-family` separately rather than the `font:` shorthand. The shorthand is CSS-only; longhand maps directly to SVG presentation attributes.
- **`<defs>` and id references are fine** on renderers that allow them at all (Obsidian; not Gitea/GitHub-inline). `<marker>`, `<linearGradient>` referenced via `url(#id)` survive the Obsidian sanitizer.
- **Group-level inheritance works for `font-family` and `fill`** (set on `<g>`, inherited by children) on Obsidian. Don't rely on it for cross-renderer; set the attribute on the leaf element.
The visible failure mode is silent: shapes still render, but with browser-default fill (usually black), no stroke, and default font sizing. On dark themes this looks like "nothing showed up"; on light themes like "a row of black blobs with no labels". There is no console error and no Markdown lint warning.
### Rule 4: No blank lines inside inline SVG
pulldown-cmark (and most CommonMark parsers) terminate an HTML block at a blank line. Any content after the blank line — even if it's still inside `<svg>...</svg>` — is parsed as Markdown, not HTML. Indented SVG elements become fenced code blocks (`<pre><code>`); unindented ones become paragraphs wrapping escaped angle brackets.
This means **the SVG source must be one unbroken block with no empty lines between `<svg>` and `</svg>`**. Use comments (`<!-- section: axes -->`) instead of blank lines if you need visual separation inside the SVG source.
Diagnostic: "Part of my SVG renders but the rest appears as code or escaped text" → blank-line-induced block break. Remove all blank lines between `<svg>` and `</svg>`.
## Default size
Generated SVG diagrams should not exceed **750 pixels in width** by default — set `width` (and a matching `viewBox`) accordingly. Height is unconstrained — pick whatever the content needs. Wider SVGs blow out the column on most Markdown renderers. Override only when the user explicitly asks for wider.
## Minimal example (external file recipe — the default)
```markdown
The architecture is straightforward:
![Architecture overview](./images/architecture.svg)
Each component handles its own state.
```
Where `./images/architecture.svg` is a normal SVG file — use any elements you want; standalone SVG is not subject to the inline-Markdown sanitizer.
## Minimal example (inline, Obsidian-friendly — only if user asks)
```markdown
Some prose before the diagram.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 80" width="200" height="80">
<g font-family="sans-serif" font-size="12" fill="#222">
<!-- inputs -->
<rect x="10" y="20" width="80" height="40" fill="#e8f0fe" stroke="#1a73e8" stroke-width="2"/>
<text x="50" y="45" text-anchor="middle">Input</text>
<!-- arrow -->
<line x1="90" y1="40" x2="130" y2="40" stroke="#1a73e8" stroke-width="2"/>
<!-- outputs -->
<rect x="130" y="20" width="60" height="40" fill="#fce8e6" stroke="#d93025" stroke-width="2"/>
<text x="160" y="45" text-anchor="middle">Output</text>
</g>
</svg>
Prose after.
```
Note: blank line before `<svg>`, blank line after `</svg>`, **no blank lines inside the SVG** (use `<!-- comments -->` for section separation), no fence, all styling via presentation attributes, font longhand on the group. This will render on Obsidian and similar permissive renderers. It will **not** render on GitHub `.md`. It will partially render on Gitea (the `<svg>` survives, the rest is stripped).
## Pre-commit checklist
If you went with the **external file** default:
- [ ] SVG saved as a `.svg` file in a sensible location.
- [ ] Markdown references it with `![alt](path.svg)`.
- [ ] `width` (the rendered width) ≤ 750px unless asked otherwise.
If the user asked for **inline SVG**:
- [ ] Confirmed the target renderer allows SVG inline (not GitHub `.md`).
- [ ] `<svg>` block has a blank line before and after, no surrounding ` ``` ` fence.
- [ ] No blank lines between `<svg>` and `</svg>` (pulldown-cmark terminates the HTML block at blank lines).
- [ ] No `<style>`, `<title>`, `<use>`, `<foreignObject>` elements (don't survive Obsidian).
- [ ] No `class=` for styling, no CSS `font:` shorthand.
- [ ] Every shape has explicit `fill` and (where applicable) `stroke` / `stroke-width` as inline attributes.
- [ ] No `<script>`, `on*` handlers, or `javascript:` URLs.
- [ ] `width` ≤ 750px unless asked otherwise.
If the target is Gitea specifically and inline is required:
- [ ] Only `<svg>` + `<path>` elements used.
- [ ] No `fill`, `stroke`, `class`, `style`, `transform` attributes (stripped by default policy).
- [ ] OR confirmed the Gitea instance has `[markup.sanitizer.N]` extensions in `app.ini` permitting more.
+98
View File
@@ -0,0 +1,98 @@
---
name: research-tree
description: Orchestrate multi-topic research as a dependency tree of parallel phases — not a flat fan-out of independent agents. Use this skill whenever the user asks for "research", "deep research", "investigate", "survey", or "look into" a topic that has multiple sub-topics, or when a question is broad enough that a single agent would either skim or take forever. Trigger especially when the user says things like "research X and Y and Z", "find out everything about…", "do a deep dive on…", or when prior research has surfaced new questions that need follow-up. Composes with the `workpad` skill for file placement and runs alongside `superpowers` and similar orchestration helpers.
---
# Research Tree
Most non-trivial research questions decompose into many sub-topics, and those sub-topics are *not* independent — later questions get sharper once earlier ones are answered. Running every sub-topic in parallel as peer agents wastes work and produces shallow, redundant findings. Running them strictly in series wastes wall-clock time. The right shape is a **tree of phases**: within a phase, agents run in parallel; between phases, later agents inherit the earlier reports.
This skill describes how to plan and run that tree. It does not describe how to write the contents of an individual research report — that's up to the agent doing the writing, plus whatever conventions the project has.
## When to use this skill
Use it when **two or more** of these are true:
- The topic has multiple sub-questions that a single agent couldn't realistically cover in depth.
- Some sub-questions clearly *depend on* the answer to other sub-questions (e.g. "evaluate library X" depends on "what are our requirements").
- The user wants something they can read and refer back to, not just a chat answer.
For a single focused question, just answer it. Don't reach for the tree.
## The shape of a research tree
```
Phase 1 (parallel) Phase 2 (parallel) Phase 3 (parallel) Summary
─ topic A ─────┐ ─ topic D (knows A,B) ─┐ ─ topic F (knows D,E) ─┐ ─ index.md
─ topic B ─────┼──────► ─ topic E (knows B,C) ─┼──► … ─┼──► (linking all)
─ topic C ─────┘ ─ … ┘ ┘
```
- **Within a phase:** agents run in parallel. They do not share intermediate findings with each other — by definition the phase is composed of topics that are mutually independent at that point in the tree.
- **Between phases:** when an agent in phase N+1 starts, hand it the *full text* of the reports it depends on from earlier phases — not just summaries, and not all reports indiscriminately. Pass *its* ancestors in the tree, transitively.
- **Specificity flows downward.** Broad framing topics live near the root; narrow, technical, "given X, exactly how does Y behave" topics live near the leaves.
## Planning the tree
Before spawning a single agent, plan the tree explicitly. Write the plan down — usually in the workpad as a brainstorm or design note — so you and the user can sanity-check it.
1. **List every sub-topic** you can think of, even ones that feel redundant. Easier to delete than to discover later.
2. **For each sub-topic, ask: "what would I need to know first?"** Draw an arrow from each prerequisite topic to the dependent topic. This produces a dependency graph, not yet a tree.
3. **Break cycles.** If A needs B and B needs A, you have a cycle. Resolve it by inserting a new, smaller intermediate topic that both can build on (e.g. "shared definitions and ground truth for X"), or by deciding which direction is the dominant dependency and demoting the other to a follow-up question for phase N+2.
4. **Group into phases by depth.** Topics with no prerequisites are phase 1. Topics whose prerequisites are all in phase 1 are phase 2. And so on. A topic that depends on items from phases 1 and 3 is itself a phase 4 topic — always one past its deepest prerequisite.
5. **Sanity-check phase widths.** A phase with one topic is fine but suspicious — can it merge with the next phase? A phase with fifteen topics is a sign you haven't decomposed dependencies enough. Aim for 26 per phase typically.
6. **Confirm the plan with the user** before launching. The plan itself is the most important artifact — a wrong tree wastes the most expensive resource (agent time on the wrong questions).
## Running the phases
Use the workpad's `research/` folder, almost always inside a dated subfolder for the whole tree:
```
research/
2026-05-05-14-auth-provider-evaluation/
phase-1-requirements.md
phase-1-current-state.md
phase-1-constraints.md
phase-2-candidate-comparison.md
phase-2-migration-paths.md
phase-3-cost-modeling.md
index.md ← written last, read first
```
Filenames should be slugged by topic; the `phase-N-` prefix is optional but helps when listing the directory.
For each phase:
1. **Spawn agents in parallel** for that phase's topics. Each agent receives:
- Its own narrow research brief.
- The full text of every ancestor report it depends on (transitively up the tree). Don't summarize on the way in — let the downstream agent skim or quote as it sees fit.
- The path to write its report into.
2. **Wait for the phase to complete** before starting the next. Don't try to overlap phases — the dependency is what makes the tree worth doing.
3. **Quickly read each report yourself** before dispatching the next phase. If a phase produced something surprising or contradictory, the dependency graph for the *next* phase may need updating.
## When findings contradict each other
If two reports in the same phase reach incompatible conclusions, or a phase-N report contradicts something assumed in phase-N-1, do not paper over it in the summary.
- Spawn a **verification / reconciliation agent** as an extra step. Give it both conflicting reports and ask it to identify the actual disagreement, what evidence each side rests on, and what would resolve it.
- The verification agent writes a **review paper** that lives next to the others (`review-<topic>.md`).
- Update the relevant prior reports if they got something wrong, or note the open question explicitly in the summary.
This is also the move when the summary is *hard to write* — that's usually a signal that contradictions are present and have been silently smoothed over.
## The summary / index document
The summary is written **last** and is the **first** thing a reader should open. Conventions:
- Filename: `index.md` (or `00-summary.md` if you want it to sort first).
- Linked from every other report in the tree (or at least from the directory's README).
- Structure: a one-paragraph TL;DR, the question that started the tree, the high-level answer, then a short section per phase linking out to the full reports.
- Do not paste the contents of the other reports into the summary. Link to them. The summary's job is navigation and synthesis, not duplication.
If the summary turned out hard to write, that's a signal — see the contradictions section above.
## What this skill does *not* govern
- The internal structure of an individual research report — that's the agent's call, plus project conventions.
- Whether the workpad itself exists / where it lives — defer to the `workpad` skill.
- Picking which model to use for which agent — out of scope here.
+112
View File
@@ -0,0 +1,112 @@
---
name: workpad
description: Decides WHERE and WHEN to put working documents — reports, plans, goals, brainstorms, designs, journals, research, specs, tickets, bug notes. Use this skill whenever the user asks you to write a "report", "plan", "goal", "brainstorm", "design", "journal", "research note", "spec", or anything "in the workpad" — and also when another skill is about to drop a markdown file somewhere ad-hoc (e.g. a `superpowers/` subdirectory, the repo root, `/tmp`, or alongside source code). If a workpad exists, the workpad wins. This skill steers other skills toward a single, predictable place for thinking-in-markdown so the user can always find what was written and when.
---
# Workpad
The workpad is the user's filing cabinet for thinking-in-markdown. Reports, plans, brainstorms, post-mortems — anything that is *about* the work rather than *being* the work — lives here. This skill answers two questions only: **where** does a given document go, and **when** is one kind of document the right kind versus another. It does not tell you how to write the contents.
Treat this skill as authoritative for placement. If another skill suggests writing a markdown artifact to its own scratch directory (a `superpowers/` folder, a sibling `notes/` dir, the repo root, etc.), prefer the workpad instead. A single predictable location is more valuable than each skill having its own.
## Where the workpad lives
Resolve the workpad base directory in this order — stop at the first hit:
1. **Explicit user instruction in the current conversation.** If they said "put it in `~/notes/foo`", that wins.
2. **`WORKPAD_FOLDER` environment variable.** Reading it reliably is fiddly because Claude Code runs commands in subshells that may not inherit the user's interactive env, and the value may live in a project-local `.env` file rather than the actual environment. Try, in order:
- `uv run --quiet --with python-dotenv python -c "from dotenv import load_dotenv; import os; load_dotenv(); print(os.environ.get('WORKPAD_FOLDER',''))"` if `uv` is available. This loads `.env` from the current working directory before reading the variable, which catches the common case where `WORKPAD_FOLDER` is set per-project in a `.env`.
- `just workpad-folder` (or any equivalent recipe) if a `.justfile` / `justfile` is present and defines one — `just` loads `.env` automatically.
- `printenv WORKPAD_FOLDER` as a last resort. This will only see values exported into the actual process environment, not values in `.env` files.
If any of these prints a non-empty path, treat it as the workpad base.
3. **Project-local ticket folder.** Some projects keep a sibling folder *outside* the main repo for per-ticket scratch (e.g. `../<repo>-tickets/` or a path the user has mentioned before). If such a folder is configured for this project, prefer placing the workpad inside it (e.g. `<ticket-folder>/workpad/`). When in doubt whether one exists, ask.
4. **`/docs/workpad`** at the project root, if a `/docs` folder already exists.
5. **Otherwise: ask.** If there is no `/docs` folder and no other signal, do not silently create `/docs/workpad/`. Ask the user where the workpad should live, and confirm before creating any folders.
## Folder structure
The workpad always contains at least these subfolders:
- `brainstorm/` — open-ended exploration, options, half-formed ideas
- `goals/` — acceptance criteria, milestones, "what we're trying to reach"
- `designs/` — design docs, architecture sketches, RFC-style writeups
- `plans/` — concrete sequences of steps to execute
- `reports/` — findings, summaries, status writeups
It may also contain any of these, created on demand:
- `archive/` — superseded or completed material moved out of the way
- `bugs/` — bug investigations and notes
- `journals/` — append-only narratives of long-running problems
- `research/` — external research, library evaluations, prior art
- `specs/` — frozen, unchanging specifications
- `tickets/` — per-ticket scratch space
If one of these optional folders is needed and doesn't exist yet, create it. Don't create folders speculatively.
## File naming
Use a `YYYY-MM-DD-hh-` prefix on filenames in `reports/` and `plans/` at minimum. The hour helps when multiple artifacts land on the same day — which is common during active work — and keeps directory listings naturally sorted by recency. Apply the same prefix to `journals/`, `bugs/`, and `research/` entries; it's almost always the right call there too. For `goals/`, `designs/`, and `specs/`, the prefix is optional — these are referred to by name more than by date, so a descriptive slug alone is fine (e.g. `goals/q2-onboarding-flow.md`, `specs/event-schema.md`).
After the prefix, use a short kebab-case slug describing the topic: `2026-05-05-14-auth-token-leak.md`, not `2026-05-05-14-report.md`. The slug is what the user will skim for later.
## When to create a subfolder
Single artifact → single file. Don't wrap one report in a folder.
Create a dated subfolder when a piece of work will produce **multiple related files** — typically a research cascade, a multi-part report with appendices, or a plan with supporting design notes that belong together. The subfolder takes the date prefix and slug; files inside it can drop the date prefix since the parent already carries it.
Example:
```
reports/
2026-05-05-14-auth-token-leak.md ← single report
2026-05-05-15-q2-perf-audit/ ← cascade
overview.md
db-findings.md
frontend-findings.md
recommendations.md
```
## Picking the right kind of document
The categories overlap. These are the distinctions that matter:
**Plan vs. spec.** A plan is a sequence of steps you intend to take. A spec encodes something that shouldn't change — an invariant, a contract, a frozen decision. Default to `plans/`. Promote to `specs/` only when the content is meant to be referenced repeatedly as a source of truth and is not expected to be revised as work progresses.
**Goal vs. plan.** A goal says *what we're trying to reach* — acceptance criteria, a milestone, a story-level outcome. A plan says *how we'll get there*. If you find yourself writing "and then I'll…", you're writing a plan, not a goal.
**Report vs. journal.** A report is a snapshot — it can be revised as new information arrives, and the latest version is the version that matters. A journal is append-only and tells the story of a problem, including missteps, dead ends, and course corrections. Post-mortems, multi-day bug hunts, and architectural-correction narratives are journals. If the historical sequence is itself part of the value, it's a journal. If only the current conclusion matters, it's a report.
**Brainstorm vs. design.** A brainstorm is divergent — multiple options, tradeoffs, no commitment. A design is convergent — one approach, fleshed out enough to build from.
## Lifecycles
Most work follows one of these flows. Use them as a guide for what to create next, not as a mandatory pipeline — skip stages when they wouldn't earn their keep.
**Feature work:** `brainstorm → goal → design → plan`. Start with options, settle on what success looks like, design the approach, then break it into steps.
**Investigative or reactive work:** `report → design → plan`, or `report → plan`, or just `plan`. You usually start by reporting on what's there or what's broken; a design is only needed if the fix is non-trivial.
When moving between stages, create a new file in the next folder rather than mutating the previous one. The earlier artifact stays as a record of how thinking evolved.
## What "write a report" means by default
When the user says "write a report on X" without further direction:
1. Create a markdown file in `<workpad>/reports/` with the `YYYY-MM-DD-hh-<slug>.md` naming.
2. Put the actual findings in the file.
3. In your reply to the user, **summarize directly** — don't restate the whole report. Mention the file path so they can open it.
The same default applies to "write a plan", "draft a brainstorm", etc. — the user wants a file in the right folder plus a short verbal summary, not the file's contents pasted back into chat.
## Steering other skills
If you're operating under another skill that wants to write a markdown artifact (a research note, a design sketch, a status report), and a workpad exists or is reasonable to create, route the artifact through the workpad rather than that skill's default location. The other skill governs **what goes in the file**; this skill governs **where the file lives and what it's called**. They compose cleanly.
## What this skill deliberately does not cover
- The internal structure or formatting of reports, plans, designs, etc. That's up to the user, the project's conventions, or another skill.
- Git workflow for workpad files (whether to commit them, branch them, etc.).
- Tooling for searching or indexing the workpad.
If the user asks for help with any of those, treat it as a separate concern.