marimo._code_mode is a private API; Hailer pins marimo 0.24.2 and may need changes for other versions.
The notebook must be open in a browser; a headless server without a tab has nothing to execute against.
Switching notebooks opens a new tab; the old one stays open until you close it or /notebook close it.
When the agent switches notebooks and the browser is slow to load, the CLI may open the same notebook a
second time after the turn (it opens the URL once more when it still sees no kernel session); the extra
tab is harmless, close it.
If you press Ctrl+C while the agent is in the middle of notebook_create / notebook_open, that tool call
may still finish and switch the active notebook a moment later. Hailer re-reads the state after every
turn and before /notebook and /status, so the next command shows the right notebook; a /notebook
new typed in that instant can still be overtaken by the late switch.
Every uvx hailer and uvx hailer notebook session starts its own marimo server and stops it when the
chat ends, so restarting the chat re-runs the notebook in a fresh kernel. A server you start yourself
(for example with marimo edit --no-token) cannot be used, and two sessions never share a kernel.
Every request carries about 10 KB of instructions and 5 KB of tool definitions (measured with an empty
project context) plus the conversation; an endpoint with a strict request-size limit needs room for that.
The endpoint must support function calling in the standard OpenAI shape. An endpoint that streams tool
calls in a non-standard way may lose their arguments; stream = false on the provider avoids that.
The code checks are static: ty cannot see column names or the data,
and types from packages Hailer's own Python lacks (with the docker kernel: altair, plotly) are unknown to
it, so it finds less there. ty is pre-1.0; Hailer pins it, and its rules and messages may change when
the pin moves. Formatting needs ruff in the kernel's Python: Hailer's own Python (unsafe-local) and the
kernel image have it, and so does an image of your own built FROM Hailer's.
After Ctrl+C during a long marimo_execute, the turn ends at once but the code keeps running in the
kernel until it finishes, or until you interrupt or restart the kernel from the notebook.
The default docker kernel needs Docker, which is not always an option: Docker Desktop is free for
personal use and small businesses, but larger organisations need a paid subscription (check Docker's
current terms), and managed machines often block Docker Desktop, WSL2 or Hyper-V. Where it is not,
runtime = "unsafe-local" runs notebook code on the machine as you, without isolation, for those who
accept that (see Kernel runtimes).
Reading large data files through a Windows bind mount is slower than reading them from a local folder;
how much slower for large Parquet files has not been measured yet.
A docker kernel works on copies of the notebooks (see Notebook copies):
only marimo notebooks with plain names travel, at most 500 of up to 5 MB each; other files notebook code
writes next to them are gone when the kernel stops; edits made on your machine during a session reach the
kernel only at the next start; and if Hailer is killed, the kernel's changes since the last copy (at most
about 15 seconds of browser edits, or the current turn) are lost.
The release workflow builds the linux/arm64 kernel image (Apple Silicon, ARM Linux), but the CI
integration test only covers amd64. Podman is not supported.
The docker kernel has only the packages in the image (marimo, Polars, fastexcel, DuckDB, ruff, altair, plotly); anything
else needs an image of your own, built FROM Hailer's (so it keeps the kernel contract label) and named in
[kernel].image. Changed [kernel] settings apply from the next session.