Skip to content

skills: add malloy-model-as-you-go - #1079

Merged
jswir merged 12 commits into
mainfrom
skills/malloy-reproducible-analysis
Aug 28, 2026
Merged

jswir merged 12 commits into
mainfrom
skills/malloy-reproducible-analysis

Conversation

@jswir

@jswir jswir commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

What this does

Adds a skill for the step after a data question is answered: writing down what the answer assumed, in the most durable place the session can write. Today an agent either builds a full model before answering anything, or answers ad hoc and formalizes later if someone remembers to. Both lose the reasoning behind each definition, because nobody wrote it down when the decision was actually made.

malloy-analysis answers the question. This skill runs right after, while the query is still in front of the agent, and decides what to codify and where.

Where the assumption lands depends on what the session can write

The same judgment call ("returns don't count as revenue") lands differently depending on the tools available, and the skill says so explicitly instead of assuming everyone can edit the model:

You can Codify as
Edit the model files (local package, draft package) a measure: / dimension: / view: with a #(doc) in the .malloy, after confirming binding decisions
Author notebooks or reports, not the model (a viewer) source: orders_q is orders extend { ... } with the #(doc) in a notebook cell, plus a markdown cell stating the assumption
Only chat (claude.ai, Cowork) the assumption stated in the answer, plus the Malloy snippet a modeler could paste

Pick the highest rung the tools allow; never skip codifying because the model is read-only.

What reviewers should look closely at

The skill asks the user to confirm a judgment call before it goes into the model, not after. While a decision lives in one query it's the analyst's own call. The moment it becomes a measure:, it's the definition everyone downstream inherits, and they never see the reasoning. So the skill stops and asks first, with both numbers shown, instead of picking one and mentioning it in the write-up. It only asks when the alternative would change the number, when the call is about to become permanent, or when a different analyst could reasonably pick the other option. Everything else gets a one-line note.

Routing

malloy-modeling and the malloy index now send a first-message data question (and "build a model but not sure what metrics") to this skill. malloy-analyze keeps open-ended exploration with no intent to keep anything. Retiring malloy-analyze and folding its EDA loop into malloy-analysis is a separate change (proposed in ms2data/service#6177); this PR goes ahead of it.

Shared-skill compliance

Shared skill, so it lives here first and gets vendored downstream. No credible- prefix; no platform-specific tools or answers (no execute_query_draft, no hosted draft/publish flow, no #(index)/#(agent-hidden)). All skill: references point at shared skills: malloy-analysis, malloy-analysis-pitfalls, malloy-charts, malloy-dashboards, malloy-notebooks, malloy-model, malloy-lookml-review, malloy-analyze. Tools are named bare, with the host note.

Packaging

  • .claude/skills/malloy-model-as-you-go symlink so Claude Code discovers it.
  • skills_bundle.json regenerated: 57 entries, 32 skills plus 25 reference files.
  • packages/skills bumped to 0.1.10. 0.1.9 is already published on npm, so leaving the version alone would make a release skip this package and stay green while shipping none of these skills. The release guard catches that.

Testing

bun test src/mcp/skills in packages/server (18 pass: bundle in sync, no em dashes) and bun run --cwd packages/skills test (15 pass) on this branch.

The earlier shape of this skill was run end to end against a real BigQuery dataset: three questions produced a five-field model, re-verified by running the codified measures back through a served package and matching the original numbers to the cent. Not yet exercised on a fresh dataset: the confirm-before-codify checkpoints, and the notebook and chat-only rungs of the ladder. Those were written from the four user situations (local developer, Credible viewer, Credible modeler, chat-only), not from a run. Worth a reviewer's eye.

History

Earlier commits on this branch carry the previous name (malloy-reproducible-analysis) and shape; the last commit does the rename and the reshape.

@jswir
jswir force-pushed the skills/malloy-reproducible-analysis branch from 2b02ca3 to bbb766f Compare August 26, 2026 22:54
@jswir jswir changed the title skills: add malloy-reproducible-analysis skills: add malloy-model-as-you-go Aug 27, 2026

@kylenesbit kylenesbit left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving — the skill is strong and the mechanics check out. Three shared-skill governance items to address, the first before merge if possible.

What I verified

  • The writable-surface ladder (model file → notebook extend → stated assumption + snippet) keyed off tools present, not guessed roles, is the right design, and confirm-before-codify with both numbers attached is the right control — "reporting it afterwards is not confirming it" is exactly the distinction.
  • Symlink target correct; skills_bundle.json regenerates byte-identically from this tree (57 entries, new skill present); DCO signed; all checks green; bare tool names with the host note; and the explicit departures from skill:malloy-model are declared in both skills, which is how to disagree with a sibling skill without creating a contradiction.

Items

  1. skill:malloy-dashboards breaks the shared-skill reference rule. skills/README.md on this branch says a shared skill may only skill:-reference other shared skills, and classifies malloy-dashboards as Publisher-specific ("dashboards are a Publisher surface"). The new skill references it in "Save the view when a question is worth re-asking" (the PR body lists it among shared references, which contradicts the README). The README's own escape hatch fits: neutral prose — "views wanted side by side belong in a notebook, or in a dashboard surface if the host has one" — keeping only skill:malloy-notebooks. One-line fix; would be good before merge.

  2. malloy-model is a shared skill edited downstream-first. The README rule is upstream-first (ms2data/agent-skills), then copy, or the next sync conflicts. If the agreed direction for the new skill is publisher-first, fine — but the hunk in the existing shared malloy-model is squarely what the rule exists for. Please mirror it (and the new skill, if it is to be shared) upstream at or before merge, and note it here. The new skill also needs adding to the README's shared-skills list.

  3. The narrowing doesn't reach where hosts actually route from. malloy-analyze is narrowed to "open-ended exploration" in the two routers, but its own front-matter description still says "Explore data for insights and build views/dashboards/notebooks… or any analysis task" — and that description is what Claude Code matches for auto-invocation. A first-message data question will keep landing on malloy-analyze directly, bypassing the routers. Either narrow that description too (again upstream-first), or state in the README/PR that description-routing hosts won't see the new behavior until the malloy-analyze retirement lands.

Notes, not blockers

  • Branch is behind main; needs a branch update before merge (protection is strict; no conflicts).
  • skills-npm.yml's PR job packs and tests but doesn't compare versions against npm — moot here since 0.1.9 > published 0.1.7, so no bump needed.
  • On the honest flag that the confirm checkpoints and the notebook/chat rungs weren't exercised on a fresh dataset: given they're the heart of the skill, one real run on the middle rung would be worth doing before this ships broadly — not holding the PR for it.

@jswir

jswir commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks — all three addressed, plus the branch update.

1. skill:malloy-dashboards reference. Fixed with the README's own escape hatch: neutral prose for the dashboard surface, keeping only skill:malloy-notebooks.

views wanted side by side belong in a notebook (skill:malloy-notebooks), or in a dashboard surface if your host has one

You were right that the PR body contradicted the README; the body was wrong, not the classification.

2. Direction of the malloy-model edit. This is publisher-first on purpose, and I should have said so here rather than leaving it to be inferred. The proposal in ms2data/service#6177 reverses the upstream-first rule: this repo becomes the source of truth for the shared set and agent-skills vendors from a pinned Publisher tag with a CI drift check, so the hand-carried cp goes away. #1088 lands the first half of that.

I've added malloy-model-as-you-go to the README's shared-skills list and recorded the reversal next to the upstream-first rule, including that this skill and the malloy-model hunk need mirroring by hand until the vendoring script exists. Happy to reorder if you'd rather this waited behind #1088.

3. The narrowing not reaching description-routing hosts. This was the most useful catch — the routers were doing nothing for auto-invocation. malloy-analyze's own description now scopes it and names where a specific question goes instead:

Open-ended exploration with no specific question to answer, and building views/dashboards/notebooks on an existing model. … Not for a specific data question - answering one is malloy-analysis, and writing down what the answer assumed is malloy-model-as-you-go.

Notes. Rebased onto current main (was 4 behind, no conflicts). Bundle regenerated: 57 entries, 32 skills. packages/server MCP-skills specs 18 pass; packages/skills 15 pass.

On the unexercised middle rung: agreed, and it stays flagged in the PR body. A real viewer-session run is the check I'd want before this ships broadly, and it's the one claim in the skill I haven't been able to back with evidence.

@jswir
jswir force-pushed the skills/malloy-reproducible-analysis branch from 5776a46 to a09914a Compare August 27, 2026 23:54
jswir added 8 commits August 27, 2026 22:43
An analysis that lives in a chat transcript is not reproducible. Six weeks on
nobody can say what revenue excluded, which of four timestamps was the order
date, or whether the last period was complete, so the work gets redone.

This skill codifies the analysis into a semantic model as it runs, rather than
proposing one from the schema up front. Answer a question, write down what the
answer assumed, answer the next one; every field ends up traceable to the
question that needed it.

The spine is naming the judgment calls the data cannot settle, and confirming
one before it is codified - a decision stops being the analyst's the moment it
becomes a measure everyone inherits. The codify rubric leads with 'a reader
needs this to trust the number' rather than reuse.

Shared skill, copied verbatim from ms2data/agent-skills (upstream first, per
skills/README.md). No platform-specific tools or answers; all eight skill:
references point at other shared skills.

Includes the .claude/skills symlink and the regenerated MCP bundle. No
packages/skills version bump: main is 0.1.9, npm is 0.1.7, and skills-npm.yml
asks whether the declared version is ahead of npm rather than whether this PR
changed it.

Signed-off-by: James Swirhun <james@credibledata.com>
Step 1 read as though the skill's job was generating questions: a one-line 'if
the user brought a question, use it' followed by three paragraphs on the branch
where they didn't. The description matched, keying on 'analyzing data that has
no model yet' rather than on someone asking something.

The skill is what an agent reaches for when a user arrives WITH a data question.
Step 1 now says so: restate what was asked, decide what a right answer looks
like, and do not widen it into a modelling project or swap it for a more
interesting question found on the way. Ambiguity is resolved by taking the most
reasonable reading and stating it rather than stalling.

Proposing questions survives as a fallback for a genuinely empty start, in one
paragraph, marked as not the normal path.

Copied verbatim from ms2data/agent-skills; bundle regenerated.

Signed-off-by: James Swirhun <james@credibledata.com>
Four changes from running the skill end to end on an unmodelled dataset.

A broad ask is an ask. The empty-start fallback told the agent to profile
and offer three questions, two paragraphs after "the user gets a real
answer on question one" and next to an anti-pattern against opening with a
menu. For "analyse the political ads data" those point opposite ways, and
the agent had to referee. Say plainly: pick the obvious question, name it,
answer it. Working out what is analysable does not need a skill.

Confirm binding decisions, do not report them. The rule existed but was
scoped to a measure encoding an ANSWER decision, and "report it afterwards"
read as compliance. In the run, `spend_estimate` was defined as a bucket
midpoint and the user was told after the fact. Worse, `where: regions =
'US'` went onto the source - scoping every future question against it - and
was also only mentioned in the write-up. Widen the rule to dimensions,
views, joins and source-level filters, and require stopping for an answer.

Every number comes out of a query. The run reported a campaign-level
rollup (~$192M vs ~$136M) added up by hand from a `limit: 15` table, which
drops every committee below the cut and cannot be re-run. There is a query
language and an execute tool; nothing needs estimating by eye.

Do not encode tool bugs as data properties. POINT said a schema tool "may
return no columns - do not debug that". That taught the agent to route
around a bug silently. `select: *` is the better first move on its own
merits, because sample values catch what a column list hides. An
unexplainable schema result is a bug to report, not a fact about the data.

Also name the query tool per host, since Publisher and Credible differ and
draft-vs-published is easy to confuse; and fix a house-style em-dash that
was failing the bundle's own spec on this branch.

Signed-off-by: James Swirhun <james@credibledata.com>
…ocs in the loop

Three things a session following this skill got wrong, each traceable to the
text rather than to the agent.

Docs were listed as step 1 of the hand-over checklist, under 'Do not do this
during the loop'. Followed correctly, that produces a model with no #(doc) at
all - the reasoning reaches nobody, because the hand-over often never comes.
Docs now happen in CODIFY, one line while the query is still in front of you,
and hand-over is a re-read for drift. Adds the #(doc)-versus-comment rule: #(doc)
for what a consumer needs, // for what only a maintainer needs.

Saving a view was one line near the end, after a codify table listing only
dimensions, measures, joins, and filters, so it read as an afterthought and got
skipped. It is now part of the sweep, and dashboards are named alongside views.
malloy-model's 'Views: None' said the opposite with no exception, so this scopes
that rule to schema-first and gives the reason: a schema-first model is written
before anyone asks a question, so its views would be guesses.

Access modifiers and one-file-per-table are now explicitly out of scope for
analysis-first, in both skills. They solve a schema-first problem, and an
analysis-first model has nothing to curate - every field in it was paid for by
a question.

Signed-off-by: James Swirhun <james@credibledata.com>
The bundle embeds each skill's full body, so the served copy was stale after
the previous commit's edits to malloy-reproducible-analysis and malloy-model.

Signed-off-by: James Swirhun <james@credibledata.com>
No guidance removed, only restatement. The intro said 'a model is the fix'
twice; 'leave behind the ad-hoc' and 'codify thin' were one point split in two;
the #(doc) rule ran as two paragraphs with an overlapping middle; and the views
section restated the binding-decision rule that the confirm table above it
already carries. Two anti-patterns collapsed into their neighbours for the same
reason.

skills/malloy-reproducible-analysis/SKILL.md 370 -> 344 lines, and the
malloy-model addition from the previous commit drops from 17 lines to 11.

Signed-off-by: James Swirhun <james@credibledata.com>
The skill re-explained how to answer a question (restate it, discover,
construct, verify, present) before getting to what it was for: writing
the answer's assumptions down. That duplicated malloy-analysis and
malloy-analysis-pitfalls, and hid the new part.

Now: answer with malloy-analysis, then CODIFY. What changes is where the
assumption lands, and that depends on what the session can write, not on
who the user is. Three rungs: a #(doc)'d field in the model when the
files are editable; a source extend plus a markdown note in the notebook
when only reports can be authored; the assumption stated in the answer
plus a Malloy snippet when it is chat only. Pick the highest rung the
tools allow and never skip codifying because the model is read-only.

Kept from the previous shape: the one-line source bootstrap when no
model exists, naming the decisions the answer rests on, confirm before
codifying anything binding, the codify rubric, #(doc) versus //, the
notes file, saving the view, the hand-over list. 344 -> 289 lines.

Routing: malloy-modeling and the malloy index now send a first-message
data question to this skill; malloy-analyze keeps open-ended exploration
with no intent to keep anything. Bundle regenerated.

Signed-off-by: James Swirhun <james@credibledata.com>
Three items from Kyle's review.

1. The save-the-view paragraph referenced skill:malloy-dashboards, which
   skills/README.md classifies as Publisher-specific, and a shared skill
   may only skill:-reference other shared skills. Uses the README's own
   escape hatch instead: neutral prose for the dashboard surface, keeping
   only skill:malloy-notebooks.

2. malloy-model-as-you-go added to the README's shared-skills list. The
   README's upstream-first rule is recorded as being reversed by
   ms2data/service#6177, under which this repo becomes the source of
   truth and agent-skills vendors from a Publisher tag with a drift
   check; this skill and the malloy-model hunk were authored here on that
   basis, and need mirroring by hand until the vendoring lands.

3. Narrowing malloy-analyze in the two routers did not reach the place
   hosts actually route from. Its own frontmatter description still said
   "any analysis task", and that is what a description-matching host
   auto-invokes on, so a first-message data question kept landing there
   and bypassing the routers. The description now scopes it to
   open-ended exploration and view-building, and names where a specific
   question goes instead.

Bundle regenerated.

Signed-off-by: James Swirhun <james@credibledata.com>
@jswir
jswir force-pushed the skills/malloy-reproducible-analysis branch from a09914a to fae1f2d Compare August 28, 2026 04:43
malloy-model and malloy-notebooks already mark #(filter) legacy and document
given: as the replacement. Four consumer-facing skills were never updated and
still present #(filter) as the current mechanism - malloy-define even tells the
agent to write new #(filter) annotations into a model it is authoring.

Each now points at given: and names the two exceptions malloy-model already
documents, required and implicit, so the guidance does not overshoot into cases
given: cannot cover yet.

Signed-off-by: James Swirhun <james@credibledata.com>
@jswir

jswir commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator Author

Folded #1081 into this PR (its commit, cherry-picked unchanged) and re-signed the history.

Why here: #1081 was unreviewed and is 14 lines of the same kind of content this PR carries — pointing consumer skills at given: instead of the deprecated #(filter), across malloy-analysis-report, malloy-analyze, malloy-define and malloy-document. It was also the thing blocking the next skills PR, which deletes malloy-analyze; folding it here dissolves that.

@kylenesbit this is new content since your approval, so it wants a fresh look — sorry for the moving target. It's one commit (87597a24) and independent of the three items you raised.

Also fixed: DCO went red after the rebase. The original remediation commit named a SHA that the rebase had rewritten, so it no longer covered anything. Signed every commit properly and dropped the remediation commit instead of stacking a second one; the tree is byte-identical, only the history changed.

Bundle regenerated (57 entries, 32 skills). packages/server MCP-skills specs 18 pass, packages/skills 15 pass.

jswir added 3 commits August 28, 2026 11:49
0.1.9 is now on npm, so publishing the declared version would skip this
package: the release stays green while shipping none of the skills content
this PR adds. The release guard catches exactly that.

Signed-off-by: James Swirhun <james@credibledata.com>
The publish job rewrites the scaffolder's `@malloy-publisher/skills:
workspace:*` to `^<skills version>`, so bumping skills to 0.1.10 changes
what this package ships even though no skills file enters its tarball.
0.0.8 is already on npm, so without this the scaffolder would be skipped
at release and keep depending on ^0.1.9.

Signed-off-by: James Swirhun <james@credibledata.com>
@jswir
jswir merged commit 39d27a3 into main Aug 28, 2026
19 checks passed
@jswir
jswir deleted the skills/malloy-reproducible-analysis branch August 28, 2026 18:42
jswir added a commit that referenced this pull request Aug 29, 2026
Two conflicts, plus one the merge could not see.

RELEASE_NOTES.md: the 0.2.0 stamp (#1090) renamed the colocated-persist
`[Unreleased]` heading this branch's new section sits above. Kept both -- the
new section stays `[Unreleased]`, the stamped heading stays 0.2.0, per the
file's own rule that a version-stamped heading is history.

skills_bundle.json: regenerated from the merged `skills/` tree rather than
merged by hand, per skills/README.md. Carries main's new malloy-model-as-you-go
alongside this branch's `from()` corrections; 57 entries, drift specs pass.

The one tsc caught: #1079 made `modelPath` a required argument to
`filterPublisherOwnedRenderLogs`, deliberately, so a new call site cannot widen
the suppression back to every query. The load-time call site this branch adds is
exactly such a new call site, and it merged cleanly while failing to compile.
It now passes the model's own path.

Version bumps for @malloy-publisher/skills and create-malloy-package are no
longer this branch's: 0.2.0 landed the same 0.1.10 and 0.0.9 independently.

Signed-off-by: James Swirhun <james@credibledata.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants