DEV Community

Cover image for AI Agent Finds Code: Engineering Code Navigation in Multi-Repo, Multi-Stack Projects
WonderLab
WonderLab

Posted on

AI Agent Finds Code: Engineering Code Navigation in Multi-Repo, Multi-Stack Projects

Preface

Most AI coding assistant demos start from a hidden assumption: the code is right there, and the Agent just needs to read it and modify it.

In real enterprise development environments, this assumption often doesn't hold.

An automotive software company might maintain a structure like this: dozens of independent Git repositories for each Android app module (settings, AC, navigation...); the Android system framework split into hundreds of sub-repositories in AOSP style, managed by repo and Manifest files; QNX with its own Manifest; MCU firmware in a completely separate repository.

When an AI Agent receives an instruction like "fix the Bluetooth disconnect bug," its very first question is not "how do I fix the code" but "where is the code?" The difficulty of this question is severely underestimated.


Three Progressive Levels of Challenge

Level 1: Repo Discovery

The most obvious difficulty: with dozens or hundreds of repositories, how does an Agent know which one to go to?

Some teams write natural language descriptions for each repository, telling the Agent what it does. This is a reasonable starting point, but has several systemic limitations:

  • Natural language descriptions are hard to match precisely, especially when task descriptions and repository descriptions use different terminology
  • Descriptions easily go stale as code evolves, creating ongoing maintenance costs
  • No structured metadata means the Agent can't filter by tech stack or business domain
  • For large AOSP-style Manifest repositories, there's still a gap between "what this Manifest manages" and "which sub-repository contains this specific feature"

Level 2: Cross-Repo Dependency Identification

Real business requirements often span multiple repositories across multiple tech stacks. An "AC temperature setting" feature might require this chain:

Android Settings App (application repo)
    ↕ IPC / AIDL
Android System Service (framework sub-repo)
    ↕ HAL Interface
BSP HAL Implementation (BSP sub-repo)
    ↕ Low-level communication protocol
MCU Firmware (MCU repo)
Enter fullscreen mode Exit fullscreen mode

If an Agent only finds the application repo and modifies the UI logic without realizing that the lower-layer interfaces also need to change, it produces an incomplete fix that will fail integration testing.

This problem can't be solved with single-repo descriptions alone — it requires explicitly modeling dependencies between repositories.

Level 3: Repo Fetch and Context Construction

After finding the right repository, the Agent needs to actually "get the code."

For single application-layer repositories, git clone is enough. But for AOSP-style codebases, the process is:

  1. Fetch the Manifest repository
  2. Determine which sub-repositories this task needs (full sync is prohibitively expensive in time, storage, and bandwidth)
  3. Execute repo sync -c with a curated list of sub-repositories
  4. Understand cross-sub-repo code dependencies

This requires far more from the Agent's tooling than a simple git clone.


Solution Direction 1: Structured Repo Registry

Upgrade current free-text descriptions to a structured Repo Registry, where each repository entry is a YAML object:

repo_id: android-app-settings
display_name: Settings Application
tech_stack: android-app
component_type: application
business_domains:
  - system-settings
  - wifi
  - bluetooth
  - display
fetch_type: git-single
fetch_url: ssh://gerrit.example.com/settings-app
dependencies:
  - android-framework-systemui
  - android-bsp-display-hal
owners:
  - team: android-app-team
Enter fullscreen mode Exit fullscreen mode

The core value of structure: the Agent can filter precisely by tech_stack and business_domains rather than fuzzy-matching through reams of natural language; the dependencies field provides the foundation for cross-repo linkage.

Cross-Stack Dependency Graph

Building on the Repo Registry, explicitly maintain dependency relationships between repositories. When an Agent locates one repository, the platform can automatically query the dependency graph and suggest related repositories that may also need changes.

Dependency relationships come from two sources:

  • Manual annotation: Marked by people who understand the architecture — accurate but has maintenance costs
  • Build system export: The AOSP build system knows which modules depend on which interfaces, so semi-automated extraction is theoretically possible

Standardized Repo Fetch Protocol

Elevate "how to get this repository" from natural language to a machine-executable fetch spec:

fetch_type: repo-manifest
manifest_repo: ssh://gerrit.example.com/platform/manifest
manifest_branch: main
required_projects:
  - platform/frameworks/base
  - platform/packages/apps/Settings
sparse_checkout: true
Enter fullscreen mode Exit fullscreen mode

The Agent calls a unified fetch tool provided by the platform, passing repo_id. The platform executes the actual code fetch according to the fetch spec, hiding the underlying git/repo differences from the Agent.


Solution Direction 2: Pre-Populated Workspace

An alternative approach: don't change any repository organization; pre-sync all repository code to a shared workspace that Agents can directly access. When an Agent starts, it doesn't need to download anything — it directly searches and modifies code locally.

This approach solves two problems:

  • Eliminates repo discovery — all code is in one filesystem, search tools work across all stacks
  • Eliminates download wait — code is pre-populated, Agents can start immediately

But it doesn't solve the token consumption problem. Code being local ≠ code being in the Agent's context window. The Agent still needs code search tools to locate relevant files and selectively load small amounts of relevant code snippets. The need for code search tools is identical under the pre-populated approach versus the multi-repo approach.

Another counter-intuitive issue: larger search scope also means more noise. In the multi-repo approach, the Agent searches after already narrowing to the correct repository, giving a small candidate set. In the pre-populated approach, the same keyword might hit hundreds of files across the full codebase.

Key Engineering Considerations

Hundreds of GB of code shouldn't be copied for each Agent instance. A sensible architecture:

Read-only shared mirror (full codebase)
    ↓ OverlayFS (Copy-on-Write filesystem)
Agent workspace (thin layer storing only write-operation deltas)
Enter fullscreen mode Exit fullscreen mode

Each Agent instance has zero download cost for reading code, and writes are isolated to its own thin layer. This approach has mature implementation paths in Kubernetes container environments.

Submitting back to original repositories requires dedicated design: after the Agent completes changes, the platform needs to identify which files belong to which original repository, split the changes, and submit them through each repository's code review process.


Comparison of Approaches

Dimension Multi-Repo + Structured Registry Pre-Populated Workspace
Repo Discovery Improved via Registry Completely eliminated
Download Wait Required per task Completely eliminated
Cross-layer Search Requires cross-repo operations Direct local support
Token Efficiency Needs code search tools Same — problem not solved
AOSP Compatibility Fully compatible Fully compatible
Storage Cost On-demand download Hundreds of GB + OverlayFS
Submit Back to Repos Natural Platform must split changes
Implementation Difficulty Low, progressive improvement Medium, infrastructure is mature

Core conclusion: Neither approach can bypass the fundamental need for good code search and navigation tools.


Solution Direction 3: Code Knowledge Graph

Regardless of how repositories are organized, the fundamental constraint on Agents in code work is that the context window can't hold a large codebase — relevant code snippets must be selectively loaded. That "selection" itself consumes tokens.

The code knowledge graph approach: proactively build a database of code structural relationships using static analysis, turning relationships that would require reading many files to infer — who calls whom, where interfaces are implemented, how modules depend on each other — into directly queryable structured data.

Layered Analysis with Manageable Costs

Different analysis layers have very different costs:

Analysis Layer Content Tools Cost
Symbol index Definition locations for functions/classes/variables tree-sitter, very fast Low
Call graph Which functions call which functions clangd / language server Medium
Interface-to-implementation mapping AIDL/HIDL interface-to-implementation relationships Static analysis + rules Medium
Module dependency graph Module/library-level dependencies Build system export Low
Semantic vector index Vector representations of code semantics Embedding models High

For hundreds of GB of code, symbol indexing + call graph + interface mapping using tree-sitter and clangd runs at millions of lines per minute — full analysis may take hours, but it's a one-time offline cost.

For semantic vector indexing, use selective coverage: only embed public interfaces, header files, and critical module code. Implementation file internals can be handled on demand.

High-Value Query Scenarios

Scenarios where the knowledge graph gives precise answers and saves large amounts of tokens:

  • "What implementation classes does this AIDL interface have?" → Interface mapping returns directly
  • "Which modules call AudioFlinger::setStreamVolume?" → Call graph returns directly
  • "Which upstream modules would be affected if this HAL interface is modified?" → Dependency graph reverse query
  • "Which file and line is this function defined on?" → Symbol index returns directly


For automotive software (the typical App → Framework → HAL → MCU cross-layer analysis), the knowledge graph is especially valuable — AIDL/HIDL interfaces are explicit contracts between layers, and static analysis can accurately build the complete graph of "interface definition → interface implementation → interface callers," which is exactly what Agents need for cross-layer code modifications.

Technology Stack Recommendations

Function Recommended Tool Rationale
C/C++ symbols and call graph clangd + bear (compilation database) Most mature for AOSP scenarios
Java/Kotlin symbol analysis tree-sitter-java Covers application layer
Multi-language symbol index tree-sitter Supports C/C++/Java/Kotlin, fast
Graph storage Neo4j or DGraph Naturally suited for call relationship queries
Semantic vector index Qdrant + CodeBERT (local deployment) Avoids embedding API costs
Interface-implementation mapping Custom rules + AIDL/HIDL parsing Generic tools don't understand Android HAL semantics

Unresolved Issues

Ongoing metadata maintenance: The Repo Registry is statically maintained, but repository responsibilities change as projects evolve. Ideally, this information would be maintained dynamically in a developer platform, with Agents querying through protocols like MCP rather than maintaining local static files.

Externalizing tacit knowledge: Cross-stack dependencies (especially the full call chain from App layer to MCU layer) currently exist primarily in senior developers' heads. Structurally encoding this tacit knowledge into dependency graphs requires expert input from each tech stack — it's not automatically solvable.

Multi-repo task Agent collaboration: When a task spans Android applications, system framework, and MCU repos, should all three code changes be made by a single Agent, or by multiple specialized Agents that then converge? This involves Agent Platform architecture design with no clear answer yet.


Summary

Code navigation across multiple repositories and tech stacks is the most underestimated engineering challenge when landing AI Agents in enterprise development environments. Solutions can progressively tackle three layers:

  1. Structured Repo Registry: Upgrade natural language descriptions to machine-processable YAML metadata, explicitly establish cross-repo dependencies — the lowest-cost starting point
  2. Pre-populated workspace: Eliminates repo discovery and download wait, suitable for scenarios with frequent Agent task invocation; requires OverlayFS and infrastructure support
  3. Code knowledge graph: Fundamentally changes how Agents access code relationships, turning "read files to infer" into "query database directly"

Regardless of which direction is chosen, one thing is constant: an Agent's ability to locate relevant code segments depends on the quality of search and navigation tools, not on the physical location of the code.


Visit PrimeSkills — a curated AI Agent and skills marketplace where all content is validated through real enterprise workflows. No hype, just what actually works.

For more practical knowledge and interesting products, visit my personal homepage

Top comments (0)