Skip to main content
The runtimed Python package provides programmatic access to the notebook daemon. Use it to execute code, manage kernels, and interact with notebooks from Python scripts, agents, or automation workflows.

Installation

# From PyPI (when published)
pip install runtimed

Quick Start

import runtimed

# Execute code with automatic kernel management
with runtimed.Session() as session:
    session.start_kernel()
    result = session.run("print('hello')")
    print(result.stdout)  # "hello\n"

Session API

The Session class is the primary interface for executing code. Each session connects to a notebook room in the daemon.

Creating a Session

# Auto-generated notebook ID
session = runtimed.Session()

# Explicit notebook ID (allows sharing between sessions)
session = runtimed.Session(notebook_id="my-notebook")

Kernel Lifecycle

session.connect()                    # Connect to daemon (auto-called by start_kernel)
session.start_kernel()               # Launch Python kernel
session.start_kernel(kernel_type="deno")  # Launch Deno kernel
session.interrupt()                  # Interrupt running execution
session.shutdown_kernel()            # Stop the kernel

Code Execution

The session uses a document-first model where cells are stored in an Automerge document. This enables multi-client synchronization.
# Create cells in the document, then execute
cell_id = session.create_cell("x = 42")
result = session.execute_cell(cell_id)

# Execute another cell
cell_id2 = session.create_cell("print(x)")
result = session.execute_cell(cell_id2)

# Check results
print(result.success)         # True if no error
print(result.stdout)          # Captured stdout
print(result.stderr)          # Captured stderr
print(result.execution_count) # Execution counter
print(result.error)           # Error output if failed

Document Operations

# Create a cell in the document
cell_id = session.create_cell("x = 10")

# Update cell source
session.set_source(cell_id, "x = 20")

# Execute by cell ID (daemon reads source from document)
result = session.execute_cell(cell_id)

# Read cell state
cell = session.get_cell(cell_id)
print(cell.source)           # "x = 20"
print(cell.execution_count)  # 1

# List all cells
cells = session.get_cells()

# Delete a cell
session.delete_cell(cell_id)

Queue Execution

For fire-and-forget execution:
# Queue execution without waiting
session.queue_cell(cell_id)

# Poll for results later
cell = session.get_cell(cell_id)

Context Manager

Sessions work as context managers for automatic cleanup:
with runtimed.Session() as session:
    session.start_kernel()
    cell_id = session.create_cell("1 + 1")
    result = session.execute_cell(cell_id)
# Kernel automatically shut down on exit

Session Properties

PropertyTypeDescription
notebook_idstrUnique identifier for this notebook
is_connectedboolWhether connected to daemon
kernel_startedboolWhether kernel is running
env_sourcestr | NoneEnvironment source (e.g., “uv:prewarmed”)

AsyncSession API

The AsyncSession class provides the same functionality as Session but with an async API for use in async Python code.

Creating an AsyncSession

# Auto-generated notebook ID
session = runtimed.AsyncSession()

# Explicit notebook ID (allows sharing between sessions)
session = runtimed.AsyncSession(notebook_id="my-notebook")

Async Kernel Lifecycle

await session.connect()              # Connect to daemon
await session.start_kernel()         # Launch Python kernel
await session.start_kernel(kernel_type="deno")  # Launch Deno kernel
await session.interrupt()            # Interrupt running execution
await session.shutdown_kernel()      # Stop the kernel

Async Code Execution

# Create and execute cells
cell_id = await session.create_cell("x = 42")
result = await session.execute_cell(cell_id)

cell_id2 = await session.create_cell("print(x)")
result = await session.execute_cell(cell_id2)

# Check results
print(result.success)  # True if no error
print(result.stdout)   # Captured stdout

Async Document Operations

# Create a cell in the automerge document
cell_id = await session.create_cell("x = 10")

# Update cell source
await session.set_source(cell_id, "x = 20")

# Execute by cell ID
result = await session.execute_cell(cell_id)

# Read cell state
cell = await session.get_cell(cell_id)
print(cell.source)  # "x = 20"

# List all cells
cells = await session.get_cells()

# Delete a cell
await session.delete_cell(cell_id)

Async Context Manager

async with runtimed.AsyncSession() as session:
    await session.start_kernel()
    cell_id = await session.create_cell("1 + 1")
    result = await session.execute_cell(cell_id)
# Kernel automatically shut down on exit

Async Properties

Property accessors are async methods in AsyncSession (except notebook_id):
# These are coroutines, not properties
connected = await session.is_connected()     # bool
kernel_running = await session.kernel_started()  # bool
env = await session.env_source()             # str | None

# Only notebook_id is a sync property
notebook_id = session.notebook_id  # str

DaemonClient API

The DaemonClient class provides low-level access to daemon operations.
client = runtimed.DaemonClient()

# Health checks
client.ping()         # True if daemon responding
client.is_running()   # True if daemon process exists

# Pool status
stats = client.status()
# {
#   'uv_available': 2,
#   'conda_available': 0,
#   'uv_warming': 1,
#   'conda_warming': 0
# }

# Active notebook rooms
rooms = client.list_rooms()
# [
#   {
#     'notebook_id': 'my-notebook',
#     'active_peers': 2,
#     'has_kernel': True,
#     'kernel_type': 'python',
#     'kernel_status': 'idle',
#     'env_source': 'uv:prewarmed'
#   }
# ]

# Operations
client.flush_pool()   # Clear and rebuild environment pool
client.shutdown()     # Stop the daemon

Result Types

ExecutionResult

Returned by execute_cell():
cell_id = session.create_cell("print('hello')")
result = session.execute_cell(cell_id)

result.cell_id          # Cell that was executed
result.success          # True if no error
result.execution_count  # Execution counter value
result.outputs          # List of Output objects
result.stdout           # Combined stdout text
result.stderr           # Combined stderr text
result.display_data     # List of display_data/execute_result outputs
result.error            # First error output, or None

Output

Individual outputs from execution:
for output in result.outputs:
    print(output.output_type)  # "stream", "display_data", "execute_result", "error"

    # For streams
    print(output.name)  # "stdout" or "stderr"
    print(output.text)  # The text content

    # For display_data/execute_result
    print(output.data)  # Dict[str, str] of MIME type -> content

    # For errors
    print(output.ename)      # Exception class name
    print(output.evalue)     # Exception message
    print(output.traceback)  # List of traceback lines

Cell

Cell from the automerge document:
cell = session.get_cell(cell_id)

cell.id              # Cell identifier
cell.cell_type       # "code", "markdown", or "raw"
cell.source          # Cell source content
cell.execution_count # Execution count if executed

Multi-Client Scenarios

Two sessions with the same notebook_id share the same kernel and document:
# Session 1 creates a cell and executes
s1 = runtimed.Session(notebook_id="shared")
s1.connect()
s1.start_kernel()
cell_id = s1.create_cell("x = 42")
s1.execute_cell(cell_id)

# Session 2 sees the cell and shares the kernel
s2 = runtimed.Session(notebook_id="shared")
s2.connect()
s2.start_kernel()  # Reuses existing kernel

cells = s2.get_cells()
assert any(c.id == cell_id for c in cells)

# Execute in s2, result visible to s1
cell_id2 = s2.create_cell("print(x)")
s2.execute_cell(cell_id2)  # Uses x=42 from s1's execution
This enables:
  • Multiple Python processes sharing a notebook
  • Python scripts interacting with notebooks open in the app
  • Agent workflows with parallel execution

Error Handling

All errors raise RuntimedError:
try:
    session.execute_cell("nonexistent-cell-id")
except runtimed.RuntimedError as e:
    print(f"Error: {e}")  # "Cell not found: nonexistent-cell-id"
Common error scenarios:
  • Connection to daemon fails
  • Kernel not started before execution
  • Cell not found
  • Execution timeout
  • Kernel errors

Environment Variables

VariableDescription
CONDUCTOR_WORKSPACE_PATHUse dev daemon for this worktree
RUNTIMED_SOCKET_PATHOverride daemon socket path

Sidecar (Rich Output Viewer)

The package also includes a sidecar launcher for rich output display:
from runtimed import sidecar

# In a Jupyter kernel - auto-detects connection file
s = sidecar()

# In terminal IPython - creates IOPub bridge
s = sidecar()

# Explicit connection file
s = sidecar("/path/to/kernel-123.json")

# Check status
print(s.running)  # True if sidecar process is alive

# Cleanup
s.close()
The sidecar provides a GUI window that displays rich outputs (plots, HTML, images) from kernel execution.

Build docs developers (and LLMs) love