bigquery-sql
BigQuery-specific SQL patterns: UNNEST for array expansion, STRUCT, ARRAY_AGG,…
Load before you edit or run notebook cells in chat. Covers the notebook tools, the sp SDK, governed queries, files, and charts.
$ npx -y skills add signalpilot-labs/signalpilot --skill notebook --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/notebookContext preview
The summary Claude sees to decide when to auto-load this skill.
Load before you edit or run notebook cells in chat. Covers the notebook tools, the sp SDK, governed queries, files, and charts.
name: notebook description: "Load before you edit or run notebook cells in chat. Covers the notebook tools, the sp SDK, governed queries, files, and charts." type: skill
The chat gives you one analysis notebook and optional named notebooks. Use them to run queries, compute results, and save files. Evidence for an answer comes from the analysis notebook.
1. Call `start_analysis_notebook` only when you will run cells. A notebook that you start and do not use rejects the whole run. 2. Pass `notebook: "scratch"` (short, lowercase) to start a separate notebook for drafting. Each name has its own kernel and `session_id`. 3. Use the `session_id` from the tool result with every notebook tool. 4. Make the first visible cell a title: `sp.md("# <title of the analysis>")`. Write a short title from the user's request, not the prompt text. Update it when the question changes. A markdown cell does not need `sp.init()` and must not import `signalpilot` again.
The notebook starts with two hidden cells and one empty visible cell. Never edit or remove the hidden cells. Put the title in the empty cell.
`SP_CHAT_SCRATCH_DIRECTORY` and `SP_CHAT_ARTIFACTS_DIRECTORY`, and EXPORTS `Path`, `runtime_context`, `sp`.
Redefining any of those seven names raises `MultipleDefinitionError`. That includes `import os`, even though `os` is not exported to your cells: it is defined, so you cannot define it again, and it is not exported, so you cannot use it. Import nothing that is already defined.
**Nothing else is defined. `plt` is not.** `sp.init()` has already applied the house theme to matplotlib's `rcParams`, including `savefig.dpi` and `savefig.bbox`, but the module itself is not imported. Put `import matplotlib.pyplot as plt` in one cell of your own before the first chart cell.
`sp.init()` returns None. There is no `signalpilot.db` export. Use `db` and `sp` from these cells. Do not import `signalpilot` again.
Write every cell of the analysis before running any of them. Fixing cells until they stop erroring produces code that runs and answers the wrong question.
Settle these four facts first, from the dbt project and `sp.describe_table`, not by trial:
1. The connection's SQL dialect. SQL Server takes `YEAR(x)`, `select top 10`, and three-part `Database.schema.table` names, which the governed parser requires. 2. The definition of every column you will name, read from its model SQL. A column that sums cleanly can still mean something other than its name. 3. Which names must be public because a later cell reads them, and which are `_`-prefixed scratch private to one cell. 4. The grain of each mart, so you know whether your `GROUP BY` fans out.
summary of what the code cell below it does. Give every code cell its own summary, including the first one.
Each step is therefore two cells: the summary cell, then the code cell.
first, so the notebook reads in the correct order.
`sp.md("Join invoice lines to the account dimension for one row per account per month")`. Do not write `sp.md("Run a query")`.
text cell defines no name, so it cannot cause `MultipleDefinitionError`.
`MultipleDefinitionError`. Fix all conflicting cells in one edit batch.
rejects the WHOLE batch if another cell reads it. Decide before you write: a value the next cell needs gets a public name; a value used only inside this cell gets one underscore. `_fig`, `_ax` and loop variables are always underscore. After a `PrivateVariableCrossCellReference`, promote the name in the defining cell and resend both cells in one batch.
Aggregate in SQL; use Python for ratios and formatting only. Keep a cell under 20 lines, define at most one public name in it, and end it in one bare expression or one `print`. A cell that runs three queries and twenty pandas statements fails as a unit, and its error output is truncated.
many steps into one cell is not.
again.
| Tool | Use | |---|---| | `edit_notebook` | `edits`: `add_cell` (code), `update_cell` (cell_id, code), `delete_cell` (cell_id). One batch per change set. | | `run_cells` | Runs the given `cell_ids` (all cells when omitted) and blocks. Returns outputs, console text, and errors per cell. Set `timeout` for long queries. | | `save_data_snapshot` | Saves a compact aggregate for an external deliverable. Do not dump raw tables. | | `start_notebook_session` | Opens a `.py` notebook file you wrote with `Write` and returns its `session_id`. |
Read every `run_cells` result. A cell with `status: "failed"` has an `error.message`. Fix the cell and run it again.
| Call | Result | |---|---| | `sp.connections()` | Names of the connections you may query. | | `db.query_df(sql, row_limit=1000)` | **The default.** A typed DataFrame: numeric and date columns are already converted.
Repo: signalpilot-labs/signalpilot
BigQuery-specific SQL patterns: UNNEST for array expansion, STRUCT, ARRAY_AGG,…
Load when dbt run or dbt parse fails. Covers YML duplicate patches, ref errors, passthrough…
Populate the knowledge base from dbt project research. Proposes entries across all 6…
Load when task involves dbt snapshots, SCD Type 2, or tracking data changes over time. Covers…
Load when task involves adding, writing, or fixing dbt unit tests. Covers unit_tests YAML…
Load when task involves dbt model versioning, creating v2 of a model, or backward-compatible…