Documentation
Operate your agents
LangMonitor watches and controls LangGraph agents from the outside. Wrap a compiled graph in one line and a dashboard goes live inside your process — then stream events and drive the run over a plain REST and WebSocket API.
$ pip install langmonitorStart here
Quickstart
Install the package, wrap your compiled graph, and run it as you normally would. The dashboard is served from the same process.
from langmonitor import monitor
# Wrap your compiled LangGraph graph and choose a port.monitored = monitor(compiled_graph, port=8000, open_browser=True)
# Run it like any compiled graph — sync or async.result = monitored.invoke({"input": "hello"})
print(monitored.dashboard_url) # http://127.0.0.1:8000Open http://localhost:8000 for the interactive dashboard — watch every node, then kill, pause, resume, inject state, roll back, or A/B-swap the running agent. Prefer raw REST? The Swagger UI is at /docs. Requires Python 3.10+.
monitor()
The three modes
monitor() returns a drop-in stand-in for your graph — same invoke and ainvoke. Which mode you get depends on what you pass.
# 1. Embedded (default) — a dashboard in this process on the given portmonitor(graph, port=8000)
# 2. Remote — connect to a LangMonitor server running elsewheremonitor(graph, server_url="ws://monitor.internal:8000", api_key="...")
# 3. In-process engine — route events straight to a MainEngine (used in tests)monitor(graph, in_process_engine=engine)If the dashboard can't start, or a remote server is down, monitoring fails open — your agent keeps running, just unmonitored.
Control
Operating a run
Every run gets a run_id (emitted as the run_started event and listed at GET /api/v1/runs). Use it to drive the run — from Swagger, from Python, or straight from the shell.
$ curl -X POST localhost:8000/api/v1/runs/<run_id>/pause
$ curl -X POST localhost:8000/api/v1/runs/<run_id>/resume \ -d '{"state_patch": {"context": "updated"}}'
$ curl -X POST localhost:8000/api/v1/runs/<run_id>/killKill and pause take effect before the next node — the wrapper checks for them between steps.
Time travel
Checkpoints & rollback
Checkpoints sit on top of LangGraph's native checkpointer. Save one by hand, then roll back to it at any time.
# Save a named checkpoint$ curl -X POST localhost:8000/api/v1/runs/<run_id>/checkpoints \ -d '{"label": "before-tool-call"}'
# Restore it — auto-pauses the run so you can inspect before resuming$ curl -X POST \ localhost:8000/api/v1/runs/<run_id>/checkpoints/<id>/rollbackWith CHECKPOINT_AUTO_SAVE=true (the default) a checkpoint is also taken after every node end, so you can always step backwards.
Automatic
Guardrails
Guardrails run after every node end. When one trips it fires the configured action — kill, pause, or alert.
$ curl -X POST localhost:8000/api/v1/guardrails -d '{ "name": "cost cap", "rule_type": "max_cost_usd", "config": { "threshold": 2.0 }, "action": "kill" }'Built-in rule types:
max_tool_calls,max_node_repeats,max_latency_ms,max_cost_usd— numeric thresholds.custom_condition— a sandboxed boolean expression evaluated against the current node. Noeval, no attribute access or calls.
{ "rule_type": "custom_condition", "config": { "expression": "node_name == 'planner' and latency_ms > 5000" }, "action": "alert"}Available names in an expression: node_name, latency_ms, tokens_used, sequence_order.
Experiment
A/B prompt swaps
Register two prompts for a node, then swap the active variant while the agent runs. The wrapper picks up the active variant before each node — no code changes needed.
# Create the test$ curl -X POST localhost:8000/api/v1/ab-tests -d '{ "node_name": "planner", "prompt_a": "You are a careful planner.", "prompt_b": "You are an aggressive planner." }'
# Swap the active variant mid-run$ curl -X POST localhost:8000/api/v1/ab-tests/<id>/swapWebSocket
Streaming events
Consume the live event stream from any client. Two channels:
/ws/runs/{run_id}— events for a single run./ws/all— every event across all runs.
Every message has the same envelope:
{ "type": "node_end", "run_id": "<uuid>", "timestamp": "<iso8601>", "payload": { "node_name": "planner", "latency_ms": 312, "tokens": 148 }}| Event | Key payload fields |
|---|---|
run_started | graph_name, input |
node_start | node_name, sequence, input_state |
node_end | node_name, output_state, latency_ms, tokens |
llm_call | node_name, prompt, response, model, tokens |
state_updated | sequence, state, diff |
guardrail_alert | rule_name, rule_type, action |
checkpoint_saved | checkpoint_id, label, sequence |
run_ended | status, total_tokens, total_cost_usd, duration_ms |
Environment
Configuration
The dashboard reads the same settings as the standalone server. Set them in the environment or a .env file — see .env.example for the full list.
| Variable | Default | Description |
|---|---|---|
DATABASE_URL | sqlite+aiosqlite://… | SQLAlchemy async URL. Use postgresql+asyncpg://… for Postgres. |
SERVER_HOST | 0.0.0.0 | Bind host for the standalone server. |
SERVER_PORT | 8000 | Bind port for the standalone server. |
API_KEY | "" | Shared secret on every request. Empty = unauthenticated (dev only). |
ENABLE_DOCS | true | Expose /docs, /redoc, /openapi.json. Set false in production. |
CHECKPOINT_AUTO_SAVE | true | Auto-save a checkpoint after every node end. |
CORS_ORIGINS | [localhost:3000] | JSON list, comma-separated string, or single origin. |
LOG_LEVEL | INFO | Python log level. |
Before you expose it
Security
LangMonitor is a control plane — anyone who can reach it can kill, pause, or inject state into your agents. The embedded dashboard binds to 127.0.0.1 by default, so it's local-only. Before putting it on a network:
- Set
API_KEY. Once set, every route and WebSocket requires it (X-API-Keyheader, or?api_key=for browsers). When empty the server runs open and warns at startup — fine for local dev only. - Lock down CORS to origins you trust; the
*+ credentials combination is force-disabled. - Disable docs with
ENABLE_DOCS=falsein production. - Connection caps, rule-count limits, and payload-size bounds blunt trivial DoS vectors, and
custom_conditionguardrails are AST-sandboxed.