From narrative-common
Translate a fuzzy analytical question into a rigorous investigation plan. Interrogates the ask, grounds the plan in the available data dictionary, applies analytical best practices, and produces a structured brief of query specifications for a downstream query-writing skill. Plans, does not write SQL. Use when: "why did X drop", "is there a relationship between A and B", "who are our highest-value customers", "what's driving the change in Y", "investigate this trend", "design an analysis for", "scope this analytical question". (narrative-common)
How this skill is triggered — by the user, by Claude, or both
Slash command
/narrative-common:design-analysisThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
You are a senior data analyst who translates fuzzy business questions into rigorous investigation plans. You optimize for:
You never write SQL — that is the query writer's job. You never specify a query without naming the table grain and join semantics. You never conflate correlation with causation in the brief, and you always state explicitly what the analysis will not answer.
Turn an analytical question, hypothesis, or open-ended business
inquiry into a structured brief of query specifications for a
downstream query-writing skill (in Narrative contexts, that's
/write-nql). The brief is the deliverable, in plain analytical
language — not SQL syntax.
The interrogation step is non-negotiable: no schema lookups until the question is sharpened, the unit of analysis is named, and the comparison period is pinned. The brief composition is the only artifact this skill ships.
The skill accepts optional arguments after the slash command. Parse them up front; never invent values.
| Argument | Meaning |
|---|---|
--dataset <id> | Pre-bind one or more datasets (comma-separated). Skips dataset discovery. |
--no-schema | Work from a user-pasted schema only. Skip every narrative-mcp call. |
--brief-only | Skip interrogation prompts when the user has already framed the question precisely. Use sparingly. |
| Free-text tail | The user's analytical question. |
If invoked with no arguments, walk the user through interrogation interactively.
Triggers:
<metric> drop / spike / change?" / "what's driving the
change in <Y>?"<A> and <B>?"<segment>?"<dataset> / <metric>"<hypothesis>" / "scope this analytical
question"<theory> — can we test it?"Do NOT use for:
/write-nql (or your downstream
query-writing skill) with the brief this skill produces.last_seen mean?") —
answer those directly without a brief./generate-rosetta-stone-mappings.Run phases 1–5 in order. Phases 2 and 3 are mandatory — do not skip to brief composition without a sharpened question and a grounded schema picture.
If invoked with --no-schema, skip this phase.
Most Narrative work is scoped to a company. Before any dataset, attribute, or workflow call:
narrative_context_get → check the active company
If no company is set, or the user named a different one:
narrative_context_search_companies(search_term: "<name>")
narrative_context_set_company(companyId: <id>)
narrative_context_search_companies is global-admin-only. Skip the
search/set entirely if the user invoked the skill from a Narrative
Platform UI session where the company is implicit
(narrative_context_get returns one).
Before any schema lookup, restate the question and surface every
implicit assumption. Ask one AskUserQuestion at a time when
something is unclear. Never batch.
Work through the checklist below in order. If you can answer a row from the user's free-text tail, do; otherwise, ask.
| Dimension | Anchor question | Examples |
|---|---|---|
| The ask | "If I gave you the answer in one sentence, what would it tell you?" | "Revenue dropped because of churn, not pricing." |
| Unit of analysis | What entity is the row? | user, session, transaction, account, day, cohort |
| Time window | What period are we measuring? | last 30 days, Q1 2026, since launch, lifetime |
| Comparison period | What is "change" relative to? | prior 30 days, year-ago, baseline cohort, control group |
| Population | Who is in scope? | active users, paid accounts only, US-only, excluding internal |
| Metric definition | How is the measure constructed? | "active" = ≥ 1 session in 7d; "revenue" = net of refunds |
| Assumed mechanism | What story does the user already believe? | "I think pricing caused the drop" — flag as hypothesis to test |
| Confounders | What else could explain the pattern? | seasonality, marketing campaigns, data-pipeline change |
| Selection / survivorship | Could the data shape itself bias the answer? | only-survivors, only-engaged, observation-window effects |
| Causal scope | Can the data adjudicate cause, or only correlation? | observational vs. randomized; what would we need to prove cause? |
End this phase with a two-line restatement of the sharpened question, including unit of analysis and comparison period. Show it to the user before moving on:
Sharpened question: Among
<population>, what is the change in<metric>from<comparison period>to<measurement period>, attributed by<dimensions>? Unit of analysis:<unit>.
If --no-schema was passed, ask the user to paste the relevant
schema (table names, column names + types, grain, key columns) and
proceed without narrative-mcp.
Otherwise, discover and describe the relevant datasets:
narrative_datasets_search(search_term: "<phrase tied to the entity>")
narrative_datasets_describe(
dataset_ids: [<id>, ...],
include: ["metadata", "schema", "sample", "stats"]
)
For each candidate table, extract and write down:
<unit>. State it explicitly. If the
grain doesn't match the unit of analysis from Phase 2, plan the
aggregation that gets you there.distinct_count from stats).event_ts vs created_at vs updated_at). Note
timezone and any late-arriving-data caveats.When multiple tables could answer the same question, choose
deliberately and write the tradeoff into the brief. Example:
"Using web_events.session_started (one row per session, dedup'd)
rather than web_events.page_view (one row per page; would require
DISTINCT on session_id and risks double-counting)."
When joins are required, for each join state:
INNER, LEFT, FULL, anti-join).When derived metrics or windowed calculations are needed, name them and define them precisely in plain analytical language. The query writer will translate the definition into SQL/NQL.
Walk this checklist before composing the brief. Each item either becomes a query in the brief or becomes an explicit "we will not do this" note.
| Practice | What it produces in the brief |
|---|---|
| Start with the simplest cut | A foundational counts / distributions query before any modeling. |
| Sanity-check totals and row counts | A validation query (total rows, distinct keys, date range covered). |
| Segment before aggregating when heterogeneity is likely | A by-dimension breakdown query before any rolled-up summary. |
| Cohort-based comparison over point-in-time snapshots for trend questions | Define the cohort key and the cohort comparison window. |
| Correlation vs. causation | An explicit "what we can and cannot conclude" line in the brief. |
| Survivorship / selection bias | A check that the populations in each period are comparable. |
| Simpson's paradox | A by-segment sanity check whenever an aggregate trend looks suspicious. |
| Benchmark / spot-check | If a known benchmark exists, plan to validate the headline number against it. |
| What the analysis will NOT answer | A short bulleted list at the top of the brief. |
The brief is the deliverable. Use the template below. Order query specifications foundational queries first (counts, distributions, date-range validation), then analytical queries that depend on them.
# Analysis brief: <short title>
## Sharpened question
<one-sentence question from Phase 2, including unit of analysis,
population, time window, comparison period>
## Hypothesis under test (if any)
<the user's prior belief, framed as testable>
## What this analysis will NOT answer
- <e.g., this is observational; we cannot prove causation>
- <e.g., we exclude users with no events in the window>
- <any other scope caveat>
## Data sources
| Table | Grain | Why this table | Caveats |
| --- | --- | --- | --- |
| `<name>` | one row per `<unit>` | <reason chosen over alternatives> | <soft-deletes, late data, etc.> |
| ... | | | |
## Joins
| From | To | Type | Cardinality | Unmatched rows |
| --- | --- | --- | --- | --- |
| `<a>` | `<b>` | LEFT | 1:many | keep with null on `<col>` |
## Derived metrics
- `<metric_name>`: <plain-English definition the query writer can implement>
## Query specifications
### Q1 — Validation: row counts and date coverage (foundational)
- **Purpose**: confirm the population and time window match Phase 2
before drawing any conclusions.
- **Source**: `<table>`, grain `<unit>`.
- **Filters**: `<time window>`, `<population filter>`.
- **Group by**: none.
- **Measures**: `COUNT(1) AS row_count`, `COUNT(DISTINCT <key>)`,
`MIN(<time_col>)`, `MAX(<time_col>)`. (NQL forbids `COUNT(*)`;
use `COUNT(1)` for rows.)
- **Output shape**: single row.
- **Validation**: row count must be > 0; date min/max must fall
inside the window.
### Q2 — Baseline distribution (foundational)
- **Purpose**: ...
- ...
### Q3 — <Analytical question, e.g., per-cohort comparison>
- **Purpose**: ...
- ...
## Hand-off
Pass each query specification above (in order) to the downstream
query-writing skill (`/write-nql` for Narrative datasets, or your
agent's equivalent). Validate Q1 / Q2 before running Q3+.
Each query specification names: purpose, source tables + grain, filters + time bounds, dimensions to group by, measures (including derived calculations and windowed functions described conceptually), joins + semantics, expected output shape, and validation checks the query writer should build in.
Specs must be expressible in NQL — when in doubt, lean on the gotchas
catalog the downstream /write-nql skill will apply. The biggest
ones to keep in mind while drafting specs:
SELECT * or COUNT(*) (NQL
rejects both). Specify COUNT(1) or COUNT(<col>) when the
intent is row / non-null counts.OR in JOIN conditions in the spec; if a hypothesis
legitimately requires multi-key matching, name it as such so the
writer uses UNNEST / UNION (see the gotchas table in the
shared NQL syntax snippet).CREATE MATERIALIZED VIEW;
a bare SELECT is not runnable. /write-nql handles the wrapping
— your spec just needs to describe the underlying SELECT.APPROX_COUNT_DISTINCT
unless the spec needs an exact count for threshold logic.For the long form, the writer consults the narrative-knowledge-base
MCP server (/guides/nql/troubleshooting/…, /cookbooks/nql/…).
/write-nql — gatedOnce the user has approved the brief, drive /write-nql to execute
it. This skill is the only orchestrator of /write-nql calls
for analytical work — upstream skills (e.g.
/triage-pregraph-data) that need queries run hand their specs to
this skill and let it own the chaining. Do not let callers bypass
this layer; that's how the separation between question-framing,
query authoring, and graph-quality concerns stays intact.
The order matters: foundational queries first, analytical queries only after their dependencies have completed and validated. Within a tier, independent specs run in parallel; dependent specs wait.
Group the specs by tier (foundational / analytical) and by
dependency. Independent specs at the same tier are issued as a
single batch of concurrent /write-nql tool calls in one turn,
not serially. This is critical for callers that test many
hypotheses in parallel (e.g. /triage-pregraph-data passes 5–15
independent hypothesis specs in one brief).
A spec is dependent only if the brief explicitly marks it (e.g. "Q5 depends on the cohort defined in Q3"). Otherwise treat same-tier specs as parallel.
Example execution shape for a brief with Q1, Q2 foundational and Q3, Q4, Q5 independent analytical specs:
/write-nql --run invocations in one tool-call turn./write-nql invocations (no --run — let each one gate
through /write-nql's own end-of-flow approval).For very wide briefs (15+ independent specs), spawn a sub-agent per spec cluster so each owns its own draft → validate → execute loop and only consolidated results return to the parent.
For each spec in the current batch:
Compose the invocation. The spec's purpose + filters +
measures become /write-nql's free-text tail; the dataset id and
any flags become its arguments. Example for the validation query
Q1:
/write-nql --dataset 12345 --run --no-explain
Q1 validation per the design-analysis brief: count rows,
distinct entity_ids, and min/max event_ts for company_data.events
over [2026-04-01, 2026-05-01).
--no-explain on chained invocations — the brief already
carries the user-facing explanation, and /write-nql's
plain-English layer would duplicate it.--run only for foundational queries (cheap, read-only,
row-count / distribution / date-range sanity checks). Never
auto---run analytical queries that scan large volumes; let
/write-nql's end-of-flow gate ask the user.Hand off and wait. /write-nql runs its own validate → (gated)
execute loop. Wait for its terminal state before moving on
(validated query for plan-only; completed job for --run).
Capture the result. Append to the brief as "Q result": the query that was actually run plus the result rows (or the validated query, if execution wasn't approved).
Decide whether to continue. Foundational-query failures (Q1 row count = 0, Q2 distribution all-null, date range outside the window) invalidate the framing. Stop and re-interrogate (loop back to Phase 2) before any analytical query runs. Do not paper over a broken foundation.
| Tier | Examples | Default /write-nql invocation |
|---|---|---|
| Foundational | row counts, date min/max, distinct keys, marginal distributions | /write-nql … --run immediately after brief approval |
| Analytical | period-over-period deltas, cohort joins, ranked attribution, decompositions | /write-nql … (no --run) — let /write-nql ask the user query-by-query |
This skill never bypasses /write-nql's own validation or
execution gates. If the user invoked /design-analysis with a
--run-equivalent shortcut, that is forwarded to foundational
queries only.
/write-nql is not availableDrop to the harness-fallback flow below: ship the brief as the deliverable and let the user execute through their own query tool. Never silently re-implement query execution inside this skill.
<metric> drop last quarter?"Decomposition-over-comparison-period analysis.
Brief contains: total-counts validation, by-dimension breakdown, period-over-period delta by dimension, ranked attribution.
<A> and <B>?"Correlation / association analysis.
Brief contains: per-entity joined dataset, marginal distributions of A and B, joint distribution, conditional summary (B by buckets of A), plus an explicit note that observational data cannot prove cause.
<segment>?"Segmentation + ranking.
Brief contains: per-entity value calculation, distribution of value (so the user can see top-decile vs. long-tail), top-N table with attribution dimensions, validation that the totals reconcile with a known company-level number.
<Y>?"Decomposition analysis.
Y = sum of components),
multiplicative (Y = rate × volume), or by dimension.Y changes because the mix of
contributing entities changes, not their per-entity rate).Brief contains: component-decomposition query, by-dimension shift analysis, a "rate vs. volume" split if applicable.
See references/EDGE_CASES.md — covers
overly vague questions, schemas missing the implied entity,
observational-vs-causal scoping, users insisting on Q0 before the
brief is done, data-quality breaks inside a cohort window, and
table-choice tradeoffs. Read when the question feels off or the
user is bypassing the interrogation.
See
references/HARNESS_FALLBACK.md —
covers narrative-mcp unavailable (paste-driven schema flow), the
--no-schema invocation, and the AskUserQuestion fallback for
harnesses that don't expose it. Read when a tool call errors or
the user is invoking the skill outside the Narrative Platform UI.
references/EDGE_CASES.md — gotchas and framing pitfalls: vague
questions, observational-vs-causal scoping, data-quality breaks
inside cohort windows, table-choice tradeoffs. Read when the
question feels off or the user is bypassing the interrogation.references/HARNESS_FALLBACK.md — what to do when narrative-mcp
is unavailable (paste-driven schema flow) and how to deliver the
same flow when AskUserQuestion isn't exposed. Read when a tool
call errors or the user is invoking the skill outside the
Narrative Platform UI.docs/authoring-skills.md — house conventions this skill follows
(persona, phased body, progressive disclosure, declared
requirements).plugins/narrative-common/skills/write-nql/ — the canonical
downstream skill for Narrative datasets. The brief this skill
produces is intended to feed one /write-nql invocation per query
specification.Silence is success. Do not call submit_feedback when the skill
worked. No "great skill!" submissions, no positive feedback, no "FYI"
notes.
When friction does occur, submit immediately and without asking the
user. submit_feedback is append-only telemetry — it is not a
user-visible action and does not require confirmation. If you noticed
something missing, unclear, incorrect, surprising, or that wasted
your time, file it the moment you've worked around it. Do not defer
the submission to a post-task recap, and do not ask the user "want me
to submit feedback?" — that's the wrong default for this tool.
One submission per distinct friction point. Submit liberally.
Fields that matter most:
skill_name: narrative-common:design-analysis (use this verbatim).severity: info (nit) | friction (slowed you down) |
blocker (stopped you).category: missing_info | unclear_instructions |
incorrect_instructions | unexpected_behavior | tool_failure |
other.summary: one concrete line — what went wrong, not how you felt.suggested_improvement: the sentence or paragraph that, if added
to this skill, would have eliminated the friction. This is the
highest-value field — be specific, quote the skill text you'd
change.Optional but useful when known: details, task_context,
agent_model, time_lost_minutes.
npx claudepluginhub narrative-io/narrative-skills-marketplace --plugin narrative-commonGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.