user@elrise.io:~
2026-07-2018 min readcode-intelligencestatic-analysisobservabilityaideveloper-tools

This article grew out of work on a private autonomous multi-agent development system I run alongside my main projects. The six evidence layers and the rollout plan are not an abstract model — they are a contract that survived its real scenarios: polyglot code search for agents, separating evidence from actor in memory, retention in telemetry for long-running sessions, and mandatory traceability of every agent-driven change down to a commit.


Code intelligence stack 2026: building a map of the code, not a collection of AI toys

In a large codebase, the question “where is this function defined?” quickly turns into an investigation. You need to find every implementation and every caller, understand dependencies, check static violations, correlate code with real production behaviour, and then verify that the change didn’t break a neighbouring service. In a monorepo or a polyglot system this is no longer a job for plain grep, and no longer a job you can safely hand to a single chatbot.

By code intelligence I mean not a specific AI product, but a closed loop of six kinds of facts:

  1. Text and symbol facts — search across files, branches, commits, and definitions.
  2. Static facts — AST, types, data-flow, dependencies, and rule violations.
  3. Dynamic facts — traces, profiles, latency, errors, and load behaviour.
  4. Operational facts — logs, metrics, release-to-incident correlation, and retention.
  5. Relational / knowledge-graph facts — code-as-data queries, typed recipes, inter-repo symbol links, and multi-hop questions.
  6. Generative interpretation — an LLM that answers questions only over the layers above and shows the evidence behind its output.

The first five are the evidence layers around a single CODEBASE; the LLM is the actor that interprets them, not a sixth source of evidence. The illustration below visualises that contract.

I compared tools across six axes: code search, static analysis, runtime tracing, log aggregation, LLM-assisted investigation, and knowledge-graph code models. The primary sources were last verified on 2026-07-20. Where the data moves quickly, that is called out explicitly.

TL;DR

If you want a practical starter set rather than a marketing list, I would begin like this:

This list does not say “install everything”. First decide which question you want to make cheap: find a symbol, catch a vulnerability, explain latency, or verify a change through an LLM.

How to choose: maturity over stars

For each tool I used four filters:

“Mature” here means a stable production scenario and not in beta or maintenance mode (where the project is frozen). It is not a promise of zero bugs. Conversely, a beta tool may be fast and convenient, but it should not be put into a blocking gate (a CI check that fails the build) without explicit observation. But you already know that.

1. Code search: find the facts first

Code search is the most under-rated layer. Before you build a graph or wire an LLM, you must be able to answer “where is it declared”, “who calls it”, “in which branch did it change”, and “does the same problem exist in a neighbouring repo”.

Sourcegraph and Zoekt

Sourcegraph Code Search is the practical choice for the enterprise tier when you care about multi-host, multi-branch, multi-commit search, symbol search, batch changes, and a Cody layer on top of the index. Its strength is not just string search — it is a unified interface for cross-repo investigations. The cost of that depth is the commercial model, opaque pricing, and a separate privacy review for SaaS or AI features.

Zoekt is Apache-2.0 and a good base for an OSS-only scenario. It is a trigram-based engine that powers Sourcegraph Code Search. It is fast across large code volumes, supports regexp, boolean queries, and symbol ranking. Zoekt by itself is not a drop-in replacement for the full Sourcegraph platform: UI, repository sync, auth, and ops still need to be assembled.

The choice is simple: if you need a finished enterprise product and the licence works — Sourcegraph; if you value control over the data and have a team to integrate a platform — Zoekt.

OpenGrok and livegrep

OpenGrok stays a reasonable choice for Java-heavy and legacy environments. It has cross-references, multi-language support, web UI, and API. The downside is the JVM stack, the cost of full reindex, and tuning for very large repositories. The licence mix also needs review: the project is CDDL-1.0 with mixed components.

livegrep is narrower but convenient for a single-tenant setup. It is fast regex search across gigabytes of source with re2 and mmap indices. It fits an internal “Google Code Search” when you do not need a complex permission model or multi-repo semantics.

Hound is worth considering only if you need a very small deployment footprint and tolerate maintenance mode. I would not make it the base of a new strategic layer.

What not to do

Do not start with semantic search if you cannot do exact text and symbol search. Otherwise the LLM will paraphrase an incomplete index nicely, and the team will not be able to verify the answer with a simple re-query.

2. Static analysis: split fast feedback from deep investigation

Instead of one “magical” analyser, separate work by cost.

The practical shape: Ruff and local Semgrep rules give fast feedback; CodeQL and deep taint analysis run in CI; SonarQube collects cross-repo quality. Every finding must have an owner, a severity, a suppression reason, and a review date. Otherwise the tool just produces backlog.

3. Runtime tracing and profiling: code explains intent, production shows the fact

Static analysis does not show which branch actually runs or where time is spent. For Linux-native systems the base is perf (the Linux profiling subsystem) events, perf, ftrace, and Brendan Gregg’s tooling. They give hardware counters, kernel tracepoints, kprobes, uprobes, and USDT with low overhead.

bpftrace is convenient when you need a quick diagnostic query without a separate C program: syscalls, locking latency, network events, or process behaviour. It is mature, but it requires Linux with BPF support and is not a replacement for a full continuous-profiling system.

For JVM workloads you want async-profiler. It captures CPU and heap profiles, works with native frames, JIT, and GC threads, and can export to JFR and flame graphs. For a Java service this is usually a more useful starting point than a universal agent for every language.

For continuous profiling you can pick Pyroscope or Parca:

A profile without context is useless. Every measurement must be tied to the build version, the service, the environment, and the time window. Otherwise the flame graph becomes a picture without causality.

4. Logs and observability: data standard first, then backend

The biggest observability decision is not “Loki or Elastic” — it is whether you will still be able to swap the backend without rewriting instrumentation.

OpenTelemetry is the first layer to put in. It is a vendor-neutral model, SDK, and Collector for traces, metrics, and logs. OpenTelemetry does not store data and is not a search system, but it establishes common semantic conventions, routing, and the boundary between the application and the backend.

The next choice depends on the shape of queries:

For self-hosted SaaS, AGPL may be acceptable, but embedding a component in a closed commercial product requires a legal review. Also decide retention, data residency, erase workflow, and log access in advance. You cannot promise deletion if the storage cannot reliably find and remove every copy.

5. LLM-assisted investigation: the model is not the source of truth

An LLM is useful when it shortens the path from a question to verifiable facts. It is dangerous when it produces confident explanations over an incomplete index.

Aider is a strong OSS option for terminal-based work. It builds a repository map, works with different models, can run lint and tests automatically, and commits the changes. Its natural role is a guided CLI helper, not an autonomous production deployer.

Cursor is convenient as an enterprise IDE, and Sourcegraph Cody is a natural fit for teams already on Sourcegraph that want to feed its code graph to the model. Both come with a price: commercial dependency, vendor-specific indexing, and the need to verify where source code, prompts, snippets, and search results are sent.

Devin is positioned as an autonomous coding agent for end-to-end tasks (issue → patch → PR). As of 2026-07 it remains a commercial product with a closed runtime; for code-intelligence scenarios it is best treated as a black box — there are no links to intermediate evidence, and a reproducible trace requires a separate vendor agreement.

Continue.dev can no longer be recommended as a base for new installations: per the continuedev/continue README, the repository is no longer maintained and is left read-only after the final 2.0 release. It is useful as a historical reference for prompt patterns, but it is not a current deployment target.

A minimum guardrail for any LLM tool:

  1. the model only sees the repositories and branches it is allowed to see;
  2. every answer includes links to files, symbols, commits, or runtime traces;
  3. changes land in a diff first, not directly in production;
  4. lint, tests, SAST, and secret scanning run after generation;
  5. access to sensitive code, logs, and personal data goes through a separate review.

If the model cannot surface evidence, it is a hypothesis, not a finding.

6. Knowledge graph: different graphs answer different questions

The term “code knowledge graph” is used for three different things.

OpenRewrite builds a Lossless Semantic Tree and applies type-aware recipes. It is a strong choice for mass refactoring and framework migrations: instead of a regex replace, the tool understands the structure of the program and can re-apply the recipe across multiple repositories. Parser maturity varies by language — Java is usually better covered than newer ones.

CodeQL stores code in a relational model that can be used in practice as a knowledge model: queries express relationships between data sources, calls, types, and sinks. Especially useful for security and cross-repo searches for vulnerable patterns.

SCIP is the Sourcegraph Code Intelligence Protocol index format. It is useful as an interoperability layer: separate language indexers can publish symbols and relationships in a common format. The SCIP ecosystem is still mostly tied to Sourcegraph.

Sourcegraph Code Graph is a commercial production-grade graph for cross-repo symbol navigation and AI-grounded Q&A. It is most valuable when you already have Sourcegraph-scale code search. For a small repo, a separate graph is almost always over-engineering.

The practical rule: a graph is for relationships and multi-hop questions — “which services depend on this type?” or “which calls lead to this sink?” — not for every string search. For local fact lookup, the plain index is faster, cheaper, and easier to verify.

Reference architecture

A minimal production shape can look like this:

Git repositories
-> Zoekt or Sourcegraph index
-> SCIP and symbol metadata
-> Semgrep, CodeQL, SonarQube, Ruff
-> OpenTelemetry Collector
-> logs, traces, profiles
-> Loki, Quickwit, OpenObserve, or Elastic
-> Aider, Cody, or another guarded LLM interface
-> diff, tests, SAST, reviewer

The sequence matters. The LLM should not be the first link. First build the indexes and the telemetry contracts, then add a model that can go from a question to evidence. If you swap the order, you get an expensive chat with stale context, not code intelligence.

Three practical deployment profiles

On the diagram above, compliance-sensitive concerns are shown as a horizontal overlay across both main profiles rather than a third column. Compliance is orthogonal to the tool choice: you can run OSS or GitHub-centric, and in both cases you can enable a compliance-sensitive mode. The two questions — which vendor mix? and which compliance posture? — are independent.

OSS-only and self-hosted

Zoekt, Semgrep OSS, CodeQL CLI, Ruff, perf/bpftrace, OpenTelemetry, Loki or Quickwit, Aider, and OpenRewrite. This gives you control over code and data, but requires in-house work on auth, indexing, UI, retention, and upgrades.

GitHub-centric enterprise

Sourcegraph or GitHub-native search, CodeQL, Semgrep, SonarQube, OpenTelemetry, the chosen observability backend, Cody or Cursor. Faster to start, but you have to nail down SaaS boundaries, indexing cost, and an exit plan (a playbook for migrating off the vendor).

Compliance-sensitive production

Start not with an LLM, but with a data map: which repositories, logs, and profiles contain personal data, where they are stored, who has access, and how deletion requests are executed. Then pick self-hosted indexing, an OpenTelemetry Collector with filtering, a backend with clear retention, and only then an AI tool with a verified data-handling policy.

Four-stage rollout plan

  1. Stage 1 — inventory. Lock in languages, repositories, branches, owners, recurring investigation questions, and data classification. Pick one pilot repository.
  2. Stage 2 — static baseline. Wire up Ruff or a language-native linter, Semgrep, and one deep analyser. Strip the noise, assign owners, and start a regression corpus.
  3. Stage 3 — runtime loop. Turn on OpenTelemetry, collect minimal traces and logs, add perf or async-profiler for one critical service. Tie every event to a build revision.
  4. Stage 4 — guarded AI. Connect Aider, Cody, or Cursor only to the pilot scope. Require citations, diff, tests, and security checks. Compare model answers against a fixed investigation set.

After the pilot, measure not the number of tools or token spend, but time-to-find, time-to-explain, the share of findings with reproducible evidence, the false-positive rate, and the time from a runtime signal to a fix.

Exit gates

Each stage on the diagram ends with an explicit exit gate. The next stage starts only when the gate is satisfied — this is a sequencing rule, not a calendar rule. A gate is a one-line verifiable criterion, not a goal:

If a gate is not passed, fix the gap first and then continue. The pilot repository and the gates are the only durable artefacts that survive the rollout; everything else can be replaced.

Anti-patterns

What to re-check before publishing

Code intelligence moves quickly, so this article is not a permanent catalogue:

In a field like this, a re-fetch every six months is reasonable, and for commercial AI tooling and compliance-sensitive deployments it should happen before every substantial change.

Sources

Static analysis

Runtime tracing and profiling

Logs and telemetry

LLM investigation and code models

Compliance references

Discussion

Comments (0)

No comments yet.