Inspiration

I have a handful of bots I've built over time for different things that interact with my IRC team. So when I started looking at GitLab Orbit, the question that actually grabbed me was: can I point this at my infrastructure to communicate with my team about MR failures?

A pipeline fails, and figuring out which of the last several merge requests actually caused it means manually diffing files, checking timestamps, and guessing. And dropping into an unfamiliar function means grepping for callers, checking blame, piecing together context.

Orbit's knowledge graph makes both of those genuinely solvable instead of just faster-to-google. So I built something that acts on the graph automatically and reports into a channel I'm already watching, instead of one more tool I'd have to remember to open.

What it does

Orbit Triage is a Duo Agent Platform flow that triggers automatically on pipeline failure. It identifies the failing job, pulls the merge request's diff to see what changed, walks the Orbit graph to find recent activity on those files, scores candidates by recency and blast radius, and posts a ranked triage note directly on the merge request - explaining why it picked that culprit, not just naming it. Results also land in my IRC channel, live:

14:01 <Orbit-Fan466> orbitwatch, find_blast_radius
14:01 <@orbitwatch> Orbit-Fan466: querying Orbit graph…
14:01 <@orbitwatch> context-pack: find_blast_radius — 0 dependents, 0 recent MRs
14:01 <@orbitwatch> **`find_blast_radius` — context pack**
14:01 <@orbitwatch> **What it does**
14:01 <@orbitwatch> `Function` in `scripts/orbit_client.py`
14:01 <@orbitwatch> **Depends on it (blast radius)**
14:01 <@orbitwatch> No imports found in the indexed graph — may be a top-level entry point.
14:01 <@orbitwatch> **Recently touched by**
14:01 <@orbitwatch> No recent MR activity found in indexed graph.

That's a real user in the channel asking the bot a question and getting a real answer pulled live from the graph. A companion Duo Chat skill, context-pack, shares the same traversal core: point it at a function name, file path, or GitLab issue, and it returns what the code does, who depends on it, and what recently changed nearby.

How we built it

Both tools share one Python traversal core (orbit_client.py) wrapping Orbit's REST API. The core traversal is two relationship chains: ImportedSymbol -[IMPORTS]-> Definition for blast radius, and MergeRequest -[HAS_DIFF]-> MergeRequestDiff -[HAS_FILE]-> MergeRequestDiffFile for recent file activity.

The flow itself is built as two components: a deterministic step that gathers context from Orbit and the GitLab REST API, and an agent step that reasons over that context to rank candidates and write the triage note. Splitting it this way meant the agent never needed direct tool-calling permissions to query Orbit — it just reasons over data that's already been fetched and verified.

To prove it actually works, not just looks plausible in a demo, I created a real breaking change: renamed a core function and pointed it at a nonexistent API endpoint, let the pipeline genuinely fail, and triggered the flow against it. It correctly identified the responsible merge request, explained the connection between the rename and the specific failing test assertions, and reported the blast radius across every file that imports the changed module.

The IRC bridge is a deliberately narrow integration: a bot that can do exactly one thing - query Orbit through the same tested context-pack logic and nothing else. No general-purpose model in the loop, no access to anything outside this project's own indexed graph. That mattered to me specifically because the bot runs on the same infrastructure as my personal assistant bots.

Challenges we ran into

Two real bugs surfaced during testing, and they're worth describing honestly rather than glossing over.

An early version of context-pack only retrieved a function's definition content via its first dependent's attached graph data. Any function with zero current importers, a completely normal state for new or internal code incorrectly reported "definition not found," even though the function clearly existed. The fix was a standalone, direct definition lookup, independent of blast radius.

The same tool's free-text token extraction was initially too permissive. A real visitor in the IRC channel asked a general question about the project instead of naming a specific function, and the extraction logic pattern-matched a common English word as a code identifier, queried Orbit, and returned a confidently wrong answer pulled from an unrelated indexed project. The fix was a stoplist applied before any graph query runs and a recognition that "I couldn't find a specific function or file reference" is a far better answer than a wrong one delivered with confidence. The same visitor came back later and got correct answers including the exchange above.

Beyond the code itself, getting the Duo Agent Platform flow's YAML schema right took real trial and error, the toolset field turned out to be reserved for GitLab-native tools only, not a path to Orbit's MCP interface, which led to redesigning the flow around a deterministic-step-plus-agent architecture instead of relying on agent-side tool calling.

Accomplishments that we're proud of

Getting failure-triage to correctly diagnose a real, self-inflicted production failure and explain its reasoning in a way a developer could act upon. Catching both definition-lookup and token-extraction bugs through real usage, including from a real stranger in my channel, rather than assuming the first working version was correct. Building a public-facing IRC integration that's genuinely scoped to nothing but this project's own graph, with no path to any other data, even though it's built on top of a much larger personal automation stack I've been running for a while.

What we learned

That a knowledge graph is only as useful as the discipline around what you let an agent decide versus what you fetch deterministically and hand it as fact. The biggest reliability gains came not from prompting better, but from moving graph queries out of agent reasoning entirely and into verified, testable code, the agent's job became ranking and explaining, not deciding what to trust.

What's next for Orbit Triage with IRC Notification

  • Tighter scoping on Orbit queries to a single project by default, since results currently span every project a token can access
  • Extending the IRC bridge's stopword/intent detection with a small constrained model layer that only rephrases already-fetched Orbit data, never deciding what to fetch
  • A second flow trigger on merge-request-ready events, to surface blast radius proactively before merge rather than only after a failure

Built With

Share this project:

Updates