Don't let broken changes merge.
Project description
Maida
The step-through debugger for AI agents.
Maida captures a structured trace of every agent run - LLM calls, tool calls, errors, state updates, loop warnings - and gives you a clean local timeline to see exactly what happened.
Add @trace, run your agent, then run:
maida view
In under 10 minutes, you can inspect a full execution timeline with inputs, outputs, status, and failure evidence - all on your machine.
No cloud. No accounts. No telemetry. Everything stays on your machine.
Built-in run guardrails: stop runaway debug sessions when an agent starts looping or exceeds your limits for LLM calls, tool calls, total events, or duration.
Get running in 5 minutes
Three commands. No config files, no API keys, no sign-up. Install: pip install maida-ai. Then:
Step 1: Install
pip install maida-ai
Step 2: Run the example agent
python examples/demo/pure_python.py
This simulates a tiny agent that makes several tool and LLM calls and includes loop warnings and errors. Trace data lands in ~/.maida/runs/.
Step 3: Open the timeline
maida view
A browser tab opens at http://127.0.0.1:8712 showing the full run timeline - every event, with inputs, outputs, and timing. The viewer stays running: run more agents and their timelines appear automatically.
That's it. You're debugging.
Instrument your own agent
Add three lines to any Python agent:
from maida import trace, record_llm_call, record_tool_call
@trace
def run_agent():
# ... your existing agent code ...
record_tool_call(
name="search_db",
args={"query": "active users"},
result={"count": 42},
)
record_llm_call(
model="gpt-4",
prompt="Summarize the search results.",
response="There are 42 active users.",
usage={"prompt_tokens": 12, "completion_tokens": 8, "total_tokens": 20},
)
run_agent()
Then maida view to see the timeline.
What gets captured
| Event | Recorded by | What you see |
|---|---|---|
| Run start/end | @trace (automatic) |
Duration, status, error if any |
| LLM calls | record_llm_call() |
Model, prompt, response, token usage |
| Tool calls | record_tool_call() |
Tool name, args, result, status |
| State updates | record_state() |
Arbitrary state snapshots |
| Errors | @trace (automatic) |
Exception type, message, stack trace |
| Loop warnings | Automatic detection | Repetitive pattern + evidence |
Stop runaway runs with guardrails
Guardrails are opt-in and meant for development-time safety rails: they let you stop an agent when it starts looping or using more budget than intended, while still writing a normal trace you can inspect afterward.
from maida import (
GuardrailExceeded,
LoopAbort,
record_llm_call,
record_tool_call,
trace,
)
@trace(
stop_on_loop=True,
max_llm_calls=10,
max_tool_calls=20,
max_events=80,
max_duration_s=30,
)
def run_agent():
...
try:
run_agent()
except LoopAbort:
print("Maida stopped a repeated loop.")
except GuardrailExceeded as exc:
print(exc.guardrail, exc.threshold, exc.actual)
When a guardrail fires, Maida uses the existing lifecycle:
- it records the event that triggered the issue
- it records
ERROR - it records
RUN_END(status=error) - it re-raises a dedicated exception so your code knows the run was intentionally aborted
Available guardrails:
stop_on_loopstop_on_loop_min_repetitionsmax_llm_callsmax_tool_callsmax_eventsmax_duration_s
You can set them in @trace(...), traced_run(...), .maida/config.yaml, ~/.maida/config.yaml, or env vars like MAIDA_MAX_LLM_CALLS=50.
See docs/guardrails.md for full examples, precedence, and trace behavior.
What you see
In the UI, you see:
- Run summary panel: status (ok / error / running), duration, LLM call count, tool call count, error count, loop warnings, jump-to-first-error, jump-to-first-loop-warning
- Chronological timeline of events
- Expandable events: LLM calls (prompt, response, usage), tool calls (args, results, error status), loop warnings with evidence
- Live-refresh: leave
maida viewrunning — new runs appear in the sidebar, events stream in real-time for running agents - Filter chips: All, LLM, Tools, Errors, State, Loops
Each run produces run.json (metadata, status, counts) and events.jsonl (full structured event stream) under ~/.maida/. Nothing leaves your machine.
What Maida is
- Local-first: traces stored as JSONL on disk. No cloud, no accounts, no telemetry.
- Framework-agnostic: works with any Python code
- Redacted by default: secrets scrubbed before writing to disk
- Active prevention: stop-on-loop guardrails kill runaway agents before they burn your budget
- A development-time debugger for the "why did it do that?" moment
What Maida is NOT
- Not a hosted service or cloud platform
- Not a production observability tool (no dashboards, alerts, or monitoring)
- Not tied to a single framework
CLI reference
List recent runs
maida list # last 20 runs
maida list --limit 50 # more runs
maida list --json # machine-readable output
View a run timeline
maida view # opens latest run, stays running
maida view <RUN_ID> # specific run
maida view --no-browser # just print the URL
Export a run
maida export <RUN_ID> --out run.json
Capture a baseline
maida baseline <RUN_ID> # saves to .maida/baselines/<run_name>.json
maida baseline <RUN_ID> --out baselines/v1.json # custom path
Assert against a baseline
maida assert <RUN_ID> --baseline .maida/baselines/my_agent.json
maida assert <RUN_ID> --max-steps 80 --no-loops # standalone thresholds
maida assert <RUN_ID> --baseline baseline.json --format markdown # for CI summaries
Exit code 0 = pass, 1 = fail. See docs/regression-testing.md for the full workflow and docs/reference/policy.md for policy YAML configuration.
Diff two runs
maida diff <RUN_A> <RUN_B>
maida diff <RUN_A> --baseline .maida/baselines/my_agent.json
Regression testing
Baselines, assertions, and diffs let you catch agent regressions — locally or in CI. The workflow:
- Baseline a known-good run (
maida baseline) - Assert future runs against it (
maida assert --baseline ...) - Diff failures to see what changed (
maida diff)
Control assertion thresholds via a committed .maida/policy.yaml file or CLI flags. Supports text, JSON, and markdown output formats.
See docs/regression-testing.md for the end-to-end guide and docs/reference/policy.md for the policy file reference.
Redaction & privacy
Redaction is ON by default. Maida scrubs values for keys matching sensitive patterns (case-insensitive) before writing to disk. Large fields are truncated (marked with __TRUNCATED__ marker).
Default redacted keys: api_key, token, authorization, cookie, secret, password.
# Override defaults via environment variables
export MAIDA_REDACT=1 # on by default
export MAIDA_REDACT_KEYS="api_key,token,authorization,cookie,secret,password"
export MAIDA_MAX_FIELD_BYTES=20000 # truncation limit
You can also configure redaction in .maida/config.yaml (project root) or ~/.maida/config.yaml.
Guardrails
Guardrails are separate from redaction and are disabled by default. They are useful when you want Maida to actively stop a run instead of only recording what happened.
export MAIDA_STOP_ON_LOOP=1
export MAIDA_STOP_ON_LOOP_MIN_REPETITIONS=3
export MAIDA_MAX_LLM_CALLS=50
export MAIDA_MAX_TOOL_CALLS=50
export MAIDA_MAX_EVENTS=200
export MAIDA_MAX_DURATION_S=60
YAML example:
guardrails:
stop_on_loop: true
stop_on_loop_min_repetitions: 3
max_llm_calls: 50
max_tool_calls: 50
max_events: 200
max_duration_s: 60
Precedence:
- Function arguments passed to
@trace(...)ortraced_run(...) - Environment variables
- Project YAML:
.maida/config.yaml - User YAML:
~/.maida/config.yaml - Defaults
See docs/guardrails.md and docs/reference/config.md.
Storage
All data is local. Plain files, easy to inspect or delete.
~/.maida/
└── runs/
└── <run_id>/
├── run.json # run metadata (status, counts, timing)
└── events.jsonl # append-only event log
Override the location:
export MAIDA_DATA_DIR=/path/to/traces
Integrations
Maida is framework-agnostic at its core. The SDK works with any Python code.
LangChain / LangGraph
Optional callback handler that auto-records LLM and tool events. Requires langchain-core:
pip install maida-ai[langchain]
from maida import trace
from maida.integrations import LangChainCallbackHandler
@trace
def run_agent():
handler = LangChainCallbackHandler()
# pass to your chain: config={"callbacks": [handler]}
...
See examples/langchain/minimal.py for a runnable example.
OpenAI Agents SDK
Optional tracing adapter that auto-records generation, function, and handoff spans. Requires openai-agents:
pip install maida-ai[openai]
from maida import trace
from maida.integrations import openai_agents # registers hooks
@trace
def run_agent():
# ... your OpenAI Agents SDK code ...
...
See examples/openai_agents/minimal.py for a runnable fake-data example with no API key and no networked model calls.
CrewAI
Optional execution-hook adapter that auto-records LLM and tool events from CrewAI crews and flows. Requires crewai[tools]:
pip install maida-ai[crewai]
import maida
from maida.integrations import crewai as mai_crewai # registers hooks
@maida.trace
def run_crew():
# ... your crew.kickoff() or flow.kickoff() ...
...
More framework adapters coming soon (Agno, and others).
Tutorials
Step-by-step Jupyter notebooks live in a separate repository: Maida-AI/maida-tutorials. Covers LangChain, OpenAI Agents SDK, and guardrails — all runnable without API keys.
Development
git clone https://github.com/Maida-AI/maida.git
cd maida
uv venv && uv sync && uv pip install -e .
No uv? Use pip instead.
python -m venv .venv && source .venv/bin/activate
pip install -e .
For LangChain support: pip install -e ".[langchain]". For OpenAI Agents support: pip install -e ".[openai]". Run tests: uv run pytest (or pytest).
License
Licensed under the Apache License, Version 2.0. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file maida_ai-0.3.2.post1.tar.gz.
File metadata
- Download URL: maida_ai-0.3.2.post1.tar.gz
- Upload date:
- Size: 8.9 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8d5170f61bbf9871e6853b46509abdc5f1aa4e9d4fd5370255f49483f89e9486
|
|
| MD5 |
ccbf7dc33a4016ebbb9d11464c4f8f9d
|
|
| BLAKE2b-256 |
f68f7afe6b14b71acd89e1a706f3db7ffd404c49a27051cf682a7808bd4f9ee7
|
File details
Details for the file maida_ai-0.3.2.post1-py3-none-any.whl.
File metadata
- Download URL: maida_ai-0.3.2.post1-py3-none-any.whl
- Upload date:
- Size: 74.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
05393c58e905974a545e135b47e2fe18e9dd2aa5e289746ea383ae779ae72a35
|
|
| MD5 |
ab11c3fa98e54b8d0f01466bb4e54e5d
|
|
| BLAKE2b-256 |
650368aa372914cefd8e301bca86909cfe6b51d9bbe4b55684ae52094692db09
|