Depcon
Pre-commit hooks that don't just read your code — they run it, watch it, and tell you exactly what broke.
Inspiration
Every developer has shipped a bug that a linter didn't catch. Pre-commit hooks are great for style and type errors, but they fundamentally can't tell you whether your service actually works — they never run it.
We kept asking: what if the pre-commit hook didn't just read your code, but ran it, watched it with real observability, and had an AI agent diagnose what broke? That's the gap Depcon fills.
The industry talks about "shifting left" — catching problems earlier in the dev cycle. We pushed that all the way to before the commit exists. If Dynatrace can tell you what's wrong in production, why not let it tell you at git commit time instead?
What We Built
Depcon is a pre-commit hook that wires Dynatrace observability and Gemini AI into the commit workflow:
git commitfires the hook- The service spins up in Docker, fresh
- Smoke tests fire against it — recording exact timestamps
- If anything fails, a Google ADK + Gemini 2.0 Flash agent loop starts
- The agent queries the Dynatrace MCP server for what actually happened during the test window — error logs, anomaly events, error spans — all scoped to the 30-second test run, not the full tenant history
- Gemini synthesises a root cause hypothesis, maps it back to the staged diff, and generates a fix patch
- The commit is blocked with the diagnosis. One command —
depcon fix apply— patches the file. Re-commit passes.
The key insight: Dynatrace is the brain of the system. Without the telemetry, the agent is guessing. With it, the diagnosis is grounded in what actually executed.
How We Built It
Depcon is a Python CLI built with Typer and Rich for terminal output, with a parallel FastAPI + SSE web dashboard for visual demos.
Agent loop — Google Cloud Agent Builder (ADK) manages the Gemini iteration cycle. We registered the Dynatrace MCP tools — get_problems, query_logs, query_traces — as ADK tool functions. The MCP server (@dynatrace-oss/dynatrace-mcp-server) runs as a local subprocess over stdio; our Python wrapper connects to it using the mcp SDK.
Target service — examples/fastapi-service/ is a FastAPI app fully instrumented with OpenTelemetry, exporting traces and logs to Dynatrace via OTLP. It includes CHAOS_MODE fault injection (error, panic, latency) so we can trigger and demo specific failure scenarios on demand.
Web dashboard — streams the agent's raw reasoning live to the browser via Server-Sent Events, so you can watch Gemini work through the Dynatrace data in real time.
Challenges
Dynatrace MCP connection
The newer apps.dynatrace.com platform uses DT_ENVIRONMENT (a full URL) rather than DT_ENVIRONMENT_ID, which the docs weren't explicit about. We discovered this by running the server manually and reading the startup error.
Async SSE streaming
Streaming agent output through SSE required careful async generator composition — the ADK event loop, the MCP stdio subprocess, and the FastAPI response generator all had to stay in sync without deadlocking. Python's @asynccontextmanager has a subtle "generator didn't stop after athrow()" failure mode when exceptions propagate through nested async context managers; we had to manually manage the MCP session lifecycle to work around it.
Cross-platform git apply
Making git apply work reliably on Windows was surprisingly finicky. AI-generated fix diffs sometimes lacked a trailing newline, and CRLF line endings in the working tree caused context mismatches. We added a normalisation step that tries progressively more lenient git apply flags until one works.
Structured agent output
Prompt engineering for reliable JSON output took several iterations. The agent needed to consistently emit a Diagnosis object as its final message regardless of what it found. The winning structure: explicit schema in the system prompt, explicit instruction to emit only JSON as the last message, and no markdown fences.
What We Learned
Dynatrace DQL is expressive. Scoping every query to a precise test window (start/end ISO timestamps) was essential for relevance — querying the full tenant history would return noise from unrelated services.
Google ADK's event model is clean once you understand it. The Runner, InMemorySessionService, and event streaming fit together well. The is_final_response() event pattern is the reliable way to extract the model's final output.
Shifting left has a UX problem. If the tool is slow or noisy, developers will bypass it with --no-verify. We spent real effort on the fail-open policy (never block for infrastructure reasons), a sub-90-second runtime budget, and clean terminal output — because a pre-commit tool that annoys you is worse than no tool at all.
MCP as a standard protocol paid off. We could swap the observability backend with zero agent code changes. If Dynatrace adds new tools to their MCP server, the agent can use them immediately.
Log in or sign up for Devpost to join the conversation.