SKILL.md
Deepnote Notebook Editor
Goal
Edit Deepnote .ipynb notebooks so that changes are visible when the file is re-imported into Deepnote.
When to use
- Editing cells in a Deepnote-exported
.ipynbfile - Adding new SQL or code cells to a Deepnote notebook
- Modifying queries or markdown in Deepnote notebooks
When not to use
- Standard Jupyter notebooks (no
deepnote_sourcein metadata) - Notebooks created in JupyterLab, VS Code, or Colab
The Problem
Deepnote notebooks look like standard .ipynb files but store a duplicate of each cell's content in metadata.deepnotesource. Deepnote reads from deepnotesource on import, NOT from the standard source field. If you only update source (which NotebookEdit does), Deepnote shows the old content.
Cell Types
deepnotecelltype |
ipynb cell_type |
deepnote_source contains |
source contains |
|---|---|---|---|
markdown |
markdown |
Markdown text | Same markdown text |
text-cell-p |
markdown |
Markdown text | Same markdown text |
code |
code |
Python code | Same Python code |
sql |
code |
Raw SQL only | Python wrapper (dntk.executesql(...)) |
SQL cells are critical — deepnote_source has just the SQL, while source has the auto-generated Python wrapper.
SQL Cell Metadata Fields
{
"deepnote_cell_type": "sql",
"deepnote_variable_name": "df_result",
"sql_integration_id": "uuid-of-database-integration",
"deepnote_source": "SELECT * FROM table"
}
SQL Cell Source Format
The Python wrapper in source follows this pattern:
if '_dntk' in globals():
_dntk.dataframe_utils.configure_dataframe_formatter('{}')
else:
_deepnote_current_table_attrs = '{}'
df_result = _dntk.execute_sql(
'SELECT * FROM table',
'SQL_INTEGRATION_UUID',
audit_sql_comment='',
sql_cache_mode='cache_disabled',
return_variable_type='dataframe'
)
df_result
Template variables use Jinja-style {{VARIABLE|safe}} syntax (double braces).
Default Workflow
1) Read the notebook
Identify cell types and which cells need changes. Check for deepnote_source in metadata to confirm it is a Deepnote notebook.
2) Edit cells with NotebookEdit
Update source fields as usual.
3) Sync deepnote_source (mandatory)
Run a Python script to update deepnote_source for all modified/inserted cells:
python3 << 'PYEOF'
import json
NOTEBOOK = '/path/to/notebook.ipynb'
with open(NOTEBOOK) as f:
nb = json.load(f)
# For markdown/code cells — sync deepnote_source from source
cell = nb['cells'][CELL_INDEX]
cell['metadata']['deepnote_source'] = ''.join(cell['source'])
# For SQL cells — write the raw SQL directly (NOT the Python wrapper)
cell = nb['cells'][CELL_INDEX]
cell['metadata']['deepnote_source'] = """YOUR RAW SQL HERE"""
with open(NOTEBOOK, 'w') as f:
json.dump(nb, f, indent=1, ensure_ascii=False)
PYEOF
4) Adding new SQL cells
After inserting with NotebookEdit, set Deepnote metadata:
cell = nb['cells'][INDEX]
cell['metadata']['deepnote_cell_type'] = 'sql'
cell['metadata']['deepnote_variable_name'] = 'df_result'
cell['metadata']['sql_integration_id'] = 'COPY_UUID_FROM_EXISTING_CELL'
cell['metadata']['deepnote_source'] = """SELECT ..."""
5) Verify
Grep for any stale content to confirm all references were updated.
Validation checklist
- Every modified cell has
deepnote_sourceupdated - SQL cells have raw SQL in
deepnote_source(not the Python wrapper) - New SQL cells have
deepnotecelltype,deepnotevariablename, andsqlintegrationid -
grepconfirms no stale content remains in the file
Examples
Example 1: Update a SQL query
Input: User asks to change a SQL query in a Deepnote notebook. Output:
NotebookEditupdates thesource(Python wrapper with new SQL)- Python script sets
deepnote_sourceto the new raw SQL - Grep verifies old query text is gone
Example 2: Add a new chart section
Input: User asks to add a new SQL + chart cell pair. Output:
NotebookEditinserts a markdown cell, a code cell (SQL wrapper), and a code cell (chart)- Python script sets
deepnotecelltype: sql, copiessqlintegrationidfrom an existing cell, setsdeepnotevariablename, and writes raw SQL todeepnote_source - Python script syncs
deepnote_sourcefor the markdown and chart cells from theirsource