agentleFS
german-borisevichgerman-borisevich/apache-zeppelin-mcp/skills/notebook/SKILL.md

notebook

Skill12 starsChanged 30 days agoMITView on GitHub

Work with Zeppelin notebooks — create notebooks, add paragraphs, configure charts, and manage notebook content via MCP tools. Use this skill whenever the user asks to create a notebook, add paragraphs or cells to a notebook, configure or change chart types, set up visualizations, or any task involving Zeppelin notebook manipulation. Also trigger when the user references a specific notebook by name or ID and wants changes made to it, or asks to fix/refactor existing notebook code.

  • Reads credentials

4 other projects use a version of this.

Adopted by

Most recently taken up by

  • Other versions4 projects use a version of this.

    Word for word · 0

    None found.

    Edited · 0

    None found.

    Wrote their own version · 4

    1. catcatcatstudio/cat-skills★ 3same name
    2. qkitzero/kage-bunshin★ 1same name
    3. stackql/stackql-skills★ 0same name
    4. theaayushstha1/agentic-skills★ 0same name

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repositoryOne other file it gives its agents.

The file

Show its rules and text

We split this skill into the rules it gives an agent

25 rules. 0 are common, 4 are distinctive, and 21 are very specific to this project.

  • 0

    Common

    Most of the 4 edited versions we read keep these.

  • 4

    Distinctive

    This author's own choices. Worth a look.

  • 21

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  • could be automatic: a setting could enforce it
  1. Distinctive:

    Follow the steps below in order.

    line 11
  2. Very specific:

    Before discovering anything, check whether this artifact is already documented.

    line 15
  3. Very specific:

    If the user provides a notebook ID → use get_notebook directly

    line 52
  4. Very specific:

    If the user provides a name or partial name → use list_notebooks with a name filter

    line 53
  5. Very specific:

    If creating a new notebook → confirm the path follows the folder conventions already visible on the server (e.g.

    line 54
  6. Very specific:

    Use list_notebooks to discover existing structure before creating

    line 55
  7. Very specific:

    Read existing notebook paragraphs with get_notebook to understand the structure, data flow, and coding patterns already in use.

    line 59
  8. Distinctive:

    When the user does ask for analysis/conclusion paragraphs: keep them clear and concise — short bullets, key numbers with their source …

    line 80
  9. Very specific:

    Every Zeppelin paragraph starts with an interpreter prefix.

    line 84
  10. Distinctive:

    Follow the connection pattern already used in the notebook.

    line 88
  11. Very specific:

    Use z.show(df) to output DataFrames for Zeppelin's built-in charts

    line 103
  12. Very specific:

    Same query, different chart: use clone_paragraph — it copies code, title, and chart config directly below the original, so you only change …

    line 113
  13. Very specific:

    After running a paragraph that outputs table data, use update_paragraph_config to set the chart and the presentation flags from "Finalize …

    line 117
  14. Very specific:

    Use {"name": "col"} only in keys/groups/values — never include index or aggr fields.

    line 137
  15. Very specific:

    Always verify column names against actual executed output (get_paragraph) before setting chart config.

    line 138
  16. Very specific:

    Use get_paragraph_forms to discover available form parameters before running

    line 142
  17. Very specific:

    Use update_paragraph_forms to change values without re-executing

    line 144
  18. Very specific:

    Every paragraph the assistant adds or edits MUST be finalized with both of the following set via update_paragraph_config before the task is …

    line 158
  19. Very specific:

    When finalizing several paragraphs, use batch_update_paragraph_config — one call with a config object per paragraph (same shape as above) …

    line 174
  20. Very specific:

    After the task succeeds, persist what was learned (protocol: $WIKI_DOCS_PATH/docs/artifact_cache_protocol.md):

    line 180
  21. Very specific:

    If the hook reports a rebase conflict in _index.md, take the remote version and re-add this artifact's bullet — never hand-merge prose.

    line 192
  22. Very specific:

    If $WIKI_DOCS_PATH is unset/absent, skip silently — do not fail the task.

    line 195
  23. Distinctive:

    Never make direct HTTP/curl requests to Zeppelin — all interaction goes through MCP tools only

    line 204
  24. Very specific:

    Never read credential files, .env files, or connection strings from the filesystem

    line 205
  25. Very specific:

    Never modify or delete ~Backups notebooks — these are auto-created safety backups and the MCP server blocks mutations on them

    line 206

“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

You are working with Zeppelin notebooks via MCP tools. The user's request is:

$ARGUMENTS

Follow the steps below in order.

Step 0: Check the artifact doc cache

Before discovering anything, check whether this artifact is already documented. Full protocol: $WIKI_DOCS_PATH/docs/artifact_cache_protocol.md.

Cache state (resolved at invocation)

  • Docs root: !echo "${WIKI_DOCS_PATH:-unset}"
  • Sync: ![ -d "$WIKI_DOCS_PATH/.git" ] && { git -C "$WIKI_DOCS_PATH" pull --ff-only --quiet 2>/dev/null && echo synced || echo "pull failed - using local copy"; } || echo "no clone - cache off, use normal discovery"
  • Project slug (derived from cwd): !head -1 knowledge/project/data_model.md 2>/dev/null | sed 's/^# //; s/ Data Model$//'
  • Project _index.md:
!`s=$(head -1 knowledge/project/data_model.md 2>/dev/null | sed 's/^# //; s/ Data Model$//'); [ -n "$s" ] && cat "$WIKI_DOCS_PATH/$s/_index.md" 2>/dev/null || echo "(no index for slug '$s' - cold cache, or slug underivable from this cwd; resolve per protocol 1)"`
  1. Interpret the pre-resolved cache state above — it already performed the env resolution, the git pull --ff-only sync, the <project_slug> derivation, and the _index.md read; do NOT redo them. Docs root unset or "no clone" → log one warning and proceed with normal discovery (the cache is optional; never create the root directory yourself — only the SessionStart hook's clone does). Slug empty or index unreadable → resolve them manually per protocol §1 (the cwd may not be the analyst repo).
  2. Not listed (cold miss) → proceed to normal discovery; write the spec in the final step.
  3. Listed → call get_notebook_fingerprint(notebook_id, spec_path="$WIKI_DOCS_PATH/<project_slug>/notebooks/<id>.md") — the server reads the stored hashes from the spec frontmatter itself and returns match plus an exact diff; never hand-compare hash maps or re-type them into tool arguments. Then read the spec body (it is the payload, not part of the check):
    • match: true (hit) → trust the spec, skip Step 2 discovery, go to the task.
    • match: false (stale) → diff names the changed/added/removed paragraph ids; re-learn those and their dependents (cross-unit rule, protocol §5); update the spec in the final step.
    • spec_note in the response → stored hashes unreadable; treat the spec as unverified background and run normal discovery.

Step 1: Identify the notebook

  • If the user provides a notebook ID → use get_notebook directly
  • If the user provides a name or partial name → use list_notebooks with a name filter
  • If creating a new notebook → confirm the path follows the folder conventions already visible on the server (e.g. Users/{username}/{Project}/{Notebook name})
    • Use list_notebooks to discover existing structure before creating

Step 2: Understand context

Read existing notebook paragraphs with get_notebook to understand the structure, data flow, and coding patterns already in use. This is important because paragraphs share interpreter state — variables and imports from earlier paragraphs are available in later ones.

Decide how much exploration is needed:

SituationWhat to explore
Adding a paragraph similar to existing onesNotebook context is sufficient
Adding a new kind of query or metricCheck the project's query templates / reference notebooks, if the project keeps any
Creating a new notebook from scratchRead an existing notebook in the same folder/project to learn the interpreter prefix, connection pattern, and coding style

When the data schema is unknown: discover it live from a scratch paragraph (e.g. inspect the table DDL or list distinct values of a key column with a LIMIT) instead of guessing table or column names.

Step 3: Generate and add content

Markdown paragraphs: separators yes, commentary only on explicit request

Two kinds of %md paragraphs — treat them differently:

  • Section separators (a short header line that structures the notebook, e.g. %md ## Retention) — allowed and encouraged for readability.
  • Commentary — methodology descriptions, analysis narratives, findings tables, conclusion or recommendation sections — do NOT add these unless the user explicitly asks. Conclusions and methodology belong in the chat response, not in the notebook.

When the user does ask for analysis/conclusion paragraphs: keep them clear and concise — short bullets, key numbers with their source (table, date range), no filler prose or restating what the chart already shows.

Interpreter prefix

Every Zeppelin paragraph starts with an interpreter prefix. Check existing notebooks on the same server to find the correct one — e.g. %python, %sql, %jdbc(...), %md. Do not guess — using a prefix that isn't configured on the server causes HTTP 500 errors.

Code patterns

Follow the connection pattern already used in the notebook. If no pattern exists, a common shape for Python paragraphs querying a database is:

%python

import os
from sqlalchemy import create_engine
import pandas as pd

sql = "QUERY"
df = pd.read_sql(sql, create_engine(os.getenv('YOUR_CONNECTION_STRING_ENV')).connect())

(adapt the connection source to whatever the server/team already uses — an env var, a configured interpreter, or a helper module).

  • Use z.show(df) to output DataFrames for Zeppelin's built-in charts
  • For plotly (only when Zeppelin charts can't handle it — Sankey, heatmaps, violin plots): print("%html " + fig.to_html(include_plotlyjs='cdn', full_html=False))

Adding paragraphs

Set a descriptive title for each paragraph. For a single paragraph use add_paragraph; for two or more, use batch_add_paragraph — one call, paragraphs created in the given order, returns the new IDs.

Fixing existing code: for targeted changes (a line, a filter, a column, a rename) use edit_paragraph — find-and-replace that sends only the changed snippet instead of re-sending the whole paragraph, which is much faster and cheaper for long paragraphs. Read the code first with get_paragraph_code and copy old_string from that output (raw text — get_notebook/get_paragraph indent code by 2 spaces, so snippets copied from them won't match). old_string must match exactly and be unique: include a neighbouring line if it repeats, or set replace_all for renames. For several edits — in one paragraph or across many — use batch_edit_paragraph (one call; all-or-nothing per paragraph, other paragraphs still proceed). Use update_paragraph / batch_update_paragraph only for whole rewrites or when most of the paragraph changes. The MCP server automatically backs up the original content before applying any of these changes.

Same query, different chart: use clone_paragraph — it copies code, title, and chart config directly below the original, so you only change the chart config afterwards instead of re-sending the code.

Chart configuration

After running a paragraph that outputs table data, use update_paragraph_config to set the chart and the presentation flags from "Finalize paragraph config" below in a single call:

{
  "editorHide": true,
  "runOnSelectionChange": false,
  "graph": {
    "mode": "lineChart",
    "keys": [{"name": "date_column"}],
    "groups": [{"name": "segment_column"}],
    "values": [{"name": "metric_column"}]
  }
}

Supported graph.mode values: table, multiBarChart, stackedAreaChart, lineChart, pieChart, scatterChart.

Set graph.keys, graph.groups, graph.values with name only — omit index and aggr so Zeppelin auto-detects them from the result set.

Important — these cause broken charts if ignored:

  • Use {"name": "col"} only in keys/groups/values — never include index or aggr fields. The MCP server auto-fills these from paragraph output headers.
  • Always verify column names against actual executed output (get_paragraph) before setting chart config. Column names in code (e.g. SQL aliases) may differ from what Zeppelin outputs. Guessing causes "out of sync" warnings.

Dynamic forms

  • Use get_paragraph_forms to discover available form parameters before running
  • Pass params dict to run_paragraph to set form values (keys must match field names exactly)
  • Use update_paragraph_forms to change values without re-executing

Important — new paragraphs ignore pre-set forms:

  • update_paragraph_forms before a paragraph's first run is silently ignored by Zeppelin — the forms aren't registered yet. Pass params directly to run_paragraph instead, which registers forms and executes with correct values in one pass.

Running paragraphs

  • Several paragraphs in order → batch_run_paragraph (runs sequentially in the given order; stops on first error by default; each run item is {paragraph_id, params?} so cells can get different form values, with top-level params as the shared default) — use this for the "run each paragraph one-by-one" step of notebook migrations instead of N separate calls
  • Long-running query → run_paragraph_async to start without waiting, then poll get_paragraph_status
  • Stuck or runaway execution → stop_paragraph
  • Exploratory queries → always add a LIMIT so a scratch query can't scan or return unbounded data

Finalize paragraph config

Every paragraph the assistant adds or edits MUST be finalized with both of the following set via update_paragraph_config before the task is considered complete — these are not optional polish, they are part of "done":

  • editorHide: true — hides the code editor so readers see the result (chart/table), not the query. Readers who want the code can unhide it with the paragraph menu.
  • runOnSelectionChange: false — disables Zeppelin's default behavior of auto-re-running the paragraph every time a dropdown or form value changes. Heavy queries otherwise fire on every click, which wastes cluster time and can crash the server. Users re-run explicitly with the Run button.

Minimal call (paragraph without a chart — e.g. markdown or a pure table output):

{
  "editorHide": true,
  "runOnSelectionChange": false
}

For paragraphs with charts, fold these keys into the same update_paragraph_config call as graph (see the Chart configuration example above) — one round-trip, not two.

When finalizing several paragraphs, use batch_update_paragraph_config — one call with a config object per paragraph (same shape as above) instead of N update_paragraph_config calls.

Verify before writing: editorHide and runOnSelectionChange are paragraph-config keys in current Zeppelin versions, but names can shift across versions. Fetch the current config via get_paragraph and confirm the key is accepted; if update_paragraph_config returns without the key taking effect, check the paragraph's JSON and adapt (e.g. some versions nest the editor-hide flag under editorSetting).

Step 4: Update the artifact doc cache

After the task succeeds, persist what was learned (protocol: $WIKI_DOCS_PATH/docs/artifact_cache_protocol.md):

  • Cold miss → write a new spec to $WIKI_DOCS_PATH/<project_slug>/notebooks/<notebook_id>.md using the spec template (fingerprint + units via get_notebook_fingerprint; record validated:), and register it: wiki index-add <project> notebooks/<id>.md --name "…" --desc "…".
  • Stale → update the changed ## Per-unit notes / ## Architecture sections (plus dependents per the cross-unit rule), append a ## Change log entry (cap at 5 — drop the oldest), refresh validated:, and re-fetch the fingerprint into the frontmatter.
  • Do not run git commands — the plugin Stop hook commits and pushes. If the hook reports a rebase conflict in _index.md, take the remote version and re-add this artifact's bullet — never hand-merge prose. (Hook not installed — older plugin — → commit manually per protocol §6.)
  • If $WIKI_DOCS_PATH is unset/absent, skip silently — do not fail the task.

Boundaries

What MCP can do: read/search notebooks and paragraphs; add/update/delete/move paragraphs (single or batch_* variants); edit paragraph code in place via find-and-replace (edit_paragraph, batch_edit_paragraph); clone paragraphs and notebooks; create/export/import notebooks; modify paragraph config (charts, single or batch); run paragraphs (sync, batch, or async with status polling) and stop them; update form values; read/update permissions.

What MCP cannot do: modify or delete ~Backups notebooks (protected by the MCP server).

Hard rules — these exist because violations have caused real problems:

  • Never make direct HTTP/curl requests to Zeppelin — all interaction goes through MCP tools only
  • Never read credential files, .env files, or connection strings from the filesystem
  • Never modify or delete ~Backups notebooks — these are auto-created safety backups and the MCP server blocks mutations on them

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.