Auto-created from discussion #6294 by @pavver (Ideas)
Discussion: Workspace Code Intelligence Layer for Coding Agents
Description
I would like to open a discussion about whether LibreFang should grow a workspace-level code intelligence layer for coding agents.
This is not meant as a finished design or a request to implement this exact architecture.
The first question is whether this direction fits LibreFang at all.
If the direction seems useful, I would like to discuss the right architecture, boundaries, and migration path with the maintainers.
Short version:
This should not be "vectorize the codebase".
It should be a workspace/repository code navigation layer for coding agents.
It should combine structural indexing, lexical search, optional vector search, and optional LSP-backed language intelligence.
The goal is to help agents locate and understand relevant code with fewer blind file_list, grep, and file_read loops.
Main Questions
Before discussing implementation details, I think there are two larger questions.
1. Does this direction fit LibreFang?
Should LibreFang try to improve its coding-agent experience with a workspace/repository code intelligence layer?
In other words, should code navigation become a first-class workspace capability, rather than something every agent rediscovers through repeated filesystem searches and file reads?
2. If yes, what should the architecture look like?
The architecture below is only a starting point for discussion.
I am not attached to the exact shape.
The main idea is to start a design conversation and let a better solution emerge from review and discussion.
Some concrete architecture questions:
- should this live in
librefang-memory, librefang-runtime, or a new crate?
- should workspace/repository state own the index, with agents only receiving scoped access?
- should the first version focus on FTS/repo maps/tree-sitter before LSP and vectors?
- should LSP be managed by LibreFang, or should LibreFang integrate with existing editor/LSP state where possible?
- should code-intelligence tools be ordinary agent tools, context-engine helpers, or both?
- how much context, if any, should be injected automatically?
The rest of this issue describes one possible shape, mainly to make the discussion concrete.
Core Idea
Coding agents need different kinds of code retrieval.
Different questions require different backends:
Where is this symbol defined?
-> prefer LSP
-> fallback to symbol index / tree-sitter / text search
Where is this symbol used?
-> prefer LSP references
-> fallback to reference index / lexical search
What files are relevant to this feature?
-> hybrid lexical search + repo map + optional vector search
What does this repository look like?
-> repo map from structural symbols and dependency ranking
What code is conceptually similar to this request?
-> optional vector search
So the system should not have one universal "code search" mechanism.
It should route each query to the best available backend.
Why
Today, a coding agent usually has to explore a repository through repeated filesystem tools:
- list files;
- search text;
- read files;
- infer structure from partial context;
- repeat when it missed something.
That works, but it is inefficient for large or unfamiliar codebases:
- the agent spends tool calls rediscovering project structure;
- it burns context on file contents that may not matter;
- it may miss relevant files when relationships are not obvious from filenames;
- multi-file changes require better localization;
- multi-repository workspaces are difficult to navigate;
- exact symbol/reference questions are poorly served by vector search alone.
A code intelligence layer would give agents a structured and traceable way to ask for code context.
What This Is Not
This is not primarily a vector database feature.
Vector search can be useful for semantic discovery, but it should not be the center of the design.
Vector-only code retrieval is weak for exact programming questions such as:
- where is this function defined?
- where is this type used?
- what calls this method?
- which implementation of this trait is active?
- which route handler owns this endpoint?
Those questions are better served by LSP, symbol indexes, reference indexes, lexical search, and structural graphs.
The best design is hybrid:
- deterministic text search for exact strings;
- structural symbols for repository maps and navigation;
- LSP for precise language-aware facts when available;
- optional vectors for fuzzy semantic discovery;
- git/file tracking for freshness.
Possible Architecture
Conceptually:
WorkspaceCodeIntelligence
RepositoryRegistry
RepositoryIndex[]
SourceInventory
TextSearchIndex
SymbolIndex
RepoMap
ReferenceIndex optional
VectorIndex optional
LspState optional
BackendHealth
QueryRouter
IncrementalUpdater
Backends:
TextBackend
-> SQLite FTS5 / BM25
StructuralBackend
-> tree-sitter
LanguageBackend
-> LSP, when configured and healthy
VectorBackend
-> optional embeddings for semantic queries
The query router could select the best backend for the task instead of treating every query as a vector query.
Possible Ownership Model
My current assumption is that the code intelligence layer should be owned by the workspace and its repositories.
Agents should not each build their own copy of the same repository index.
Conceptually:
workspace
-> repositories[]
-> code intelligence state
agent
-> access policy
-> search/tool preferences
This would avoid duplicated indexing and prevent different agents from having inconsistent views of the same codebase.
Multi-Repository Workspaces
A workspace may contain several repositories.
Example:
workspace/
backend/ .git
web-frontend/ .git
android-app/ .git
protocol-lib/ .git
These repositories may have different:
- git branches;
- commit heads;
- build systems;
- languages;
- LSP servers;
- ignore rules;
- dependency graphs;
- generated/vendor directories.
So the real indexing unit may need to be a repository root, while the workspace acts as the container.
Conceptually:
Workspace
Repository: backend
CodeIntelligenceState
Repository: web-frontend
CodeIntelligenceState
Repository: android-app
CodeIntelligenceState
Repository: protocol-lib
CodeIntelligenceState
Search results should always include the repository identity:
repo: protocol-lib
path: src/auth/token.rs
symbol: AuthToken
lines: 12..48
source: rust-analyzer
confidence: exact
This matters because the same file names, modules, or class names can exist in multiple repositories.
Per-Agent Access
If the index is shared at workspace/repository level, access should probably be configurable per agent.
Examples:
backend agent:
repositories: backend, protocol-lib
android agent:
repositories: android-app, protocol-lib
web agent:
repositories: web-frontend, protocol-lib
architect:
repositories: all
project manager:
repositories: all
mode: summary/map only
Possible per-agent settings:
- enabled/disabled;
- allowed repositories;
- allowed paths;
- allowed tools;
- max search results;
- whether a small repo map may be auto-injected;
- whether vector search is available;
- whether only summaries/maps are allowed.
Example:
[tools.code_intelligence]
enabled = true
repositories = ["backend", "protocol-lib"]
allowed_tools = ["code_search", "symbol_search", "code_map"]
max_results = 12
auto_repo_map = true
For a project manager:
[tools.code_intelligence]
enabled = true
repositories = ["backend", "web-frontend", "android-app", "protocol-lib"]
allowed_tools = ["code_map"]
mode = "summary_only"
Query Router
I think the query router may be the important design boundary.
It could choose the best backend for the query type:
code_search(query)
-> FTS/BM25 baseline
-> optional vector merge/rerank
-> optional repo-map ranking
symbol_search(name)
-> symbol index
-> LSP workspace symbols, if available
-> lexical fallback
find_definition(symbol)
-> prefer LSP
-> fallback symbol index
find_references(symbol)
-> prefer LSP references
-> fallback reference index / lexical search
code_map(repo/path)
-> structural symbols + dependency ranking
impact_analysis(path_or_symbol)
-> git diff + references + imports/dependencies
This keeps the system honest about which retrieval methods are exact and which are approximate.
LSP Role
LSP could be the preferred backend for precise language intelligence when it is available and healthy.
It can provide things that vector search and syntax-only parsing cannot reliably provide:
- go to definition;
- find references;
- document symbols;
- workspace symbols;
- diagnostics;
- type-aware navigation;
- call hierarchy, where supported;
- module/crate/package resolution.
Examples:
- Rust:
rust-analyzer;
- TypeScript:
typescript-language-server;
- Python:
pyright / basedpyright;
- Kotlin/Android: Kotlin or Android-aware tooling where available.
However, I do not think LSP should be the only foundation.
LSP has real operational cost:
- slow startup;
- indexing delays;
- build-system dependencies;
- language-specific setup;
- varied server quality;
- failures and degraded states;
- heavier resource usage.
Therefore LSP may work best as an optional exact backend with health and fallback behavior.
Suggested LSP health states:
unavailable
starting
indexing
ready
degraded
failed
Tool results should expose provenance:
source: rust-analyzer
confidence: exact
fresh: true
fallback_used: false
or:
source: tree-sitter + FTS
confidence: approximate
fresh: true
fallback_used: true
fallback_reason: rust-analyzer unavailable
Tree-Sitter Role
Tree-sitter could be the robust structural baseline.
It is useful for:
- parsing many languages;
- extracting classes/functions/types;
- building repo maps;
- finding approximate references;
- creating symbol-based chunks;
- supporting languages where no good LSP is available.
It is not a full replacement for LSP because it usually does not understand types, build systems, crate graphs, trait resolution, imports at the same level, or generated code.
It may be a better MVP foundation than LSP because it is more predictable and easier to run inside a runtime service.
Text Search Role
Text search seems like the baseline that should always be available.
SQLite FTS5/BM25 would likely be enough for a first version.
It is deterministic, cheap, and very useful for code:
- function names;
- error strings;
- config keys;
- route paths;
- environment variables;
- type names;
- file names;
- log messages.
Even after adding LSP and vectors, text search should remain a core backend.
Vector Search Role
Vector search should probably be optional.
It is useful for fuzzy questions like:
- where is token refresh logic handled?
- what code looks related to offline sync?
- where is a similar validation flow?
- which files implement this kind of behavior?
It is not reliable enough for exact code intelligence questions by itself.
Embeddings should be stored per chunk hash, not per whole repository.
If one function changes in a large file, only the affected chunk should need a new embedding.
Repository Map
A small repo map can be more useful than large retrieved snippets.
It should contain important files, symbols, signatures, and relationships, with a token budget.
Possible ranking signals:
- symbol reference count;
- import/dependency graph centrality;
- files mentioned in the current task;
- recently edited files;
- failed test/compiler output paths;
- current git diff;
- agent role and allowed repositories.
The runtime could optionally inject a small repo map for agents that opt in.
Detailed code should still be retrieved through tools.
Incremental Updates
The system should be incremental if it supports large workspaces.
Large workspaces can contain millions of lines of code.
Rebuilding the whole index after every commit or branch switch would be too expensive.
The database should track file/chunk/index state, for example:
workspace_id
repository_id
repo_path
repo_relative_path
branch
git_head_sha
file_hash
mtime
size
language
backend_used
indexed_at
For chunks/symbols:
repository_id
path
start_line
end_line
symbol_name
symbol_kind
content_hash
embedding_hash
embedding_model
When a repository changes from one git head to another, the updater can use:
git diff --name-status <old_head> <new_head>
Then:
- deleted files are removed from the index;
- renamed files update their path;
- modified files are re-indexed;
- unchanged files are left alone;
- if git state is unavailable, fall back to scanning and comparing file hashes.
The updater should be background/lazy where possible, not blocking the agent loop on large repositories.
Git and Filesystem Events
The system could notice:
- file writes from LibreFang tools;
- patch application;
- external file changes;
- git commit changes;
- branch switches;
- repository checkout changes;
- manual refresh requests;
- manual rebuild requests.
Possible update strategy:
file_write/apply_patch:
mark affected files dirty or re-index them immediately
git head changed:
compute changed paths and update only those paths
branch changed:
update repository git state and diff from previous indexed head if possible
manual code_intelligence_refresh:
refresh dirty files and verify hashes
manual code_intelligence_rebuild:
rebuild the repository index from scratch
A full rebuild should be reserved for:
- first index creation;
- index schema version change;
- embedding model change;
- corrupted/missing index state;
- explicit user request.
Tools Exposed to Agents
I do not think the model should automatically receive a large pile of retrieved code on every turn.
Instead, coding agents should get tools that retrieve the specific context they need.
Possible tools:
code_search(query, repo?, path?, language?, limit?)
symbol_search(name, repo?, kind?, limit?)
code_map(repo?, path?, depth?)
find_definition(symbol, repo?)
find_references(symbol, repo?)
find_callers(symbol, repo?)
impact_analysis(path_or_symbol, repo?)
code_intelligence_status(repo?)
code_intelligence_refresh(repo?)
This keeps context usage controlled and makes retrieval decisions visible in traces.
Suggested Configuration Shape
Workspace-level configuration:
[workspace.code_intelligence]
enabled = true
auto_discover_repositories = true
auto_update = true
symbol_backend = "auto"
search = ["fts"]
[[workspace.code_intelligence.repositories]]
name = "backend"
path = "backend"
[[workspace.code_intelligence.repositories]]
name = "web"
path = "web-frontend"
[[workspace.code_intelligence.repositories]]
name = "android"
path = "android-app"
[[workspace.code_intelligence.repositories]]
name = "protocol"
path = "protocol-lib"
[workspace.code_intelligence.languages.rust]
backend = "auto"
lsp = "rust-analyzer"
[workspace.code_intelligence.languages.kotlin]
backend = "auto"
[workspace.code_intelligence.fallback]
backend = "tree_sitter"
Agent-level access:
[tools.code_intelligence]
enabled = true
repositories = ["backend", "protocol"]
allowed_tools = ["code_search", "symbol_search", "code_map"]
max_results = 12
auto_repo_map = true
Vector search could be enabled separately:
[workspace.code_intelligence.vector]
enabled = false
embedding_model = "..."
Runtime Safety and Validation
The code intelligence layer should respect existing workspace safety boundaries.
Important constraints:
- do not index files outside allowed workspace roots;
- respect ignore files and configured excludes;
- exclude generated/vendor/build directories by default;
- avoid indexing secrets where possible;
- avoid sending large retrieved snippets automatically;
- make all retrieval visible in traces;
- let agents access only repositories/paths allowed by configuration;
- distinguish exact results from approximate results.
Suggested default excludes:
.git/
target/
node_modules/
build/
dist/
.gradle/
.idea/
.vscode/
vendor/
Debugging and Tracing
The system should emit trace information such as:
repo backend: detected git head change abc -> def
repo backend: 14 files modified, 2 deleted, 1 renamed
src/foo.rs: reused 18 chunks, re-embedded 1 chunk
code_search("auth token") returned 8 results from FTS + vector rerank
symbol_search("AuthToken") resolved via rust-analyzer
rust-analyzer unavailable, falling back to tree-sitter for backend
find_references("AuthToken") used approximate lexical fallback
This is important because retrieval quality becomes part of agent quality.
When an agent misses relevant code, we need to know whether the issue came from:
- stale index;
- bad search query;
- missing backend;
- LSP failure;
- embedding mismatch;
- access restrictions;
- overly aggressive result limits;
- approximate fallback being mistaken for exact language intelligence.
Possible Migration Path
If maintainers think this direction is worth pursuing, I think it should be built incrementally.
Phase 1: Workspace/Repository Registry
- Detect repositories inside a workspace.
- Store repository identity and git state.
- Add config for workspace-level code intelligence.
- Add per-agent access controls.
Phase 2: Lexical Search and Repo Map
- Build file/chunk tables.
- Add SQLite FTS5/BM25 search.
- Add
code_search.
- Add
code_map.
- Update changed files incrementally by hash/git diff.
This phase is useful even without embeddings or LSP.
Phase 3: Tree-Sitter Symbol Index
- Add a structural backend.
- Extract symbols and signatures.
- Create symbol-based chunks.
- Add
symbol_search.
- Improve repo-map ranking with references/imports where available.
This may be a good first structural step because it is predictable and works without running language servers.
Phase 4: LSP Backend
- Add optional LSP process management.
- Add health/readiness state.
- Add fallback behavior.
- Use LSP for exact definitions/references/diagnostics where available.
- Cache results with freshness metadata.
Phase 5: Optional Vector Search
- Chunk by symbols/functions where possible.
- Store embeddings per chunk hash.
- Reuse the existing embedding infrastructure if possible.
- Add hybrid ranking across FTS, symbols, repo-map signals, and vector results.
Phase 6: Graph Queries
- Add call/import/reference graph where supported.
- Add
find_callers, find_references, and impact_analysis.
Questions for Maintainers
- Does this direction fit LibreFang's goals as an agent operating system?
- Should coding-agent code navigation become a first-class workspace capability?
- Is the workspace/repository ownership model the right boundary, or should this live somewhere else?
- Does the query-router idea make sense, or would a simpler tool/search layer fit the architecture better?
- Is the proposed MVP too large, too small, or aimed at the wrong first piece?
- Where should workspace-level code intelligence configuration live?
- Should repository discovery be automatic by default, explicit by default, or both?
- Should LSP processes be managed by LibreFang, or should LibreFang connect to editor/LSP state when available?
- Which crate should own persistent index storage:
librefang-memory, librefang-runtime, or a new crate?
- Should vector search use the existing memory embedding driver?
- Should code-intelligence tools be regular tools, context-engine helpers, or both?
- How should retrieved code snippets be budgeted against the agent context window?
- How should generated files and vendored dependencies be excluded by default?
- How should exact and approximate results be represented in tool output?
Possible First Useful Version
If this direction is accepted, I think the first version should be deliberately smaller than the full vision.
A practical MVP:
- workspace/repository registry;
- per-agent enable/disable and repository allowlist;
- SQLite FTS5/BM25 over source chunks;
- simple repo map;
- tree-sitter symbol extraction if feasible in the same phase, otherwise next phase;
- incremental update by file hash and git diff;
- no automatic large context injection;
- no vectors yet;
- no LSP yet.
Then add LSP and vectors later.
The goal would be to keep the first implementation small while establishing the right architecture:
Workspace owns code intelligence.
Repositories own index state.
Agents receive scoped tool access.
Query routing chooses the right backend.
Exact and approximate retrieval are clearly distinguished.
Updates are incremental.
Source: #6294
Auto-created from discussion #6294 by @pavver (Ideas)
Discussion: Workspace Code Intelligence Layer for Coding Agents
Description
I would like to open a discussion about whether LibreFang should grow a workspace-level code intelligence layer for coding agents.
This is not meant as a finished design or a request to implement this exact architecture.
The first question is whether this direction fits LibreFang at all.
If the direction seems useful, I would like to discuss the right architecture, boundaries, and migration path with the maintainers.
Short version:
The goal is to help agents locate and understand relevant code with fewer blind
file_list,grep, andfile_readloops.Main Questions
Before discussing implementation details, I think there are two larger questions.
1. Does this direction fit LibreFang?
Should LibreFang try to improve its coding-agent experience with a workspace/repository code intelligence layer?
In other words, should code navigation become a first-class workspace capability, rather than something every agent rediscovers through repeated filesystem searches and file reads?
2. If yes, what should the architecture look like?
The architecture below is only a starting point for discussion.
I am not attached to the exact shape.
The main idea is to start a design conversation and let a better solution emerge from review and discussion.
Some concrete architecture questions:
librefang-memory,librefang-runtime, or a new crate?The rest of this issue describes one possible shape, mainly to make the discussion concrete.
Core Idea
Coding agents need different kinds of code retrieval.
Different questions require different backends:
So the system should not have one universal "code search" mechanism.
It should route each query to the best available backend.
Why
Today, a coding agent usually has to explore a repository through repeated filesystem tools:
That works, but it is inefficient for large or unfamiliar codebases:
A code intelligence layer would give agents a structured and traceable way to ask for code context.
What This Is Not
This is not primarily a vector database feature.
Vector search can be useful for semantic discovery, but it should not be the center of the design.
Vector-only code retrieval is weak for exact programming questions such as:
Those questions are better served by LSP, symbol indexes, reference indexes, lexical search, and structural graphs.
The best design is hybrid:
Possible Architecture
Conceptually:
Backends:
The query router could select the best backend for the task instead of treating every query as a vector query.
Possible Ownership Model
My current assumption is that the code intelligence layer should be owned by the workspace and its repositories.
Agents should not each build their own copy of the same repository index.
Conceptually:
This would avoid duplicated indexing and prevent different agents from having inconsistent views of the same codebase.
Multi-Repository Workspaces
A workspace may contain several repositories.
Example:
These repositories may have different:
So the real indexing unit may need to be a repository root, while the workspace acts as the container.
Conceptually:
Search results should always include the repository identity:
This matters because the same file names, modules, or class names can exist in multiple repositories.
Per-Agent Access
If the index is shared at workspace/repository level, access should probably be configurable per agent.
Examples:
Possible per-agent settings:
Example:
For a project manager:
Query Router
I think the query router may be the important design boundary.
It could choose the best backend for the query type:
This keeps the system honest about which retrieval methods are exact and which are approximate.
LSP Role
LSP could be the preferred backend for precise language intelligence when it is available and healthy.
It can provide things that vector search and syntax-only parsing cannot reliably provide:
Examples:
rust-analyzer;typescript-language-server;pyright/basedpyright;However, I do not think LSP should be the only foundation.
LSP has real operational cost:
Therefore LSP may work best as an optional exact backend with health and fallback behavior.
Suggested LSP health states:
Tool results should expose provenance:
or:
Tree-Sitter Role
Tree-sitter could be the robust structural baseline.
It is useful for:
It is not a full replacement for LSP because it usually does not understand types, build systems, crate graphs, trait resolution, imports at the same level, or generated code.
It may be a better MVP foundation than LSP because it is more predictable and easier to run inside a runtime service.
Text Search Role
Text search seems like the baseline that should always be available.
SQLite FTS5/BM25 would likely be enough for a first version.
It is deterministic, cheap, and very useful for code:
Even after adding LSP and vectors, text search should remain a core backend.
Vector Search Role
Vector search should probably be optional.
It is useful for fuzzy questions like:
It is not reliable enough for exact code intelligence questions by itself.
Embeddings should be stored per chunk hash, not per whole repository.
If one function changes in a large file, only the affected chunk should need a new embedding.
Repository Map
A small repo map can be more useful than large retrieved snippets.
It should contain important files, symbols, signatures, and relationships, with a token budget.
Possible ranking signals:
The runtime could optionally inject a small repo map for agents that opt in.
Detailed code should still be retrieved through tools.
Incremental Updates
The system should be incremental if it supports large workspaces.
Large workspaces can contain millions of lines of code.
Rebuilding the whole index after every commit or branch switch would be too expensive.
The database should track file/chunk/index state, for example:
For chunks/symbols:
When a repository changes from one git head to another, the updater can use:
Then:
The updater should be background/lazy where possible, not blocking the agent loop on large repositories.
Git and Filesystem Events
The system could notice:
Possible update strategy:
A full rebuild should be reserved for:
Tools Exposed to Agents
I do not think the model should automatically receive a large pile of retrieved code on every turn.
Instead, coding agents should get tools that retrieve the specific context they need.
Possible tools:
This keeps context usage controlled and makes retrieval decisions visible in traces.
Suggested Configuration Shape
Workspace-level configuration:
Agent-level access:
Vector search could be enabled separately:
Runtime Safety and Validation
The code intelligence layer should respect existing workspace safety boundaries.
Important constraints:
Suggested default excludes:
Debugging and Tracing
The system should emit trace information such as:
This is important because retrieval quality becomes part of agent quality.
When an agent misses relevant code, we need to know whether the issue came from:
Possible Migration Path
If maintainers think this direction is worth pursuing, I think it should be built incrementally.
Phase 1: Workspace/Repository Registry
Phase 2: Lexical Search and Repo Map
code_search.code_map.This phase is useful even without embeddings or LSP.
Phase 3: Tree-Sitter Symbol Index
symbol_search.This may be a good first structural step because it is predictable and works without running language servers.
Phase 4: LSP Backend
Phase 5: Optional Vector Search
Phase 6: Graph Queries
find_callers,find_references, andimpact_analysis.Questions for Maintainers
librefang-memory,librefang-runtime, or a new crate?Possible First Useful Version
If this direction is accepted, I think the first version should be deliberately smaller than the full vision.
A practical MVP:
Then add LSP and vectors later.
The goal would be to keep the first implementation small while establishing the right architecture: