Skip to main content
CodeMode replaces a wide tool schema with one programmable environment. The model writes Python that runs in an IPython kernel persisting for the session, so variables, imports, and helper functions survive across turns. Toolkits passed to it are not listed in the model’s schema: they are bound inside the kernel as awaitable handles the code can call, composing tools with variables, loops, and helpers instead of round-tripping each call through the transcript.
CodeMode is not a sandbox. Cells run arbitrary Python — and, by default, %%bash shell commands — with the host process’s permissions, and restoring a persisted snapshot is itself code execution. allow_shell=False removes the shell magic but is a footgun reducer, not a security boundary. For untrusted use, run the agent inside a real sandbox (container or VM).

Prerequisites

CodeMode requires Python 3.10 or newer. The agno[code] extra provides ipykernel, jupyter_client, and dill; the example also uses the openai library:

Example

cookbook/code/01_basics/basic.py

How a Cell Runs

The model sees two tools by default: execute and, unless allow_restart=False, restart. The first execute in a session starts an IPython kernel subprocess keyed on the run’s session id — the id comes from the framework, never from a model argument — and the kernel is reused across runs in the same process until it has been idle for idle_ttl seconds. Toolkits and functions passed via tools= become awaitable handles inside the kernel: the handle name is the toolkit name with a trailing _tools stripped, and each function is an async stub the code can await. The host runs the real tool call, so tool_hooks, pre_hook/post_hook, and result caching still apply — and a whole cell counts as one call toward the agent’s tool_call_limit. Tools that pause a run (requires_confirmation, external_execution, requires_user_input) are bound as stubs that refuse with a fixed message, because a cell cannot pause the run. The generated instructions tell the model which handles exist, that state persists, and the %%bash rules. Cell output returns stdout, a stderr block, the Out[n]: repr, or a traceback; each stream is capped at max_output_chars with the truncated streams named, and PNG display output is promoted to image artifacts (at most max_images_per_cell, each at most max_image_bytes). Failure modes:
  • An exception in the cell returns its traceback to the model as an error result.
  • A cell over timeout seconds is interrupted; if the kernel does not respond to the interrupt, the cell returns as aborted and the next cell must wait for the kernel to clear within busy_wait seconds — otherwise the model is told the environment is busy and to retry or restart. With on_busy_kernel="restart", CodeMode instead restarts the kernel and re-runs the cell once.
  • A kernel that dies mid-cell reports the death; a fresh kernel starts on the next execute, with previous state gone.
  • A bridged tool result over max_result_bytes raises a ResultTooLarge error inside the cell, telling the model to enable result offloading or write large payloads to the file system — unless the agent has result offloading enabled, in which case the result is offloaded and the cell receives an envelope id.

Persistence

With fs= set to an AgentFS FileSystem and snapshot=True (the default), every successful cell schedules a debounced per-variable snapshot, and a new kernel for a known session restores it before binding tools — so kernel state survives process restarts. Unpicklable or oversized variables are skipped and named in the restore notice the model sees. The snapshot caps are lowered to the FileSystem’s own per-file and per-namespace limits when those are smaller, with a warning naming the reduction. A session is owned by the user_id of the run that created it; a later run with a different user_id is refused and gets no kernel. The run-end close() flushes pending snapshots but keeps kernels alive; call shutdown() to snapshot and kill them.

Teams

A team leader and members share the team session id, so members sharing one CodeMode instance share one kernel namespace — and concurrent cells contend for it under the busy-kernel rules above. Share one instance when members should build on each other’s variables; give members separate instances when their state must stay isolated.

Toolkit Params

Toolkit Functions

Both tools have async variants registered under the same names. A developer surface exists alongside the model-facing tools — run, variables, value, and shutdown, each with an a-prefixed async twin — for driving or inspecting a session from your own code.

Developer Resources