The Inspiration
Every engineering team I have worked with has the same invisible problem: a merge request sits open for three weeks because everyone assumed someone else had picked it up, and a helper function that got superseded six months ago is still sitting in the codebase being read by every new developer who tries to understand the system. Neither of these shows up on any dashboard. Nobody is tracking them. They quietly cost time every week, until someone manually goes looking — which nobody does, because they are too busy with merge requests and the code that may or may not still matter.
I wanted to build something that founds this cost automatically, without anyone having to remember to look. I turned it into a concrete artefact the team could act on — not a chat reply, an actual GitLab issue with a table and a recommended action.
What it does
Cost Guardian is an Orbit-powered audit tool that runs automatically on every push to main and on a weekly schedule. It queries GitLab Orbit's knowledge graph for two signals:
Signal 1 — Review debt: Open merge requests that have had no activity beyond a configurable staleness threshold. These are the reviews that are quietly blocking someone, or that have been abandoned without being closed.
Signal 2 — Dead weight: Function, class, and method definitions in the codebase that have no detected import references — code that is still being maintained and read, but that nothing actually calls.
The output is always one GitLab issue, created automatically, with both findings in a structured table and one concrete recommended next step. It is not a chat transcript. It is a tracked, assignable, closeable item in the project's issue tracker.
How we built it
The core is a Python script (scripts/cost_guardian.py) that calls the GitLab Orbit API directly at POST /api/v4/orbit/query — no intermediate tools, no external dependencies. Two traversal queries run in sequence: a MergeRequest traversal filtered by state=opened, and a Definition inventory cross-checked against ImportedSymbol nodes to identify unreferenced code. Results are then posted to the GitLab Issues API.
The pipeline is defined in .gitlab-ci.yml — four lines of YAML that run the script on every push to main, every manual trigger, and every scheduled run. The only external requirement is a GITLAB_TOKEN CI/CD variable with api scope.
A custom agent has also been published to the GitLab AI Catalogue (skills/cost-guardian/SKILL.md), which documents the same audit protocol in a form the Duo Agent Platform can follow, providing a conversational interface on top of the same Orbit queries.
Challenges we ran into
The Orbit query DSL has constraints that are not fully documented outside of the schema endpoint itself. Several query shapes that appeared valid from the conceptual description — Cypher-style string queries, edge traversal with edge and target co-properties, filterless traversals — were rejected at runtime with compile errors. Every one of these required diagnosing the actual API response, understanding what the DSL does and does not support, and redesigning the query around what actually works. The get_graph_schema and glab orbit remote tools responses were essential for this — the schema is the ground truth, not the documentation.
The Duo Agent Platform's custom agent runtime was also more constrained than the UI suggested. Tools that appeared enabled in the agent configuration were not available at runtime, which required pivoting from an agent-first architecture to a CI pipeline as the execution layer.
Accomplishments that we're proud of
The tool produces a real, actionable GitLab issue from real Orbit data with zero human intervention after setup. The pipeline passes cleanly, the Orbit queries return genuine graph data, and the issue template is structured enough to be useful rather than decorative. It also handles every failure mode gracefully — if a signal is unavailable, the issue says so explicitly rather than fabricating results.
What we learned
Orbit's knowledge graph is genuinely powerful for SDLC-layer questions — what MRs are open, what code exists, what relationships exist between entities. The constraint is that it measures code structure and development lifecycle, not runtime behaviour or cost. Building something useful on it means finding the right question to ask, not forcing it to answer a question it was not designed for. "Where is engineering time leaking in this project?" turns out to be exactly the right question.
What's next for OrbitLens Cost Guardian
Three concrete extensions, in order of priority:
Scheduled silent runs: Move from push-triggered to a true weekly schedule that only opens a new issue when findings change, so the team sees a new report only when something new needs attention.
Code owner routing: Orbit indexes ownership data. The next version of the report routes each finding to the actual code owner rather than opening a general project issue that everyone has to triage.
CI signal: Orbit indexes pipeline jobs. A third signal — jobs that fail repeatedly on the same step — is the same class of problem as a stale MR: engineering time stuck in the same place every week. This is the natural next addition to the report.
Built With
- ai
- catalogue
- gitlab
- gitlab-ci/cd
- gitlab-duo-agent-platform
- gitlab-orbit
- python
Log in or sign up for Devpost to join the conversation.