Jupyter Notebook
microsoft/ai-agents-for-beginners
ใช้เมื่อผู้ใช้ร้องขอให้สร้าง จัดโครงร่าง หรือแก้ไข Jupyter notebooks (.ipynb) สำหรับการทดลอง การสำรวจ หรือบทแนะนำ; ควรใช้เทมเพลตที่มาพร้อมและรันสคริปต์ช่วยเหลือ newnotebook.py…
Create Malloy notebooks (a .malloy file under notebooks/, written as a one-column layout of tiles) for interactive data stories and reports.
$ npx skills add malloydata/publisher --skill malloy-notebooks -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install malloydata/publisher malloy-notebooks --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/malloydata/publisher.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/malloy-notebooks .claude/skills/malloy-notebooks && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "malloy-notebooks" agent skill from https://github.com/malloydata/publisher/tree/main/skills/malloy-notebooks into .claude/skills/malloy-notebooks/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "malloy-notebooks", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/malloydata/publisher/tree/main/skills/malloy-notebooksType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add malloydata/publisher --skill malloy-notebooks -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install malloydata/publisher malloy-notebooks --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/malloydata/publisher.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/malloy-notebooks .agents/skills/malloy-notebooks && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "malloy-notebooks" agent skill from https://github.com/malloydata/publisher/tree/main/skills/malloy-notebooks into .agents/skills/malloy-notebooks/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "malloy-notebooks", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add malloydata/publisher --skill malloy-notebooks -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install malloydata/publisher malloy-notebooks --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/malloydata/publisher.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/malloy-notebooks .cursor/skills/malloy-notebooks && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "malloy-notebooks" agent skill from https://github.com/malloydata/publisher/tree/main/skills/malloy-notebooks into .cursor/skills/malloy-notebooks/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "malloy-notebooks", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/malloydata/publisher.git --path skills/malloy-notebooks--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add malloydata/publisher --skill malloy-notebooks -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install malloydata/publisher malloy-notebooks --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/malloydata/publisher.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/malloy-notebooks .gemini/skills/malloy-notebooks && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "malloy-notebooks" agent skill from https://github.com/malloydata/publisher/tree/main/skills/malloy-notebooks into .gemini/skills/malloy-notebooks/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "malloy-notebooks", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install malloydata/publisher malloy-notebooksInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add malloydata/publisher --skill malloy-notebooks -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/malloydata/publisher.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/malloy-notebooks .github/skills/malloy-notebooks && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "malloy-notebooks" agent skill from https://github.com/malloydata/publisher/tree/main/skills/malloy-notebooks into .github/skills/malloy-notebooks/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "malloy-notebooks", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add malloydata/publisher --skill malloy-notebooks -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install malloydata/publisher malloy-notebooks --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/malloydata/publisher.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/malloy-notebooks .opencode/skills/malloy-notebooks && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "malloy-notebooks" agent skill from https://github.com/malloydata/publisher/tree/main/skills/malloy-notebooks into .opencode/skills/malloy-notebooks/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "malloy-notebooks", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
malloy-notebooksCreate Malloy notebooks (a .malloy file under notebooks/, written as a one-column layout of tiles) for interactive data stories and reports.
Malloy Notebooks is an agent skill from malloydata/publisher. Create Malloy notebooks (a .malloy file under notebooks/, written as a one-column layout of tiles) for interactive data stories and reports. Use when user asks to "create a notebook", "make a notebook", "data story", or needs to build reports/visualizations that read top to bottom. Legacy .malloynb files are read, not newly authored.
Its SKILL.md is about 6k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
The repository describes itself as: Publisher is the open-source analytics engine for Malloy. It lets you define data models once — and use them everywhere. The licence is MIT.
5 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit b9a1a19. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
No scripts in the folder and no shell commands in SKILL.md (its code samples are malloy).
From the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Malloy Notebooks loads about 6k tokens when it runs. Until then it costs about 88 tokens; SKILL.md has 3,020 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from malloydata/publisher at commit b9a1a19, republished under its MIT licence (© malloydata). 3,020 words, ~5,976 tokens.
.claude/skills/malloy-notebooks/SKILL.md (or your agent's skills folder).<!--
Copyright (c) Credible Data Inc.
SPDX-License-Identifier: MIT
-->
Files: notebooks/<slug>.malloy. Author a notebook as a one-column layout of tiles (next section). Notebooks written as run: cells, and existing .malloynb files, are still read and served, but a new notebook is never a .malloynb.
skill:malloy-analysis-reportThis skill is for curated notebooks that live in a package. Interactive parameter widgets render automatically from the given: declarations the notebook file declares or imports.
For ad-hoc reports generated by an analysis agent, combining queries into a quick narrative artifact, use skill:malloy-analysis-report instead. Ad-hoc reports also inherit whatever the source declares.
A notebook is a .malloy file directly under the package's top-level notebooks/ directory (not a subdirectory) whose model-level notes include ## artifact { kind=notebook … }. The artifact tag turns the file into a notebook. A .malloy file under notebooks/ with no artifact tag is a shared include, not a notebook, and is left out of the notebook list. Publisher serves the notebook at /<env>/<pkg>/notebooks/<slug> and lists it beside any .malloynb files. The tag's kind= decides the document's kind, not the folder.
The file is ordinary Malloy: it compiles as one model, it is validated by the same /compile call as any model, and its cells run against the whole file (every import and given: in scope).
A notebook is a dashboard with one column. Its artifact tag lists the tiles in reading order, each either a query ("source -> view", always a quoted string) or a prose block (name { kind=text }, a bare name), and the file defines the views and the prose:
##! experimental.givens
##" One category at a time: how it sells across the year and which brands carry it.
##| artifact { kind=notebook title="Category review"
tiles=[
intro { kind=text },
"category_tiles -> revenue_trend",
"category_tiles -> brand_ranking"
]
}
|##
import { order_items, products } from "../storefront.malloy"
#(description="Narrow to one product category")
# label="Category" control=select suggest { source=products dimension=category }
given: CATEGORY :: filter<string> is f''
##|(markdown) intro
## Category review
Pick a **Category** in the controls above and every chart below re-runs for it.
|##
source: category_tiles is order_items extend {
# line_chart
# label="Revenue by month"
view: revenue_trend is sales_by_month + { where: category ~ $CATEGORY }
# bar_chart
# label="Top brands"
view: brand_ranking is top_brands + { where: category ~ $CATEGORY }
}## artifact { … }) or a ##| … |## block with the same text inside, the form to use once the list is long: one tile per line, } on its own line, |## closing at the opener's column. Both read, lint and edit the same, and the builder keeps whichever form the file has. tiles=[…] is the notebook: tiles render top to bottom in list order, one column wide. dashboard { columns } other than 1 has no effect on a notebook, and a colspan or break on a tile entry is ignored with a warning (notebook-tile-layout-ignored)."orders_tiles -> headline" is a string; orders_tiles -> headline unquoted does not parse, and the lint says so (notebook-artifact-unparsed) rather than reading the file as a cell notebook.view: on a source, named as "source -> view". Put the views on a <source>_tiles extension as thin wrappers (view: revenue_trend is sales_by_month + { where: … }): the modelled view keeps its chart tag, the wrapper says which controls the tile answers to and carries the tile's # label. A run: in a layout notebook is never shown, and the lint reports it (notebook-layout-run): define a view, list it in tiles, and delete the run:.##|(markdown) name block listed as name { kind=text }. The name is one bare word on the opener line, the body starts on the next line (a heading goes inside the block), and |## closes it at the opener's column. Every text entry needs its block, and every named block needs an entry written with { kind=text }: a bare intro without it is the query-tile form (it names a query: in the file), so a block of that name is not shown.<source>_tiles extension. Tiles read in tiles=[…] order wherever their blocks sit; grouping the blocks before the extension is the convention the builder writes, and it inserts a new block after the last one.# line_chart, # label="…"), as on a dashboard; the malloy-dashboards skill has the tag set and the lint.given: above the view that reads it as $NAME, with the controls tags shown.get_context and notebook chat work on it as on any notebook.kind= decides the document's kind, not the folder. Keep notebooks in notebooks/ and dashboards in dashboards/; a file in the other folder works, and the lint notes it (notebook-other-folder). An untagged .malloy file in notebooks/ is a shared include.The rest of this skill (the header rules, given:, charts, style) applies to both forms. The sections on cells describe the older form, where the file is a sequence of run: statements and (markdown) notes: Publisher still reads it, and a person saving it in the Console converts it to a layout.
Rules 1 and 4 hold for both forms; rules 2, 3 and 5 are about run: cells and prose notes.
##! flags, // comments and unnamed " notes (the description), then ## artifact { kind=notebook … }. Nothing else goes above the tag. A statement or a tag above ## artifact is an error, and the notebook is served with that error instead of opening.(markdown) annotation, and the number of # says what it belongs to. Floating markdown is a cell of its own: ##(markdown) text (contiguous lines with no blank line between them merge into one cell) or a ##|(markdown) block, with the body starting on the next line and the |## closer at the opener's column. Attached markdown, #(markdown) text or a #|(markdown) … |# block, belongs to the statement below it and renders with that cell. Keep the parentheses: ##| markdown reads its prose as ordinary tags, and ##|markdown draws a malformed-route warning. No body line starts with |##, and a blank line follows the closer. A ## Heading line is model tags, not prose: write a heading inside a ##|(markdown) block.run:, with nothing between. A #" directly above the run: is its caption; # bar_chart, # label="..." and the other render tags go in the same block. Attached #(markdown) goes above the #" caption when both are present, and renders as a header above the result.given: uses NAME :: filter<T> is f'', bound with ~, declared before first use. Put ##! experimental.givens at the top of the file.##(markdown), never #(markdown) or #". Both belong to the statement below them, and at the end of a file there is none, so Malloy refuses a #" and the lint reports a #(markdown) as an error. An import or an export takes no annotation either, so prose above one is ##|(markdown).Cells come from the file's own notes and statements, in file order (imported files add none):
| In the file | Cell |
|---|---|
##! lines, ## artifact, and every " note above the tag | the header: no cell |
##(markdown) lines (contiguous) or a `## | (markdown)` block, after the tag |
#(markdown) or a `# | (markdown)block above arun:, source:, query:, given:ortype:` |
run: with its contiguous # tag block, including run: <named query> | one query cell |
import, source:, query:, given:, export { … }, type: | one definition cell per statement |
a non-" ## note after the tag (## title=…) | not a cell |
The unnamed " notes above ## artifact are the notebook's description. Definition cells render folded; only query cells run. Earlier spellings are still read: ##", ##|", ##(text) and ##|(text) notes below the tag are markdown cells, like (markdown). Write (markdown).
Compile the file with /compile, at the path it will have and with "scope": "file". A file under notebooks/ also gets the notebook lint: a file that would not open (a statement above the tag, an ## artifact tag that does not parse, a prose line the reader cannot place) comes back as an error problem naming the line and the fix, and the package warnings carry the same finding after a reload. Read those before you call the notebook done, then open it and look.
A notebook file compiles with all its imports in scope, so it can import several .malloy models, and a single cell can reference, and join, sources from different imported files. Import each model you need at the top; no "re-export" wrapper model is required.
When the package root holds an index.malloy, cells read only what it exports. A cell over a source index.malloy does not export answers 404, even when the notebook imports that source's file. A source the notebook derives from an exported one (source: mine is customers extend { ... }) still works. A cell's own source over a raw table (duckdb.table(...)) is refused. To use a source in a notebook, add it to the export { ... } in index.malloy. A package with no index.malloy and no legacy explores has no such limit.
import "flights.malloy"
import "carriers.malloy"
##(markdown) Flights joined to carriers, across two imported files.
run: flights extend {
join_one: carriers on carrier = carriers.code
} -> {
group_by: carriers.nickname
aggregate: flight_count
}Imports are file-wide: declare them at the top, before the cells that use them. A query cell runs as a restricted query against the already-compiled file, so an import inside a run: is rejected (file imports are not permitted in a restricted query).
Notebooks must NOT contain findings about current data values. Data refreshes will make these stale. Use markdown for framing questions and structural narrative, not for stating results.
##(markdown) WRONG: will become stale when data refreshes. Revenue spiked 23% in March.
##(markdown) RIGHT: frames the question and lets the query answer it. How is revenue trending?One notebook with all three prose forms: floating markdown cells, attached markdown headers, and a #" caption.
##! experimental.givens
##" One category at a time: how it sells across the year and which brands carry it.
## artifact { kind=notebook title="Category review" }
import { order_items, products } from "../storefront.malloy"
##|(markdown)
## Category review
Pick a **Category** in the controls above and every chart below re-runs for it.
Leave the control empty to read the whole catalog.
|##
#(description="Narrow to one product category")
# label="Category" control=select suggest { source=products dimension=category }
given: CATEGORY :: filter<string> is f''
##(markdown) How is revenue trending for the selected category?
#(markdown) ### Revenue by month
#" Revenue by month for the selected category
# line_chart
# label="Revenue by month"
run: order_items -> sales_by_month + { where: category ~ $CATEGORY }
##(markdown) Which brands are behind those numbers?
#" The eight brands with the most revenue in the selected category
# bar_chart
# label="Top brands"
run: order_items -> top_brands + { where: category ~ $CATEGORY }
##(markdown) Last, the best-selling products, defined once as a named query and then run.
query: top_products_in_category is order_items -> top_products + { where: category ~ $CATEGORY }
#(markdown) ### Best sellers
run: top_products_in_categoryThe ##|(markdown) block and each ##(markdown) line are floating markdown cells. The two #(markdown) lines are attached: each renders as a header with the run: below it, and on the first the header sits above the #" caption. The second run: has only a caption. The given: and the query: are definition cells, and each run: is a query cell. The header ends at ## artifact.
given:)Interactive parameters are common and important. Add them to most notebooks. Use given:. Never add a #(filter) annotation, even if the model you are extending already has some: it is deprecated and the notebook does not render it (see below).
A notebook's parameter surface comes from the given: declarations the file declares or imports. Publisher's notebook UI renders a Filters panel above the notebook: declared givens become parameter inputs, the values a user sets are forwarded to Malloy's runtime, and every query cell re-executes with those values applied. A given: is read by the cells below it, so declare it before the first cell that uses it.
The widget for each parameter follows the given's declared Malloy type (string, string[], number, boolean, date/timestamp, filter<T>); see docs/givens.md for the full type table. A #(description="...") annotation on the given renders as helper text under its input. It draws a cosmetic malformed-route warning that you can ignore; see docs/givens.md § Annotations. A control tag (control=select suggest { source=… dimension=… }) goes on the given: as shown in the complete notebook above.
malloy-model § Access Control covers the syntax and the #(authorize)/#(access_filter) gating story built on top of givens.
#(filter) annotations#(filter) is deprecated, and the notebook no longer renders controls for it. A model that uses #(filter) is not filterable from a notebook, and a cell whose source has a required #(filter) fails, because nothing in the notebook can supply the value. Never add a #(filter) annotation. To make such a model filterable, migrate it to givens: malloy-model § Legacy: reading an existing #(filter) model has the mapping, including required.
Build a story. Each query should reveal something that motivates the next query. Start broad, then drill into what's interesting. Frame questions in markdown, let queries answer them.
Pattern: Question, Query, Next Question, Drill
##(markdown) How is revenue trending?
# line_chart
run: orders -> { group_by: order_month; aggregate: revenue }
##(markdown) What's driving the biggest changes?
# bar_chart
run: orders -> { group_by: category; aggregate: revenue; order_by: revenue desc; limit: 10 }
##(markdown) How does the top category break down?
run: orders -> { aggregate: order_count, avg_order_value; where: category = 'Electronics' }When to use other styles:
malloy-dashboards skill) rather than a notebook.summary, by_month, by_category in sequence.To add limit, where, or other options to an existing view, use +:
run: source -> my_view + { limit: 15 }
run: source -> my_view + { where: status = 'active', limit: 10 }##! experimental.givens
##" [One-line description of the notebook.]
##| artifact { kind=notebook title="[Title]"
tiles=[
intro { kind=text },
"main_source_tiles -> broad_tile",
"main_source_tiles -> drill_tile"
]
}
|##
import "model.malloy"
##|(markdown) intro
[Framing question: what are we trying to understand?]
|##
source: main_source_tiles is main_source extend {
view: broad_tile is [broad view]
view: drill_tile is [drill view]
}Define each listed view on the _tiles extension (thin wrappers over the modelled views), and compile with "scope": "file".
A person can edit a notebooks/*.malloy notebook in the Console (an Edit button; New on the
package page starts one). A layout notebook is edited in place: tiles are reordered, added and
removed, text blocks and the tag are rewritten, and everything else in the file survives byte for
byte. A cell notebook opens converted and unsaved, and Save writes the conversion: each run:
becomes a view: on a <source>_tiles extension appended to the file (a query: used by exactly
one run is folded into its view), each prose note becomes a ##|(markdown) text_N block, and
definitions, imports, givens and comments stay where they were. The first Save asks before it
rewrites the file ("Convert this notebook?"); Cancel writes nothing, and once saved the builder
cannot undo the conversion, so the file's history in its repository is the way back. Write a cell
notebook so it converts:
run: is <source> -> <view or query body> with a named source. An inline extend before
the arrow, a source that is not a name, or a refinement (q + { … }) of a multi-stage query is
refused, and so is a run that resolves through more than ten named queries.# bar_chart { size=spark }) is kept, and the
Viz type picker is disabled for that tile with the reason shown.## artifact tag, a statement no
cell can hold, or a tag value Malloy cannot read, such as a malformed date literal
(@2024-13-01).#(authorize) or #(access_filter) gate outside prose is
refused with a 400. Put gates in a model file the notebook imports.Viz type choices are From the view, Table, Line, Bar, Big value, Scatter, Shape map and Segment map. Every choice is listed; one the view cannot render is disabled with its reason beside it.
.malloynb filesA .malloynb notebook (cells delimited by >>>markdown and >>>malloy) is a deprecated format. Publisher keeps read-only support so existing notebooks still open and run, and the bundled examples no longer ship one. Do not create a new .malloynb. To give a story a new home, write a .malloy notebook as above. Two things to know when maintaining an existing one:
.malloynb files are NOT shown in the IDE linter, and the notebook lint above does not cover them. You only see errors when cells are executed, so test queries in the model first.run: cell.| Mistake | Fix |
|---|---|
view_name { limit: 10 } | Use +: view_name + { limit: 10 } |
# currency on non-money | Only use # currency for monetary values |
A statement or a # tag above ## artifact | Only ##! flags, // comments and unnamed " notes go in the header. Move the statement below the tag. |
## Heading for a section title | That line is model tags, not prose. Write the title inside a `## |
| `## | markdownor## |
##(markdown)text or `## | (markdown)text` (no space after the route) |
##", `## | ", ##(text)or## |
| Text on the opener line after `## | (markdown)` |
#(markdown) above an import or export | Those take no annotation. Write `## |
A # tag separated from its run: by another statement | Render tags sit directly above the run:. Move the tag. |
#(markdown) or #" as the last thing in the file | Trailing prose is ##(markdown); both need a statement below them. |
given: used before it is declared | A cell reads only the givens declared above it. Move the given: up. |
| `## | (markdown) name` block in a cell notebook |
run: in a notebook that lists tiles=[…] | Never shown. Define a view:, list source -> view in tiles, delete the run:. |
tiles=[intro { kind=text }, orders_tiles -> headline] (entry not quoted) | Every source -> view entry is a quoted string: "orders_tiles -> headline". A text entry is a bare name followed by { kind=text }. Unquoted, the tag does not parse and no tile is read. |
A bare intro in tiles for a `## | (markdown) intro` block |
colspan or break on a tile entry of a notebook | Ignored (a notebook is one column) and reported as notebook-tile-layout-ignored. Remove them. |
#(filter) {"type": "Star"} (JSON-blob form, on a dimension) | Unsupported legacy syntax, and #(filter) in any form is deprecated. Declare a given: on the model's source instead. |
| Data-specific insights in markdown | Don't write "Revenue grew 23%." Frame questions instead. Data refreshes will make findings stale. |
import inside a run: cell | Imports are file-wide, put them at the top. An in-query import is rejected: file imports are not permitted in a restricted query. |
| Cross-model join inside a single ad-hoc report cell | A skill:malloy-analysis-report cell renders against a single model, so a cross-model join there won't render. Build a published notebook (which runs against the whole file) for a cross-model join. |
##|(markdown) for the title block, ##(markdown) for each question)given: declarations (see Interactive Parameters)/compile the file before saving, then reload the package and read its warningsStep complete. Output: a notebooks/<slug>.malloy file with an ## artifact { kind=notebook tiles=[…] } tag.
© malloydata, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in skills/malloy-notebooks of malloydata/publisher.
Open the folder on GitHubat commit b9a1a19
Malloy Notebooks next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Malloy Notebooks this skillmalloydata/publisher | 116 | — | ~6k | Automated safety check: Pass | MIT | |
| Jupyter Notebookmicrosoft/ai-agents-for-beginners | 77k | — | ~1.1k | Automated safety check: Pass | MIT | |
| Jupyter Notebookmicrosoft/ai-agents-for-beginners | 77k | — | ~1.2k | Automated safety check: Warn | MIT | |
| Jupyter Notebookmicrosoft/ai-agents-for-beginners | 77k | — | ~1.4k | Automated safety check: Pass | MIT | |
| Jupyter Notebookmicrosoft/ai-agents-for-beginners | 77k | 8 repos | ~1k | Automated safety check: Pass | Apache-2.0 | |
| Jupyter Notebookmicrosoft/ai-agents-for-beginners | 77k | — | ~1.3k | Automated safety check: Pass | MIT |
microsoft/ai-agents-for-beginners
ใช้เมื่อผู้ใช้ร้องขอให้สร้าง จัดโครงร่าง หรือแก้ไข Jupyter notebooks (.ipynb) สำหรับการทดลอง การสำรวจ หรือบทแนะนำ; ควรใช้เทมเพลตที่มาพร้อมและรันสคริปต์ช่วยเหลือ newnotebook.py…
microsoft/ai-agents-for-beginners
ប្រើនៅពេលដែលអ្នកប្រើស្នើឲ្យបង្កើត រៀបចំ (scaffold) ឬកែសម្រួល Jupyter notebooks (.ipynb) សម្រាប់សាកល្បង ស្វែងរក ឬមេរៀន; អនុសាសន៍ឲ្យប្រើទំរង់គំរូដែលភ្ជាប់មកជាមួយ និងរត់ស្គ្រីបជំនួយ newnotebook.py…
microsoft/ai-agents-for-beginners
အသုံးပြုပါသည်။ အသုံးပြုသူက စမ်းသပ်မှုများ၊ ရှာဖွေမှုများ သို့မဟုတ် သင်ခန်းစာများအတွက် Jupyter notebook (.ipynb) များကို ဖန်တီးရန်၊ အခြေခံဖွဲ့စည်းရန် သို့မဟုတ် တည်းဖြတ်ရန် တောင်းဆိုသောအခါ အသုံးပြုပါ။…
microsoft/ai-agents-for-beginners
A skill your agent uses when the user asks to create, scaffold, or edit Jupyter notebooks (.ipynb) for experiments, explorations, or tutorials; prefer the bundled templates and run the helper script…
microsoft/ai-agents-for-beginners
Se folosește atunci când utilizatorul solicită crearea, structurarea sau editarea notebook-urilor Jupyter (.ipynb) pentru experimente, explorări sau tutoriale; se recomandă utilizarea șabloanelor…
microsoft/ai-agents-for-beginners
Bruges når brugeren beder om at oprette, opsætte eller redigere Jupyter-notebooks (.ipynb) til eksperimenter, udforskninger eller vejledninger; foretræk de medfølgende skabeloner og kør…
malloydata/publisher
Score one analytical answer against a verified golden, and score which of the entities the golden depends on retrieval delivered to the answerer.
malloydata/publisher
Fix a CRITICAL Trivy finding that is failing CI in this repo (a vulnerability, misconfiguration, or secret from security-scan.yml or image-scan.yml), or add, review, or retire an entry in…
malloydata/publisher
Turn a list of questions into an eval set, whatever shape it arrived in: a JSONL a customer sent, a CSV, a spreadsheet export, a markdown doc, an email thread, or a pull from production logs.
malloydata/publisher
Conduct a local Publisher evaluation loop in five steps: scrape/run, eval, diagnose, improve, checkpoint.
malloydata/publisher
Make the smallest safe Malloy model edit that closes a diagnosed model-owned gap, with a probe receipt for every factual claim.
malloydata/publisher
Decide whether ONE answer matches its golden, and say whether you believe the golden.
Create Malloy notebooks (a .malloy file under notebooks/, written as a one-column layout of tiles) for interactive data stories and reports. Malloy Notebooks is an agent skill from malloydata/publisher.malloy file under notebooks/, written as a one-column layout of tiles) for interactive data stories and reports.
Malloy Notebooks fits situations like: user asks to create a notebook; make a notebook; needs to build reports/visualizations that read top to bottom.
Run `npx skills add malloydata/publisher --skill malloy-notebooks -a claude-code`. Or copy the skill folder (skills/malloy-notebooks in malloydata/publisher) into .claude/skills/malloy-notebooks in your project. Claude Code loads it when a task matches its description.
Run `npx skills add malloydata/publisher --skill malloy-notebooks -a codex`. Or copy the skill folder (skills/malloy-notebooks in malloydata/publisher) into .agents/skills/malloy-notebooks in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add malloydata/publisher --skill malloy-notebooks -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/malloy-notebooks, .gemini/skills/malloy-notebooks, .github/skills/malloy-notebooks and .opencode/skills/malloy-notebooks in your project.
SKILL.md names no scripts, command-line tools or credentials: Malloy Notebooks is instructions for the agent only.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Malloy Notebooks is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 6k tokens (SKILL.md is roughly 24k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Malloy Notebooks: Jupyter Notebook (microsoft/ai-agents-for-beginners, 77k stars), Jupyter Notebook (microsoft/ai-agents-for-beginners, 77k stars), Jupyter Notebook (microsoft/ai-agents-for-beginners, 77k stars) and Jupyter Notebook (microsoft/ai-agents-for-beginners, 77k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
malloydata (a GitHub organization) maintains it in malloydata/publisher, which has 116 GitHub stars. The repository holds 29 skills in this directory. The repository was last updated on October 9, 2026.
Source: malloydata/publisher on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.