Inspiration
Every engineer knows the 3 a.m. incident. The pager fires, production is throwing 500s, and the first 30 minutes aren't spent fixing anything — they're spent reconstructing context. Which deploy shipped this? Which merge request? Who wrote it? What did the review say? Which function actually broke, and what else calls it?
The hardest part is that the bug is almost never where the error shows up. An exception surfaces in the API layer, but the real fault lives two or three function calls deeper, in a file nobody has opened yet. That gap — between where a problem appears and where it actually lives — is what makes incident response slow and painful.
When GitLab announced Orbit, the lifecycle context graph, we saw the missing piece. All the context an engineer scrambles to assemble during an incident is already there — connected. Code to merge request, merge request to author, function to caller, fix to the change that reverted it. It just needed an agent that could walk those connections. That agent is Praetor.
What it does
Praetor is an autonomous incident responder. When an incident is filed, it:
- Traverses the lineage — walks the Orbit graph from the incident to the merge request that shipped the change, the author, and the files touched.
- Follows the call chain — uses Orbit's
CALLSedges to trace from the API endpoint where the error surfaced, down through the service layer, to the data layer where the bug actually lives. - Computes the blast radius — queries the incoming
CALLSedges to the faulty function to find every other place it's used, so a reviewer knows exactly what a fix could affect. - Reconstructs the regression history — reads the merge request timeline and detects cases where a bug was fixed once, then silently re-introduced by a later change.
- Proposes the fix — posts a single triage comment containing the root cause, the suspect timeline, the blast radius, and the exact one-line fix, ready for an engineer to apply.
In a representative run, Praetor took a "500 errors on the orders endpoint" incident and — in under a minute — traced it three layers down the call chain to a KeyError in repository.py, mapped both callers in the blast radius, and surfaced the fact that an earlier fix had been overwritten by a later refactor. That last finding is something a human tracing the bug by hand would almost certainly miss.
How we built it
Praetor runs entirely inside the GitLab Duo Agent Platform — no external backend, no servers, nothing to host. It's composed of:
- One orchestrating agent that drives the incident-response sequence.
- Three composed skills —
lineage-traversal,hypothesis-generation, andfix-proposal— each defined as aSKILL.mdfile in the repository. - The GitLab Orbit knowledge graph, accessed via the Orbit MCP server, using the
query_graphandget_graph_schemacommands.
The skills don't hard-code logic — they encode query recipes that tell the agent how to construct the right Orbit traversals (in Orbit's JSON DSL) for each stage of the investigation: outgoing CALLS for the call chain, incoming CALLS for the blast radius, and merge-request traversals for the lineage timeline. Everything is published to the GitLab AI Catalog and licensed MIT.
Challenges we ran into
- Grounding vs. guessing. Early on, the agent could produce a convincing incident analysis without actually querying Orbit — reconstructing the bug from reading source files and then citing the graph anyway. We had to build in explicit verification that real
query_graphcalls were being made, and confirm grounding by checking for genuine graph node IDs in the responses, not just plausible-looking prose. - Learning Orbit's query DSL. Orbit uses a specific JSON traversal grammar, not a familiar query language. Getting the
query_type,nodes,relationships, and filter syntax right took iteration — and we leaned on Orbit's ownget_query_dslandget_graph_schemacommands so the agent could self-correct its queries at runtime when it got the shape wrong. - MCP session reliability. The Orbit MCP connection in the IDE Duo Agent Platform would occasionally drop, and when it did, the agent silently fell back to source-only reasoning. Recognizing that failure mode — and learning to verify the connection before every meaningful run — was a real lesson in how fragile "it worked once" can be.
- Designing an incident the graph could actually solve. To demonstrate that the multi-hop traversal is load-bearing — not a trick that reading one file could replicate — we built a layered scenario where the symptom and the cause sit in different files, connected only by
CALLSedges. That's what proves Praetor needs the graph.
What we learned
The deepest lesson is the difference between retrieval and traversal. Retrieval-augmented generation finds text that looks similar to your query. But in incident response, the cause rarely resembles the symptom — they share almost no text. They're connected, across files, through the call graph, and across the merge request history. You can't embed your way to a connection; you have to walk it. That's exactly what a knowledge graph is for, and it's why Praetor's whole value depends on Orbit rather than on a vector store.
We also learned to be ruthless about honesty in agent design. An agent that sounds grounded but isn't is worse than useless — it's misleading. Building verification into the loop, so the agent only claims what it actually retrieved, turned out to be as important as the traversal logic itself.
What's next
- Wiring Praetor to fire automatically on incident work-item events, so triage begins the moment an incident is filed.
- Extending traversal into Orbit's security domain — tracing vulnerabilities from a SAST finding back to the merge request and author that introduced them.
- Surfacing the traversal visually, so the graph walk an engineer can see becomes part of the incident record.
Built With
- ci/cd
- gitlab
- mcp
- orbit
- python
Log in or sign up for Devpost to join the conversation.