# Chalk Notebooks
source: https://docs.chalk.ai/docs/chalk-notebooks

## Mix and match SQL, Python, and Query cells to explore, analyze and productionize features.

Chalk Notebooks build on the notebook format you already know. You'll be on familiar ground if
you've spent time in Jupyter or a similar environment: the interface is made up of cells. Chalk
extends that with additional cell types, including cells that run Chalk queries natively, so you
can explore your data and create new features in one place. Those cells run on
Chalk Compute, which runs sandboxed compute inside your own cloud, so
notebook code executes on infrastructure you own and control rather than in a Chalk-hosted
environment. Any data source you have already configured under Integrations
is natively queryable from a notebook — no re-configuration and no new credentials.

### Cell types

Pick a type when you add a cell.

- Python: runs Python, the same as any notebook cell you have used before.
- SQL: runs SQL against any of the data sources you have configured under Integrations.
- Text: prose, written as plain text or Markdown. A Markdown cell can interpolate live values
from the notebook session, which makes it a runnable cell; see
Cell outputs.
- Input: an interactive parameter bound to a Python variable. The available input types are
Text, Number, Checkbox, Toggle, Date, Dropdown, Multiselect, and Table.
- Section: a title cell, for grouping a notebook into named parts.
- Single value: displays a single value computed anywhere in the notebook, rendered
prominently.
- Table: displays an existing dataframe as a full-width, browsable table — a variable an
earlier cell produced, a Chalk dataset, or a table in a configured SQL datasource. Display-only:
it does not run and does not define a variable.
- Online query: runs a Chalk online query directly from the dashboard. Supply the query's
inputs in the Inputs section as feature-name and value pairs, one row at a time with
Add input, and list the features you want back in the required Outputs field as a
comma-separated list. The cell also has a collapsible Advanced panel, along with
resource-group and branch selectors and a Plan button in its header.
- Offline query: runs a Chalk offline query directly from the dashboard. Name the resulting
dataset in Dataset Name, then supply the query's inputs: pick a mode from the Inputs as
dropdown — SQL query takes a query that returns one row per requested entity, with columns
named for the input features. Set INPUT TIME, then choose the features you want back under
Outputs, marking each Required or Recompute. Run Asynchronously sends the query
through the offline query job queue, so the work can be split across shards and workers
configured under Async Resources. Like the Online query cell, it has resource-group and
branch selectors, a Plan button, and an Advanced panel.

### Cell outputs

Every cell that computes something leaves its result behind for the rest of the notebook to use.
Output renders directly beneath the cell that produced it, and the value is bound to a name that
later cells can read.

### Result variables and the variable explorer

All cells share one Python session, so a name defined in one cell stays defined for the cells
after it. Python cells bind names the ordinary way, by assignment. SQL, Online query, Offline
query, and Input cells bind their output to a result variable instead. You can rename
that variable, and it is worth naming it well early, because downstream cells refer to it by
name. The variable explorer lists what the session currently holds, with a preview of each value.

### Tables and dataframes

Tabular results render as a browsable table rather than a truncated repr. For SQL and query cell
results you can page through rows, aggregate columns, and download the result from the cell's
output. A notebook can hold dataframes of several kinds — pandas, polars, pyarrow, and Chalk's
own DataFrame — and each displays the same way.

### Template interpolation in Markdown

Two cell types exist mostly to consume other cells' output. A Single value cell renders one
number or string computed anywhere in the notebook. Markdown cells go further: every
{{ expression }} site in the prose is evaluated against the same Python session the code cells
use and rendered in place, so narrative text stays consistent with the data beside it.

There is no separate templating language. What sits between the braces is ordinary Python — a
variable, an attribute, an index, a call — and result variables are in scope under their own names,
so {{ my_sql_result["col"][0] }} works with no namespace prefix. Three forms cover the syntax:

- {{ expression }} renders the value.
- {{ expression:format_spec }} applies a Python format spec, exactly like an f-string:
{{ ratio:.1% }} renders 12.3%, and {{ total:,.2f }} renders 1,234,567.89. Only the
first colon at the top level of the site splits expression from format spec, so colons
inside brackets or string literals — a slice like {{ xs[0:2] }}, for instance — are left
alone.
- \{{ escapes a literal {{, for prose that needs double braces verbatim.

Scalars render inline, dataframes render as a bounded preview table, and an expression that raises
renders an inline error marker at its own site while the rest of the document still renders. A site
in a cell that has not run yet shows its source as inline code. Resolved values are saved with the
cell's output, so a shared notebook renders its interpolated values without a live session — you
only need one to refresh them. Two limits are worth knowing: only Markdown cells render resolved
values, since plain Text cells show their source verbatim, and chart objects are not rendered at a
template site, so display those from a Python cell.

### Chaining cells

Because cell results can be referenced by name, work can be split across cells instead of piling into one. A SQL cell
pulls a dataset, a Python cell reads that result by name and reshapes it, and a Single
value cell surfaces one number from the reshaped frame. Each step stays independently runnable
and independently readable.

Chalk query cells chain the same way. The output of an Online query or Offline query cell
is a named value like any other, so a downstream Python cell can transform it, join it against
another result, or plot it without re-running the query. SQL cells chain too: a SQL cell can
target a datasource configured under Integrations, or run against a
dataframe an earlier cell produced, which lets a long query be broken into readable stages.

You never declare these connections. Chalk infers each cell's dependencies from what that cell
reads and what it writes, and those inferred dependencies drive the notebook's
run modes and its tracking of which cells have gone stale.

Markdown cells with template sites take part as pure consumers. The names their expressions
read become dependencies on the cells that produce those names, so Auto mode re-renders prose when
its upstream cells re-run, Cell + upstream on a Markdown cell runs the producers it reads from
before rendering, and editing an upstream cell marks the prose stale like any other dependent. The
expressions never bind names, so nothing can depend on a Markdown cell in turn.

### The notebook toolbar

Every notebook's own controls sit in one bar at the top right, above the cells. The rest of this
page walks that bar from left to right.

The Chalk notebook toolbar: App, an error count, Run all with its run-mode dropdown, comments, dependencies, share, settings, and history

### App view

App switches the notebook into app view, a dashboard canvas that presents results without the
code behind them. It is a view toggle, not a publish step: the button flips to Notebook, which
switches you back, and the view is recorded in the URL, so a refresh or a pasted link reopens it.

Nothing reaches the canvas on its own. Every cell carries an Add to app dashboard button in its
action rail, and clicking it places that cell on the app dashboard; the same button then offers
Remove from app dashboard to take it back off. The Add cell dropdown in app view is the
second path, and it also offers Add all cells — a notebook with no placed cells opens as an
empty canvas.

Placed cells render their results only — source code is never shown. Input cells stay interactive,
so the controls that drive the notebook drive the app too. Section cells render as titles, and
Single value cells render as metrics. You position widgets by dragging and resizing them, and the
layout persists.

### Error count

The warning badge shows how many cells have errored. Click it to jump to the cell with the error.

### Running cells and shortcuts

How many cells a run covers is a setting. Pick a Run mode from the dropdown next to Run
all, and every subsequent run obeys it until you change it. The mode is expressed in terms of the
dependencies described above: "upstream" means the cells the selected cell reads from, and
"downstream" means the cells that read from it.

Auto — runs the selected cell and everything downstream of it, and refreshes any cells that
had gone stale. Auto is the default, and a run in Auto never leaves a cell stale. In every other
mode, a cell goes stale when something it depends on runs more recently than it did.

Cell + upstream — runs the cells the selected cell depends on, then the selected cell.

Cell only — runs the selected cell and nothing else.

Cell + downstream — runs the selected cell, then the cells that depend on it.

A handful of shortcuts are worth knowing. The Esc-prefixed ones are command-mode shortcuts:
pressing Esc leaves the cell's editor while keeping the cell selected, so the keys that follow
act on the cell as a whole rather than on its text. Finish a sequence within two seconds, or it
resets.

| Shortcut                | Action                                                                     |
| ----------------------- | -------------------------------------------------------------------------- |
| `Shift + Enter`         | Run the selected cell using the active run mode, then select the next cell |
| `Cmd + Enter`           | Run the selected cell using the active run mode and stay on it             |
| `Cmd + Click`           | Select multiple cells                                                      |
| `Esc` then `A`          | Insert a Python cell above the selected cell                               |
| `Esc` then `B`          | Insert a Python cell below the selected cell                               |
| `Esc` then `D`, `D`     | Delete the selected cell                                                   |
| `Esc` then `Cmd + Up`   | Move the selected cell up one position in the notebook                     |
| `Esc` then `Cmd + Down` | Move the selected cell down one position in the notebook                   |
| `Esc` then `F`, `F`     | Open the selected cell full screen                                         |
| `Esc` then `F`, `S`     | Format the selected SQL cell                                               |

Two whole-notebook actions sit in the same place. Run all runs the notebook end to end, and
Run all without cached results does the same with caching bypassed, so every SQL cell executes
against its datasource.

### Comments

Comments come at two levels. The speech-bubble button in the toolbar opens the notebook's comments,
and every cell carries its own comment button, which comments on that cell alone — so a notebook is
something several people can work on together.

### Dependencies

The dependencies button opens a Dependencies drawer on the right-hand side of the notebook —
"Variable data-flow between cells, analyzed by the kernel." It draws the notebook top to bottom as
an interactive graph. The drawer is resizable, and it is recorded in the URL, so a refresh or a
pasted link reopens it.

Most nodes are cells, drawn as a miniature preview of the source with the cell's name, how long
its last run took, and a pill for each variable the cell outputs. A ring around a node marks it as
selected, succeeded, or errored. Input cells render their live control inside the node. A SQL
cell's datasource appears as its own node upstream of the cell, labeled with the datasource name.
Edges are data flow, labeled with the actual variable names crossing them.

Selection syncs in both directions: selecting a cell pans the graph, and clicking a node reveals
that cell in the notebook. A minimap, zoom to fit, and zoom to selection handle navigation in a
large notebook.

The graph comes from static analysis of your Python source, run inside the kernel process. Cells
are not executed to build it. Only module-level names are considered, so a name bound inside a
function body or a class body does not become a dependency.

Two limits are worth knowing. The drawer needs a running notebook runtime: without one you see the
cells but no edges, and the empty state says so — "Add runnable cells, then start the notebook
runtime so the kernel can analyze their variable dependencies." And the graph is built from the
saved document, so an edit you have just typed is not reflected until autosave picks it up.

### Sharing a notebook

The share button creates read-only links to the notebook. Each link carries a label, visible only
to you, which is how you tell links apart later when you go to revoke one.

Require a Chalk account is on by default. With it on, a viewer has to sign in and already have
read access to the environment — the link points them at the notebook, it does not grant access on
its own. With it off, anyone holding the URL can open the notebook without an account, so treat
the URL itself as the credential.

Each link has an expiry: 7, 30, or 90 days, or 1 year. The default is 30 days.

The URL is shown exactly once, when you create the link. Chalk stores only a hash of it and
will not display it again, so copy it then — if you lose it, revoke the link and create a new one.

Active links lists every link the notebook has: its label, whether it requires sign-in or is
public, when it expires, when it was last opened, and a Revoke button.

Whoever opens a link sees the notebook — its cells, and the results of the most recent run — but
cannot edit it, run it, read its secrets, or reach the app canvas. Interpolated Markdown renders
for them too, since resolved values are saved with cell output; see
Cell outputs. Shared pages are set to noindex, so
search engines do not index them.

### Notebook settings

Runtime options that apply to the whole notebook can be found in the Notebook settings panel, which can be opened from the settings button in the toolbar. From there, you can:

- Define the notebook's secrets.
- Configure its compute resources and the behavior of its kernel.
- Turn on Vim keybindings.
- Turn on AI autocomplete.
- Read the kernel's runtime information.

### History and versions

The history button opens History & versions, one reverse-chronological timeline of what has
happened to the notebook.

Recent runs appear in it, paginated behind Load more runs, each labeled by what the run
covered — "Ran all cells", "Ran cell + upstream" — along with its status, its duration, and who
ran it. Open a run to see it cell by cell: per-cell status and duration, output and row counts,
and the text of any error inline. Run history is retained for 30 days.

Cell edits share the same timeline, one row per cell, and open into a syntax-highlighted view of
that cell's source.





