Pg feature brainstorm
Skill matejformanek/postgres-claude/.claude/skills/pg-feature-brainstorm
Turn Claude Code into a long-term collaborator on PostgreSQL internals — cited knowledge corpus, agent skills, slash commands, and task-shaped scenarios for backend hacking.
npx -y skills add matejformanek/postgres-claude --skill pg-feature-brainstormAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Brainstorm a half-formed PostgreSQL backend feature idea before it's worth a heavy plan — Phase 1 of the two-phase PG planner, the open-design-space stage that comes BEFORE pg-feature-plan. Frame the problem, name the relevant PG subsystems (parser / planner / executor / heap-AM / index-AM / WAL / replication / catalog / autovac / extensions), sketch 2-3 candidate approaches with explicit tradeoffs, run a "has this been tried?" check against CommitFest entries + git log + the local corpus, surface DECISION: questions only the user can answer before Phase 2, and output a short ~150-300-line brainstorm doc (NOT a file:line-cited implementation plan — that's pg-feature-plan's job). **Use this skill proactively whenever the user says "let's brainstorm a PG idea", "i have an idea for PG", "rough idea: [PG thing]", "what if we let PG [do X]", "what would it take to add [X] to PG", "could we do [Y] in PG", "explore the design space for [Z]", "i want PG to support [...]", "what are the 2-3 candidate approaches for [PG feature]", invokes \`/pg-brainstorm\`, or names a still-fuzzy half-formed PG-backend feature — even when they don't use the literal word "brainstorm". The signal is: the design space is still open, no approach is locked yet, the user wants to scope the problem before committing to file:line cites.** Skip when an approach is already picked and the user wants the heavy implementation plan (use pg-feature-plan or /pg-plan), the brainstorm is for product / SaaS / UX / marketing / business / sprint / roadmap (non-PG), the feature is for a different database engine (MongoDB / Redis / MySQL / SQLite / Snowflake / DuckDB / Cassandra / Kafka), the user is at the design-review stage of an already-written plan (use pg-patch-review or review-checklist), or the question is about already-committed PG features ("how does X work" — that's a corpus / explanation question, not a brainstorm).
SKILL.md
35.6 KB, ~8.5k tokens by cl100k_base, as published. Nobody here has run it
pg-feature-brainstorm — Phase 1 of the PG planner
The first stage of the two-phase PostgreSQL feature planner. Output is a short, opinionated sketch that frames the problem and offers candidate approaches — not an implementation plan.
The pairing:
- Phase 1 — brainstorm (this skill) → narrow the design space
- Phase 2 — plan (
pg-feature-planskill) → make it implementable
Per the user's split: brainstorm explores, plan commits.
When to use vs not
Use when the idea is exploratory:
- "What would it take to add server-side variables?"
- "Could we add a new hook for X?"
- "I want to make EXPLAIN show Y, what are the options?"
- "Should this be a contrib extension or a core change?"
Don't use when the task is already scoped:
- "Add a
pg_buffercount()builtin" → go topg-feature-plandirectly. - "Fix this specific bug" → no brainstorm needed; cite + patch.
Don't use for non-PG brainstorming, app architecture, infra design.
Inputs
- A natural-language description of the idea (the user's argument).
- Optional: a
slugfor the planning artifacts (otherwise derived from the idea, e.g.server-side-variables→server_side_vars).
Output
A single file at planning/<slug>/brainstorm.md with the structure
below. ~150-300 lines total. Anything longer means you're doing
Phase 2 work prematurely — stop and hand off.
Required sections (in this order)
-
Concrete usage surface (REQUIRED, comes FIRST). 20-30 enumerated example lines showing what the feature must let the user write. Each example is one SQL / PL/pgSQL / DDL line. Group by usage class. Generate this BEFORE answering DECISION questions — every DECISION must take these examples as inputs, not abstractions.
Why this is §0: the sesvars first calibration (2026-06-17) produced an MVP that covered ~30% of what the user actually wanted, because DECISION questions were phrased so narrowly they excluded entire usage classes (array indirection, composite access, PL/pgSQL direct writes, DDL DEFAULT, SELECT INTO, aggregate semantics). The §0 enumeration prevents that failure mode — if a usage class isn't on the list, the brainstorm has admitted it's out of scope; if it IS on the list, the candidate approaches MUST be able to support it.
How to generate the examples — parallel fan-out via subagents:
- Agent A reads
knowledge/scenarios/_index.md+ every pinned scenario; lists usage examples that show up in those scenarios. - Agent B greps
source/src/test/regress/sql/andcontrib/*/sql/for similar-shaped features; extracts idiomatic SQL surface lines. - Agent C web-searches pgsql-hackers + CommitFest entries for the feature keyword; extracts examples from recent threads.
- Agent D — if the user has a manual reference implementation (see §0.7) — reads the reference's regress SQL file as the UPPER BOUND. Every example line that file contains becomes a candidate for §0.
- Synthesize the four agent outputs into a deduplicated 20-30 line table grouped by usage class.
Format:
## §0 Usage surface (comprehensive) ### Reader - SELECT @x - SELECT @arr[2], @arr[2:3] - SELECT (@typ).field - SELECT @js -> 'k' ... ### Utility writer (SET) - SET @x := expr - SET @x := expr, @y := expr, @z := expr - SET @x TYPE DATE := expr - SET @arr[2] := v - SET @arr[2:3] := v ... ### Inline writer (SELECT :=) - SELECT @x := expr - SELECT @a := 1, @b := 2 - SELECT @x := (subquery) - SELECT col, @cum := @cum + col FROM t ... ### Cross-feature - PL/pgSQL DO block: BEGIN SET @pl := 3; END - SELECT col INTO @v, @w FROM t - CREATE TABLE t (c INT DEFAULT @v) - EXECUTE FORMAT('SELECT @x := %L', val) ... ### Adversarial / edge - Multi-target SET with self-referential type inference - Chained inline := with type-shift across columns - Quoted identifiers @"name with spaces" - WHERE-clause assignment evaluation order ...The DECISION questions in §7 then say things like "should the feature support the array-indirection examples above (rows 5-8)?" — concrete, bound to specific lines, not abstract.
- Agent A reads
0.5. Existing-PG-mechanism survey (REQUIRED, before candidate approaches). What existing PG nodes / mechanisms / patterns could carry this feature? The default is REUSE over INVENT. Inventing a new Expr node, new EEOP step, new parsetree shape is 5× more touch points than reusing an existing one (walker coverage, EEOP_*_EXEC interpreter step, JIT mirror, ruleutils support, copy/equal/out/read funcs regen).
How to survey — parallel fan-out via subagents:
- Agent A: grep
source/src/include/nodes/primnodes.h+parsenodes.hfor similar-shaped Expr / Stmt nodes. NoteParam(withparamkinddiscriminator),SQLValueFunction(withopdiscriminator),XmlExpr(withop), etc. Discriminator-bearing existing nodes are PRIME candidates for reuse. - Agent B: grep
source/src/include/executor/execExpr.hfor existingEEOP_*steps that could be specialized via ad.union.*arm without inventing a new opcode. - Agent C: grep
source/src/include/access/for RangeTblEntry kinds (RTE_*) and FunctionScanState patterns. New row-source features often fit RTE kinds without inventing a Path / Plan node. - Agent D: search the corpus
knowledge/idioms/*.mdandknowledge/subsystems/*.mdfor "existing mechanism" / "reuse" / "PARAM_" / "RTE_" patterns. The corpus is built to surface these.
Output a short matrix in §0.5:
## §0.5 Existing PG mechanisms considered for reuse
| Mechanism | Could it carry this? | Cost of reuse | Cost of invent |
|---|---|---|---|
| Param + new paramkind | YES — text-named, value-bearing, dynamically-typed | tiny — paramkind enum + paramsesvarid field | 5× more touch points |
| SQLValueFunction + new op | NO — designed for parameterless time/role funcs | n/a | n/a |
| New T_SessionVar Expr | YES but expensive | nodeFuncs.c 6 cases + parse_collate.c + clauses.c (3 walkers) + ruleutils.c + JIT mirror | baseline |
| RTE_*KIND* | NO — sessvars are scalar, not row-source | n/a | n/a |
The recommended approach in §6 MUST justify its mechanism choice with reference to this matrix. If §6 picks invent- new, the recommendation has to argue why the existing mechanism doesn't fit — not just "it's cleaner".
Sesvars-calibration evidence: the user's manual implementation
chose PARAM_SESSION_VARIABLE (new paramkind on Param). My
AI-driven implementation invented T_SessionVar +
T_SessionVarAssign. Mine ended up with 5× more touch points
for ~30% less coverage. The §0.5 step exists to prevent that
repeat.
0.7. User-reference-implementation readthrough (REQUIRED IF one exists). Ask the user explicitly: "do you have a manual reference implementation of this feature?" Look at the conversation history, the working directory, and any prior session logs for hints (e.g. user mentions a thesis, a private branch, a "my version" repo path).
If a reference exists, READ IT as the upper-bound spec. The §2 out-of-scope lock is for features the user EXPLICITLY EXCLUDES, not "things we haven't thought of yet". The reference tells you what the user actually wants; the §0 usage surface becomes the union of (the reference's surface) + (any additions the user calls out).
This is the R15 default: comprehensive scope, not minimal MVP. If the user has built it once already manually, the planner suite's job is to produce something comparable to the reference, not 30% of it.
How to readthrough:
- Read the reference's main regress SQL file in full
(
session_variables.sqlfor sesvars). This IS the spec. - Read the reference's expected output to confirm semantics.
- Skim the reference's main implementation file (the
equivalent of
commands/<feature>.c) just for ARCHITECTURE — what existing PG mechanism did they reuse? (This feeds §0.5.) - Note any features the reference SHIPS that look like scope expansions worth including, AND any features that look genuinely out-of-scope (e.g. experimental / personal-pref).
- Surface in §7 as a DECISION: "the reference ships X, Y, Z — should we match all of these or scope down? If scope down, which?"
Anti-pattern this rule prevents: "I won't read the reference because it might bias me toward their design." Wrong framing. The bias is helpful: the reference encodes the user's real intent. The planner suite's job is to match or exceed it, not reinvent it independently.
-
Problem statement (3-5 sentences). What is the user actually asking for, in your own words? Restate the goal so misunderstandings surface early. Name the user who would benefit (DBA, extension author, hacker, end user).
-
Why this might matter (3-5 sentences). What does PG currently force the user to do that this would replace or improve?
-
Relevant subsystems (bulleted). Name 1-3
knowledge/subsystems/*.mddocs that the implementation would touch. One-line summary of each. This is the only corpus you must load in Phase 1 — don't read the per-file docs yet. -
Has this been tried? A short result of a triage pass:
- CommitFest: search
https://commitfest.postgresql.org/for the idea keyword. Note any matching entry by ID + status + last activity. - git log:
git log --oneline --grep='<keyword>' source/for the last ~2 years. Note any related commits. - pgsql-hackers: if a recent thread is obvious from CF or git, reference it; otherwise skip (don't bulk-search the list).
- Corpus:
grep -r '<keyword>' knowledge/for anything already documented. Note any hit. - Out-of-tree extensions on PGXN / community repos: search
pgxn.org and well-known per-area extension lists for the idea
keyword. Many feature requests already have a maintained
extension solving 80% of the problem (
pg_partmanfor time-bucket retention,plpgsql_checkfor plpgsql static analysis,pg_cronfor in-DB scheduling,pgvectorfor vector ops before native, …). When this hits, the brainstorm pivots from "design from scratch" to upstream into core vs harden the extension vs move to contrib — surface this as the FIRST DECISION: in §7. - Scenarios layer: match against
knowledge/scenarios/_index.md. If a scenario (or a composite of scenarios) matches the brainstormed approach, name it in this section. Phase 2 (pg-feature-plan) will PIN to it as the authoritative §3 file checklist — knowing in advance which scenario applies lets the user spot a scope mismatch early. Format:Scenario(s): <slug>orScenarios layer gap: <one-line description>if no scenario matches and the change-class is recurring. A brainstormed approach often spans 2-3 scenarios at once; name all of them. The scenarios index documents the common compositions explicitly (seeknowledge/scenarios/_index.md§"Composite features"). Phase 2 will UNION the file checklists. Heuristic for when to flag aScenarios layer gap:— flag it when the same change-class would plausibly recur in a future brainstorm. If it's truly one-off, just say "no scenario matches" without flagging.
- CommitFest: search
-
Candidate approaches (2-3, no more — but see the mandatory approach E trigger below). For each:
- One-paragraph description.
- Pros (2-3 bullets).
- Cons / risks (2-3 bullets).
- Approximate scope (small / medium / large — measured in files touched + invariants risked, not lines of code).
- Existing PG mechanism it reuses (a hook? an existing API? a parser pattern? a catalog table? a PARAM kind? an RTE kind?). REQUIRED: cite the §0.5 mechanism survey row this approach came from. If "invent new", explain why §0.5's reuse candidates don't fit.
- Storage representation (REQUIRED when the approach involves
a collection, accumulator, sequence, batch, queue, or any
other lifecycle-managed data structure). For the data structure
the approach centers on, enumerate the representation choices
explicitly:
- by-value inline (elements stored directly in struct or
palloc'd chunk — e.g.
JsonbValue items[N]in a chunked list); - by-pointer (elements palloc'd separately, pointer array
holds references — e.g.
JsonbValue **values); - by-reference-to-shared-pool (elements live in some
longer-lived context / arena, struct just holds pointers to
borrowed memory).
Each choice has different lifetime + ownership consequences:
by-value makes the struct's free / clear release everything
atomically; by-pointer requires per-element ownership tracking
OR a per-call MemoryContext; shared-pool requires the pool
outlive the struct. The recommended approach must state which
it picks and why. Do NOT take "by-pointer" as a given just
because the parent code does it — the brainstorm should
consider the alternative explicitly. Anchored in
planning/jsonpath_leak/comparison.md§L5: our jsonpath_leak trilogy missed Tom Lane's5a2043bf713"inline chunked list" design (by-value) because we inherited the parent's pointer- based JsonValueList without questioning it; the inline storage would have eliminated the ownership question Phase 2's R7 escalation had to absorb.
- by-value inline (elements stored directly in struct or
palloc'd chunk — e.g.
- Coverage of §0 usage surface (which usage classes does this approach support? List the §0 example-row numbers explicitly. If an approach covers only rows 1-10 out of 25, it's a 40%- scope approach — say so and flag whether the remaining 60% is in-scope but deferred or genuinely out-of-scope.).
- Citations (REQUIRED): at least 3
knowledge/scenarios/*.mdthis approach draws on, 2knowledge/personas/*.mdwhose reviewer reflexes apply, 2knowledge/idioms/*.mdwhose patterns it follows. Inline format:[scenarios: #11 add-new-sql-keyword, #15 add-new-expression-eval-step][personas: tom-lane (parse-tree durability), andres-freund (JIT mirror)][idioms: lexer-and-grammar, node-types]. If any cited file doesn't exist, flag as a corpus gap to fix (don't fake it).
Mandatory approach E — "restructure control flow to match the new invariant" (REQUIRED when the fix targets an existing function and that function has ≥3 exit paths AND the fix introduces a common teardown / setup / invariant step that would need to run at every exit). Enumerate it as a named approach even when your first instinct is to keep the existing shape and paper the invariant on top.
The classic form: replace N early-return sites with a single
bool result = <default>(or equivalent accumulator) plus one final exit path, then place the invariant maintenance at that single exit. One reset call instead of N. Similar re-shapings apply for setup steps (goto-cleanup, single-init prologue), for inverting an early-return chain into aswitch/if-else-ifladder, or for extracting the branchy body into a helper that the caller wraps.Reason to enumerate it explicitly: the blind trilogy consistently under-refactors when the fix is "add a reset / cleanup / invariant step". Two data points to date:
planning/jsonpath_leak/comparison.md§L5 — Tom Lane rewrote everyJsonValueListcaller to the "always copy on Append + inline storage" shape; our fix kept mixed copy/borrow semantics and needed a per-call MemoryContext to absorb the ambiguity. Fewer lines net, cleaner API.planning/nodesubplan_leak/comparison.md§F32 — Tom collapsed six early-return sites inExecHashSubPlaninto a singlebool result+ one exit path, then placed theMemoryContextReset(node->hashtempcxt)at that single exit (net −16 executable lines). Our fix kept the six branches and placed the reset at entry (net +11 executable lines). Both correct; Tom's cleaner.
The pattern: when a fix requires an invariant that ties to every exit path, the parent code's exit shape was chosen for a world without that invariant. That world no longer exists. Treating the exit shape as fixed is inheriting an assumption the fix has just invalidated. Enumerating approach E forces the brainstorm to notice.
For approach E, the required sub-bullets are the same as any other candidate — pros, cons, scope, mechanism, coverage, citations — plus one additional bullet:
- Refactor shape: name the target function, the current
number of exit paths, the proposed collapsed shape (single
boolaccumulator? goto-cleanup? extracted helper?), and any behavioural delta the refactor risks. If the answer is "purely mechanical, no behavioural delta", say so explicitly — that's the low-risk case reviewers will accept. If the refactor DOES change observable behavior beyond the invariant (e.g. changes which of two error messages fires when both apply), flag it as a scope escalation the user must approve.
If the trigger condition doesn't fire (function has <3 exit paths, or the fix is a wholly new function), say "approach E not applicable — target function has N exit paths" instead of omitting the bullet entirely. That makes the check auditable.
-
Recommended approach (1 paragraph). Pick one. Say why. Name what would have to be true for the other approaches to win (so the user can flag if those conditions hold).
-
Decisions for the user (3-5 max). Each is a concrete question prefixed with
DECISION:. Things only the human can answer:- Scope (MVP vs full feature)
- Backward-compat policy (break old API? add new flag?)
- Performance/UX tradeoffs
- Whether to do this as core or contrib/extension first
- Whether to target current master or wait for next CF window
Worked examples at the right level (one per category):
- "Are you aware the
<extension>extension already covers ~80% of this? Does it not meet your need, and if so, why?" (Prior-art reframe; ranks FIRST whenever §4 found a mature out-of-tree extension — see Edit-2 note in §4.) - "Should expired rows be query-invisible immediately at the clock crossing, or is autovacuum-eventual acceptable?" (Semantics tradeoff; shapes the user's mental model.)
- "Ship as contrib first, or aim for core in one go?" (Path-to-release; cheap-to-revert vs harder-to-iterate.)
Anti-example (too vague): "What should the GUC name be?" — that is a Phase-2 implementation detail, not a brainstorm DECISION:.
-
What this brainstorm explicitly did NOT figure out. A short list so the boundary with Phase 2 is clear. E.g. "did not enumerate catalog changes", "did not check WAL impact", "did not propose tests".
Forbidden in Phase 1
- File:line citations from per-file
knowledge/files/...docs. (Phase 2 does this.) - Phase-by-phase implementation plan.
- Catalog-bump decisions.
- WAL format decisions.
- Test surface enumeration.
- Patch-series structure.
If you find yourself writing those — stop. Save them for Phase 2.
Method
Run as a parallel-fan-out loop (NOT a sequential tight loop — the old single-context method under-explored). The fan-out is load-bearing.
Fallback when nested Agent tool is unavailable
If running inside a subagent (the Agent tool may not be in your exposed tool set), fall back to PARALLEL Read + Bash tool calls in a single message. Same fan-out logic, same coverage — the subagent is the "container", and the parallel tool calls inside one message are the "fan-out". Document this fallback in your output so the orchestrator knows the harness limitation kicked in.
(Why this fallback works: a single message with N parallel tool calls is effectively a fan-out of N concurrent reads/greps, and the model can synthesize across them in the same context. Sesvars F16 calibration logged this approach as effective.)
-
Set up: create
planning/<slug>/if it doesn't exist. Pick the slug from the user's idea (snake_case, ≤30 chars). If a brainstorm already exists, ask the user if they want to overwrite or revise. -
Ask about user reference impl. Explicit question: "do you have a manual reference implementation of this feature anywhere?" Check conversation history + working dirs + STATE.md for hints. If yes, locate the regress SQL file path before proceeding — Agent D in step 4 needs it.
2.5. Corpus-chain keyword discovery (REQUIRED, cheap). Run
python3 scripts/corpus-chain.py --keywords "<the user's feature description>"
The output surfaces:
- candidate
knowledge/scenarios/slugs matching the feature - candidate
knowledge/idioms/slugs matching the pattern class - analogous past runs from
planning/+sessions/ranked by keyword-hit + shared-file overlap
Read the top 2-3 hits BEFORE step 3. Two effects:
- If a past
planning/<slug>/doc exists, it encodes design decisions you'd re-litigate blindly otherwise. Read at least the brainstorm + comparison files. - The scenario hits become candidates for the
## Companion skillsfrontmatter later; the idiom hits become candidates for the DECISION-question phrasing.
If the chain returns nothing useful, proceed anyway — this is a discovery step, not a gate. Log "corpus-chain returned no matches; brainstorm proceeds with fresh scope" in the doc.
-
Load minimal corpus: read the master
knowledge/subsystems/index to pick 1-3 subsystem docs to load. After step 2.5, prefer the subsystems named in the top scenario/idiom hits'## Files owned/## Call sitessections — that's an evidence-backed pick. Do NOT load per-file docs at this stage. Do NOT walk source/ in-context (the agents below will). -
PARALLEL FAN-OUT — usage surface enumeration (§0). Spawn 4 subagents in the same message (Agent tool, subagent_type general-purpose):
-
Agent A — scenario mining. Read
knowledge/scenarios/_index.md+ every plausibly-relevant scenario file. Return 10-15 example usage lines extracted from scenario examples + every scenario slug that matches. -
Agent B — source-tree mining. Grep
source/src/test/regress/sql/+contrib/*/sql/for similar-shaped features (e.g. for sesvars: grep forParam,PREPARE,SET,:=patterns). Return 10-15 idiomatic SQL lines extracted from PG's own tests. -
Agent C — community mining. WebFetch
https://commitfest.postgresql.org/?text=<keyword>+ the top 5 git log hits for the keyword + a WebSearch for "pgsql-hackers <feature> proposal". Return any recent proposal threads + the SQL surface lines they propose. -
Agent D — user-reference mining (if reference impl exists per step 2). Read the reference's regress SQL file in full. Read its expected output. Skim its main implementation file's TOP-OF-FILE comment for architecture notes. Return: every distinct usage line from the regress file + a one-paragraph architecture summary + the existing PG mechanism the reference reuses (if discernible).
Synthesize Agents A/B/C/D outputs into the §0 usage surface table (20-30 lines, grouped by usage class — see the §0 format in "Required sections" above).
-
-
PARALLEL FAN-OUT — existing-PG-mechanism survey (§0.5). Spawn 4 subagents:
-
Agent A — primnodes/parsenodes mining. Grep
source/src/include/nodes/primnodes.h+parsenodes.hfor Expr/Stmt nodes with discriminator fields (paramkindon Param,opon SQLValueFunction,opon XmlExpr, etc.). Return a list of nodes that could plausibly be specialized via a new discriminator value. -
Agent B — execExpr mining. Grep
source/src/include/executor/execExpr.hforEEOP_*steps + theird.union.*arms. Return a list of steps that handle similar value-domain operations (could a new case fit into an existing step's union?). -
Agent C — RTE / FunctionScan mining. Grep
source/src/include/nodes/parsenodes.hforRTE_*kinds. Grep for FunctionScanState + similar patterns. Return any row-source mechanisms that could carry the feature. -
Agent D — corpus pattern mining. Read
knowledge/idioms/*.mdfor "reuse"-pattern docs (e.g. node-types.md, lexer-and-grammar.md). Return a short list of "X is the canonical way to add a Y" patterns.
Synthesize into the §0.5 matrix (mechanism × can-it-carry- this × cost-of-reuse × cost-of-invent). The recommended approach in §6 must cite one row from this matrix.
-
-
Sketch 2-3 approaches. Keep them genuinely distinct (not three flavors of the same approach). If you can only name one approach, say so explicitly — it usually means the design space is narrow OR you haven't thought hard enough.
Distinctness test: two approaches are flavors-of-the-same when they share ALL of (a) the owning subsystem, (b) the invariant footprint, (c) the user-visible surface (SQL vs GUC vs reloption vs extension). If at least one of those differs meaningfully, they're distinct. Example: "TTL via autovacuum extension" vs "TTL via dedicated bgworker" differ on (a) but share (b) and (c) — borderline-flavors. "TTL via autovacuum" vs "TTL via tuple- visibility predicate" differ on all three — genuinely distinct.
Adversarial-pass for collection / accumulator / lifecycle- managed types (L5). Before locking the approach list, run one adversarial question: "For the data structure this approach centers on, have I considered by-value inline storage vs by-pointer vs by-reference-to-shared-pool?" Default failure mode: when the parent code already uses one representation (e.g. PG's
List*of pointers), the brainstorm inherits it without questioning, and the alternative (which may eliminate downstream ownership / lifetime / leak questions) never enters the candidate set. This was the jsonpath_leak trilogy's miss: approaches A/B/C/D all assumed pointer-based JsonValueList; Tom Lane's actual fix5a2043bf713redesigned to by-value inline-chunked storage, which made Clear pfreeing the chunks release everything atomically — no per-call MemoryContext needed. Seeplanning/jsonpath_leak/comparison.md§L5. The sub-question goes in EVERY approach's "Storage representation" field (per §5 of the output template).Adversarial-pass for control-flow shape when adding an every-exit invariant (L6). Before locking the approach list, run one more adversarial question when the fix targets an existing function: "Does the target function have ≥3 exit paths, AND does my fix introduce a step that must run at every one? If yes, have I enumerated the 'collapse to single exit + place the invariant there' option as approach E?" Default failure mode: when the parent code has 6 early-return sites and my fix needs a cleanup call at each of them, the easy path is to put the cleanup at function ENTRY (covers all returns with 1 call) or ADD 6 explicit cleanup calls before each return. Both work; neither considers "what if the 6 returns are the wrong shape given the new invariant?" This was the nodesubplan_leak trilogy's miss: our approach put the
MemoryContextResetat entry; Tom Lane's actual fixabdeacdb0920collapsed the six returns into a singlebool result+ one exit path with the reset there (net −16 executable lines vs our +11). Seeplanning/nodesubplan_leak/comparison.md§F32. Same additive- vs-restructure pattern the jsonpath_leak trilogy already showed — L5 and L6 are two views of the same failure mode (blind trilogy inherits parent shape without questioning). The sub-question fires on the FUNCTION being modified (not on any data structure); the approach E enumeration then goes in §5 of the output template (per the "Mandatory approach E" trigger). -
Recommend. Pick one. Default to COMPREHENSIVE scope, not minimal MVP (per R15 in pg-implement-discipline.md). If the user's framing or a reference impl from step 2 implies the comprehensive approach, take it as the default. MVP framing requires the user's EXPLICIT consent — name the tradeoff in the recommendation and let them opt down.
The recommendation must:
- Cite the §0.5 mechanism row this approach uses (reuse-vs- invent).
- Cite the §0 usage-class coverage (row-numbers list).
- Name 3 scenarios, 2 personas, 2 idioms the approach draws on (per §5 Citations requirement).
- If a reference impl exists from §0.7, explicitly state how the recommendation COMPARES to the reference: "matches reference surface" OR "extends reference by X" OR "scopes down vs reference by dropping Y, see DECISION 2".
-
Decisions. Name 3-5. Be specific — "scope (MVP vs full)" is too vague; "Should the MVP support DEFAULT clauses or only NOT NULL?" is right. Each DECISION must reference §0 example rows by number: "Should we support array-indirection (§0 rows 5-8) in v1?".
-
Write. Single file, ~250-450 lines (raised from the old 150-300 limit — the §0 + §0.5 + §0.7 + citation requirements make brainstorms LONGER, and that's correct: the cost of going deep at brainstorm time is far less than the cost of under-scoping at plan time).
-
Hand off. End with one short paragraph: "Run
/pg-plan <slug>when you've picked an approach and answered the DECISION: questions inline above." Or signal that the brainstorm itself surfaced a blocker that needs resolving before planning makes sense.
Boundaries vs other skills
pg-feature-plan(Phase 2): consumes this output. Don't do its work here.pg-claude: the master nav. Use to pick which subsystem docs to load.patch-submission: only relevant once a patch exists. Don't pre-empt./implement: takes over after Phase 2 + a real plan.
Style notes
- Be opinionated. A bland brainstorm with three equivalent approaches and no recommendation wastes the human's time.
- Be brief. The whole document should be readable in 5 minutes.
- Be honest about uncertainty. "I'm guessing the lockmgr would need a new lock type here, but I haven't verified" is more useful than a confident-sounding wrong claim.
- Cite the corpus when relevant:
[via knowledge/subsystems/X.md]for any subsystem-level claim. Use[unverified]for everything else.
Anti-patterns
- Designing instead of brainstorming. If you find yourself naming catalog columns, picking SQLSTATEs, or proposing test files — stop. That's Phase 2. The brainstorm answers "which direction" not "how exactly".
- Three-equivalent-approaches with no recommendation. A bland brainstorm wastes the user's time. Pick one. If you genuinely can't, that IS the DECISION: — surface it.
- Exhaustive prior-art search. §4 is a triage pass, not a literature review. Top 3 git-log hits + first page of CF + a quick PGXN check is enough. The user can ask for more later.
- Skipping the extension-already-exists reframe. If §4 hits a mature out-of-tree extension covering most of the ask, the candidate approaches MUST be framed against it (upstream vs harden vs move-to-contrib), not designed from scratch. The first DECISION: must surface this — see §Output 7 examples.
- Low-leverage DECISION: questions. "What should the GUC name be?" or "Should we document this?" are Phase-2 implementation details, not brainstorm DECISIONs. A DECISION: is a tradeoff only the user can adjudicate (scope, semantics, target version, core-vs-contrib).
- DECISION:-as-deferral. If the brainstorm offloads every question to the user, you haven't thought hard enough. Recommend a default; let the user override.
Where the artifact lives
planning/<slug>/brainstorm.md — in a NEW top-level directory
planning/, sibling to knowledge/ and sessions/.
The planning/ directory is for work-in-progress design docs.
Difference from knowledge/: knowledge is distilled durable
reference; planning is messy WIP that may be discarded. Difference
from sessions/: sessions are logs of what happened; planning is
forward-looking.
Cleanup policy: planning docs stay in tree until the feature lands (then the plan is referenced by the patch's commit message and can be archived) or until the user explicitly says drop it.
Cross-references
.claude/skills/pg-feature-plan/SKILL.md— Phase 2 consumer of this skill's output; readsplanning/<slug>/brainstorm.md+ the inline DECISION: answers..claude/skills/pg-implement/SKILL.md— Phase 3 consumer (via the plan); brainstorm is read for context only, not procedure..claude/skills/pg-claude/SKILL.md— master index used to pick which 1-3knowledge/subsystems/*.mddocs to load.knowledge/scenarios/_index.md— the scenarios decision tree consulted in §4 (Has this been tried?)..claude/skills/meta-commit-style/SKILL.md— the brainstorm.md file commits to the meta repo via this style.planning/README.md— directory layout forplanning/<slug>/..claude/commands/pg-brainstorm.md— slash-command wrapper that invokes this skill.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.