-
-
Registered in GitLab's AI Catalog, public, and wired to fire the moment a merge request is marked ready. No setup per project.
-
Marked ready, flow fired in seconds. Named functions, exact lines, confidence level - all from the graph before anyone opened the diff.
-
Graph shows who depends on what you just changed including three other projects. And it caught a conflicting MR before either one merged.
-
A docstring change. Three other projects, 14 files. No diff reader catches that - only because Orbit's graph spans the whole group.
-
Suggested reviewers from graph data, the Reviewer Brief - a second comment, one paragraph, posted automatically seconds after the passport.
Inspiration
Every code review starts the same way - you open a diff and try to figure out what it actually means. Not just what changed, but what depends on it, whether it's safe to merge, and whether someone else is about to step on the same code. That manual investigation falls on the reviewer every single time, and it gets skipped when people are busy. I wanted to see if Orbit's Knowledge Graph could do that work automatically, before anyone even opens the diff.
What it does
Orbit Change Passport is a GitLab Duo Agent Platform flow that fires the moment a merge request is marked ready for review. It queries Orbit's Knowledge Graph and posts a structured comment with everything a diff never shows you:
- Changed Surface - the exact functions and methods the diff touched, identified by name with a confidence level showing how the graph found them
- Dependency graph - a live Mermaid diagram of everything that imports the changed modules, rendered inline in GitLab
- Conflict Radar - scans every other open MR right now for ones touching the same code, so collisions show up at review time instead of merge time
- Cross-project blast radius - files in other projects in the group that depend on what changed, only possible because Orbit's graph spans the whole group
- Test gaps - test files that import the changed module but were not touched in this MR, flagged as possibly needing updates
- Suggested reviewers - people who have recently worked on the files that depend on what changed
- Reviewer Brief - a second shorter comment posted immediately after the passport: one paragraph with the single most important thing a reviewer needs to know before reading the diff
A companion Duo Chat agent ("Ask Orbit about this Passport") lets reviewers ask live follow-up questions against the same graph - "what else calls this?", "who imports this file?" - and get graph-backed answers without leaving GitLab.
How we built it
The core is a GitLab Duo Agent Platform custom flow registered in the AI Catalog. The agent uses the standard GitLab API tools alongside query_graph and get_graph_schema to talk to Orbit directly.
The Changed Surface algorithm works in three tiers. It first tries a DEFINES traversal (File to Definition edge in the graph), falls back to an fqn-fragment query if that returns nothing, and falls back again to a bounded page scan. Each tier produces a different confidence level in the output table.
For dependents, the agent runs ImportedSymbol lookups in both FQN and crate-relative forms for Rust files, and by identifier_name stem for Python files - a pattern we found by reading Orbit's actual stored data structure for relative package imports. Cross-project results come from running the same queries without a project_id filter, then excluding the originating project.
The Reviewer Brief is a second call to create_merge_request_note within the same agent turn - not a separate flow or a chained component. We reached this design after two other approaches failed in live testing, which led to the architecture described under Challenges.
We also built a Python engine (engine/) that runs the full algorithm directly against the live Orbit graph. It served as the proof-of-concept and stress-test layer before the flow was wired up, and it can post a passport to any MR from the command line.
Challenges we ran into
The biggest one was a platform behavior we had not expected: when two ambient flows in the same project are registered on the same trigger event, only the most-recently-enabled one fires. The other is silently skipped. We confirmed this by isolating each flow and watching it fire cleanly alone, then re-enabling both and watching one disappear. The fix - making the passport and the brief two sequential tool calls inside one component - turned out to be simpler and more reliable than anything we had tried before.
The second challenge was query availability. While testing the engine, we found that DEFINES traversal, IMPORTS, CALLS, and Definition filtering had each independently been unavailable within a two-hour window on the live instance. A flow that only works when one specific query is live is not useful, so the algorithm degrades gracefully through the three tiers rather than failing.
We also hit a UnicodeDecodeError that only appeared when stress-testing against a large real-world Rust codebase. Three subprocess.run() calls were defaulting to Windows' cp1252 codec, which cannot handle UTF-8 content in real commit data. It never surfaced in our own repo's test files - only when we pushed against actual production data. Fixed by forcing encoding="utf-8", errors="replace" on all three calls.
Accomplishments that we're proud of
The cross-project blast radius is the one that surprised us most. By dropping the project_id filter from the ImportedSymbol query, you surface files in completely different projects that depend on what you just changed. No diff-reading tool can do that. We proved it live: a docstring-only change to engine/orbit_client.py showed 14 dependent files across three other projects.
The Conflict Radar also came through in a real scenario during recording. The passport on MR !5 correctly caught MR !4 as a conflict - two open MRs touching the same two functions at the same time, flagged automatically before either was merged.
On the Contribute Track side, MR !1679 was merged into the main gitlab-org/orbit/knowledge-graph repo, documenting the mcp_orbit OAuth scope that Gemini CLI needs for native HTTP MCP transport - a gap we found while setting up our own Orbit access.
What we learned
Building against a live graph rather than a mock exposed gaps that synthetic test data never would. The query availability issue, the codec bug, and the Python import path structure (relative imports stored with identifier_name eq the module stem, not as a dotted path) - none of those showed up until we pushed against real Orbit data. research/findings.md in the repo is a record of every query pattern we confirmed and every assumption we had to adjust.
On the platform side, debugging the silent-skipping issue by querying aiFlowTriggers directly via GraphQL introspection was the right call. Trying to infer which flow had the active registration from what comments appeared and when would have taken much longer.
What's next for Orbit Change Passport
The flow currently handles Python and Rust because those are the import patterns we confirmed against the live graph. Expanding to JavaScript/TypeScript ESM imports and Go packages would cover most of the remaining ecosystem.
The risk score thresholds are reasonable defaults but could be tunable per project. A low-level utility library has a different risk tolerance than an application layer.
The suggested-reviewers feature uses recent commit authorship on dependent files. Combining that with CALLS-edge data from the graph - people who directly call the functions that just changed - would make the suggestions more precise.

Log in or sign up for Devpost to join the conversation.