← conversation · Trace
Run trace
The run as an OpenTelemetry trace: the run is the root span, each model call, tool call, and approval gate is a child span. Built from the audit log, exportable to your collector.
run: Find bugs, then fix them but show me the problem before comm
74052143.0 ms
tool: run_selfcheck
0.0 ms
tool: list_source
0.0 ms
tool: read_source
0.0 ms
tool: read_source
0.0 ms
tool: read_source
0.0 ms
tool: read_source
0.0 ms
tool: read_source
0.0 ms
tool: read_source
0.0 ms
tool: read_source
0.0 ms
tool: read_source
0.0 ms
tool: read_source
0.0 ms
tool: read_source
0.0 ms
tool: read_source
0.0 ms
final response
0.0 ms
tool: list_files
0.0 ms
tool: list_source
0.0 ms
final response
0.0 ms
tool: read_source
0.0 ms
final response
0.0 ms
final response
0.0 ms
model: claude-sonnet-4-6
53121.0 ms
gate: propose_patch
0.0 ms
denied: propose_patch
0.0 ms
model: claude-sonnet-4-6
15073.0 ms
final response
0.0 ms
Span attributes
run: Find bugs, then fix them but show me the problem before comm
warden.run_id=run-36099a48warden.agent_id=ag-78faa27dwarden.status=done
tool: run_selfcheck
warden.tool=run_selfcheckwarden.risk=LOWwarden.gated=Falsewarden.latency_ms=0warden.tool.input={}warden.tool.output={"files_checked": 11, "findings": [], "clean": true}
tool: list_source
warden.tool=list_sourcewarden.risk=LOWwarden.gated=Falsewarden.latency_ms=0warden.tool.input={}warden.tool.output=[{"file": "agent_runtime.py", "lines": 173}, {"file": "app.py", "lines": 308}, {"file": "catalog.py", "lines": 90}, {"file": "connection_manager.py", "lines": 197}, {"file": "governance.py", "lines": 64}, {"file": "mcp_code_server.py", "lines": 79}, {"file": "mcp_fs_server.py", "lines": 52}, {"file": "mcp_server.py", "lines": 95}, {"file": "paths.py", "lines": 32}, {"file": "store.py", "lines": 190}, {"file": "vault.py", "lines": 60}]
tool: read_source
warden.tool=read_sourcewarden.risk=LOWwarden.gated=Falsewarden.latency_ms=0warden.tool.input={"filename": "agent_runtime.py"}warden.tool.output="\"\"\"\nThe Warden runtime. Runs an agent in a perceive -> decide -> act loop against a live\nAnthropic model, invoking tools across one or more connected MCP servers via the\nconnection manager. Governance is enforced here: each tool's risk is resolved\n(override > known registry > auto-classification) and high-risk tools pause the run\nfor human approval. Live model calls when ANTHROPIC_API_KEY is set; otherwise a\ndeterministic sandbox planner drives the same flow offline.\n\"\"\"\nimport os, json, re\nimport connection_manager as cmod\nimport governance as gov\nimport store\n\nMODEL_DEFAU…
tool: read_source
warden.tool=read_sourcewarden.risk=LOWwarden.gated=Falsewarden.latency_ms=0warden.tool.input={"filename": "app.py"}warden.tool.output="\"\"\"\nWarden, an enterprise AI agent studio where every agent is governed by default.\nConnect MCP servers, build an agent from their tools, run it against a live model, and\ngate high-risk actions behind human approval with a full audit trail.\n\"\"\"\nimport os\nimport datetime\nimport threading\nimport json as _json\nfrom flask import Flask, request, redirect, url_for, render_template, abort\nimport store, governance as gov, agent_runtime as rt\nimport connection_manager as cmod\nimport catalog as cat\n\nWARDEN_VERSION = \"0.3\"\n\ndef _build_info():\n \"\"\"Increment a build number o…
tool: read_source
warden.tool=read_sourcewarden.risk=LOWwarden.gated=Falsewarden.latency_ms=0warden.tool.input={"filename": "catalog.py"}warden.tool.output="\"\"\"\nThe connections catalog: a curated directory of common enterprise MCP servers.\nAccurate as of mid-2026. Each entry records who maintains it, how it connects\n(transport), what credentials it needs, and a default governance posture.\n\n'maintainer': official = Anthropic reference (educational), vendor = product owner,\n community = third party, warden = ships built in with this app.\n'transport': stdio_python (uvx ...), stdio_node (npx ...), http (remote OAuth URL),\n builtin (a local server this app runs itself).\n'status': ready = connectable in this a…
tool: read_source
warden.tool=read_sourcewarden.risk=LOWwarden.gated=Falsewarden.latency_ms=0warden.tool.input={"filename": "connection_manager.py"}warden.tool.output="\"\"\"\nMulti-server MCP connection manager.\n\nOwns one dedicated asyncio loop thread. Tool discovery is done once at connect time and\ncached, so listing tools never re-hits a server. For execution: stdio/builtin servers\nkeep a persistent session (subprocess spawn is expensive); HTTP servers open a fresh\nshort-lived session per call, entirely within one coroutine, because the streamable-HTTP\ntransport binds its cancel scope to the creating task and cannot be reused across tasks.\n\"\"\"\nimport os, sys, asyncio, threading, warnings, shlex\nfrom contextlib import asynccontextmanager\nfrom…
tool: read_source
warden.tool=read_sourcewarden.risk=LOWwarden.gated=Falsewarden.latency_ms=0warden.tool.input={"filename": "governance.py"}warden.tool.output="\"\"\"\nThe governance layer. Warden's point of view: tools can do things; governance decides\nwhich run on their own and which pause for a human. Built-in enterprise tools have a\nhand-set risk registry. Tools discovered from external MCP servers are classified\nautomatically, fail-closed: reads run, writes and anything unrecognized are gated.\nAn operator can override any tool's risk.\n\"\"\"\nSKILLS = {\n \"lookup_customer\": {\"risk\":\"LOW\",\"gate\":\"auto\",\"kind\":\"read\"},\n \"search_knowledge\":{\"risk\":\"LOW\",\"gate\":\"auto\",\"kind\":\"read\"},\n \"create_ticket\": …
tool: read_source
warden.tool=read_sourcewarden.risk=LOWwarden.gated=Falsewarden.latency_ms=0warden.tool.input={"filename": "mcp_code_server.py"}warden.tool.output="\"\"\"\nWarden self-audit MCP server. Exposes Warden's own source code to an agent so a\n\"Warden Engineer\" agent can inspect the running codebase, run a real static self-check,\nand propose fixes. Reads are safe and auto-run; proposing a patch is a gated write that\nlands in a review folder (it never overwrites the running source).\n\"\"\"\nimport os, json, ast, py_compile, tempfile\nfrom mcp.server.fastmcp import FastMCP\n\nAPP_DIR = os.path.dirname(os.path.abspath(__file__))\nimport paths\nPATCH_DIR = os.path.join(paths.DATA_ROOT, \"data\", \"patches\")\nos.makedirs(PATCH_DIR, exist_ok=Tr…
tool: read_source
warden.tool=read_sourcewarden.risk=LOWwarden.gated=Falsewarden.latency_ms=0warden.tool.input={"filename": "mcp_fs_server.py"}warden.tool.output="\"\"\"\nWarden's built-in Filesystem MCP server. A real second MCP server (local, Python) so\nmulti-server connection and routing is demonstrable without needing Node. All access\nis confined to a sandbox workspace directory.\n\"\"\"\nimport os\nimport json\nfrom mcp.server.fastmcp import FastMCP\n\nimport paths\nWORKSPACE = os.path.join(paths.DATA_ROOT, \"data\", \"workspace\")\nos.makedirs(WORKSPACE, exist_ok=True)\n\n# seed one file so reads have something to find\n_seed = os.path.join(WORKSPACE, \"welcome.txt\")\nif not os.path.exists(_seed):\n open(_seed, \"w\").write(\"Warden workspa…
tool: read_source
warden.tool=read_sourcewarden.risk=LOWwarden.gated=Falsewarden.latency_ms=0warden.tool.input={"filename": "mcp_server.py"}warden.tool.output="\"\"\"\nWarden MCP server: a real Model Context Protocol server exposing a small set of\nenterprise-flavored tools. The Warden runtime connects to this as an MCP client,\ndiscovers these tools over the protocol, and invokes them.\n\nTools deliberately span read and write so the governance layer has something to\ngovern: reads are low risk and auto-execute; writes change state and are the ones\nthe studio gates behind human approval.\n\nRun standalone for a protocol smoke test: python mcp_server.py\n(but normally it is spawned over stdio by the runtime's MCP client)\n\"\"\"\nimport json\nimpo…
tool: read_source
warden.tool=read_sourcewarden.risk=LOWwarden.gated=Falsewarden.latency_ms=0warden.tool.input={"filename": "store.py"}warden.tool.output="\"\"\"\nPersistence for Warden: agents, runs, the audit log, and the approvals queue.\nSQLite on disk. On a platform with an ephemeral filesystem (Render) this resets on\nredeploy, which is fine for a demo; the point is that within a session every agent\naction and every approval is durably recorded and queryable.\n\"\"\"\nimport os\nimport json\nimport sqlite3\nimport datetime\nimport uuid\n\nimport paths\nDATA_ROOT = paths.DATA_ROOT\nDB = os.path.join(DATA_ROOT, \"warden.db\")\n\ndef _conn():\n c = sqlite3.connect(DB, timeout=10)\n c.row_factory = sqlite3.Row\n try:\n c.exec…
tool: read_source
warden.tool=read_sourcewarden.risk=LOWwarden.gated=Falsewarden.latency_ms=0warden.tool.input={"filename": "vault.py"}warden.tool.output="\"\"\"\nEncrypts secrets (connection tokens) at rest so they never sit in the database as\nplaintext. The key comes from WARDEN_SECRET_KEY if set (kept out of the data dir, the\nstronger option); otherwise a key is generated once and stored on the persistent disk\nnext to the data, so encryption works with zero configuration. Any string works as\nWARDEN_SECRET_KEY, it is hashed into a valid key.\n\"\"\"\nimport os\nimport base64\nimport hashlib\n\ntry:\n from cryptography.fernet import Fernet\n _OK = True\nexcept Exception:\n _OK = False\n\nimport paths\nDATA_ROOT = paths.DATA_ROOT\n…
tool: read_source
warden.tool=read_sourcewarden.risk=LOWwarden.gated=Falsewarden.latency_ms=0warden.tool.input={"filename": "paths.py"}warden.tool.output="\"\"\"\nResolves where Warden stores its data. Prefers WARDEN_DATA_DIR (a mounted persistent\ndisk in production). If that path can't be created or written, it falls back to a\nwritable local directory instead of crashing the app, and records that it fell back so\nthe condition is visible on /healthz. A misconfigured disk should degrade to ephemeral,\nnever take the service down.\n\"\"\"\nimport os\n\n_APPDIR = os.path.dirname(os.path.abspath(__file__))\nREQUESTED = os.environ.get(\"WARDEN_DATA_DIR\") or _APPDIR\n\ndef _writable(path):\n try:\n os.makedirs(path, exist_ok=True)\n …
tool: list_files
warden.tool=list_fileswarden.risk=LOWwarden.gated=Falsewarden.latency_ms=0warden.tool.input={}warden.tool.output=["welcome.txt"]
tool: list_source
warden.tool=list_sourcewarden.risk=LOWwarden.gated=Falsewarden.latency_ms=0warden.tool.input={}warden.tool.output=[{"file": "agent_runtime.py", "lines": 173}, {"file": "app.py", "lines": 308}, {"file": "catalog.py", "lines": 90}, {"file": "connection_manager.py", "lines": 197}, {"file": "governance.py", "lines": 64}, {"file": "mcp_code_server.py", "lines": 79}, {"file": "mcp_fs_server.py", "lines": 52}, {"file": "mcp_server.py", "lines": 95}, {"file": "paths.py", "lines": 32}, {"file": "store.py", "lines": 190}, {"file": "vault.py", "lines": 60}]
tool: read_source
warden.tool=read_sourcewarden.risk=LOWwarden.gated=Falsewarden.latency_ms=0warden.tool.input={"filename": "agent_runtime.py"}warden.tool.output="\"\"\"\nThe Warden runtime. Runs an agent in a perceive -> decide -> act loop against a live\nAnthropic model, invoking tools across one or more connected MCP servers via the\nconnection manager. Governance is enforced here: each tool's risk is resolved\n(override > known registry > auto-classification) and high-risk tools pause the run\nfor human approval. Live model calls when ANTHROPIC_API_KEY is set; otherwise a\ndeterministic sandbox planner drives the same flow offline.\n\"\"\"\nimport os, json, re\nimport connection_manager as cmod\nimport governance as gov\nimport store\n\nMODEL_DEFAU…
model: claude-sonnet-4-6
gen_ai.system=anthropicgen_ai.request.model=claude-sonnet-4-6gen_ai.usage.input_tokens=40594gen_ai.usage.output_tokens=3046warden.cost_usd=0.167472warden.latency_ms=53121
gate: propose_patch
warden.tool=propose_patchwarden.risk=HIGHwarden.decision=requestedwarden.tool.input={"filename": "agent_runtime.py", "rationale": "Bug 1 of 4: NameError in _execute_tool_turn when a gated tool call has no approval record (ap is None). The if/else branches both assign rtext, but if gated=True and ap=None neither branch executes, leaving rtext undefined when results.append() runs. Fix: initialise rtext to a safe JSON fallback at the top of the loop body so it is always defined regardless of which branch is taken.", "new_content": "\"\"\"\nThe Warden runtime. Runs an agent in a perceive -> decide -> act loop against a live\nAnthropic model, invoking tools across one or more conn…
denied: propose_patch
warden.tool=propose_patchwarden.risk=HIGHwarden.decision=deniedwarden.tool.input={"filename": "agent_runtime.py", "rationale": "Bug 1 of 4: NameError in _execute_tool_turn when a gated tool call has no approval record (ap is None). The if/else branches both assign rtext, but if gated=True and ap=None neither branch executes, leaving rtext undefined when results.append() runs. Fix: initialise rtext to a safe JSON fallback at the top of the loop body so it is always defined regardless of which branch is taken.", "new_content": "\"\"\"\nThe Warden runtime. Runs an agent in a perceive -> decide -> act loop against a live\nAnthropic model, invoking tools across one or more conn…
model: claude-sonnet-4-6
gen_ai.system=anthropicgen_ai.request.model=claude-sonnet-4-6gen_ai.usage.input_tokens=43677gen_ai.usage.output_tokens=385warden.cost_usd=0.136806warden.latency_ms=15073
Export
Set OTEL_EXPORTER_OTLP_ENDPOINT (and optional OTEL_EXPORTER_OTLP_HEADERS) to export to Datadog, Grafana Tempo, Honeycomb, or any OTLP collector.