Design spike for ranking files by relevance to an agent’s current context, so retrieval tools surface the most useful files first. The tool proposed here as get_relevant_files shipped as [[tools-reference#get_related_files|get_related_files]], which takes a path plus optional limit and task_id rather than a full context object. The signal set was reworked in 0.13.0 — see the shipped-weights note at the end.

Approach: Weighted Scoring with Configurable Signals

Each candidate file receives a composite score:

relevanceScore(file, context) = Σ(weight_i × signal_i)

Every signal is normalized to [0, 1]. Files are returned sorted by score descending.

Context Object

interface RankingContext {
  taskId?: string;       // current task — enables task-proximity signal
  queryFile?: string;    // file the agent is currently viewing
  searchTerms?: string;  // free-text keywords for name/path matching
}

Signals

Listed in priority order with default weights (sum = 1.0).

#SignalWeightSourceNormalization
1Task proximity0.35Files imported by, or importing, files already explored in the current task (task_explored_files)1.0 if directly connected, 0.5 if two hops, 0.0 otherwise
2Dependency proximity0.25Shortest path in the dependency graph from queryFile or working set1 / (1 + distance) — closer files score higher
3Recency0.15mtime of the file on disk (or last_accessed from task memory)Linear decay: most recent file = 1.0, oldest = 0.0
4File type0.10Extension / purpose classification from file summariessource = 1.0, types = 0.8, config = 0.6, test = 0.4, docs = 0.2, assets = 0.0
5Change frequency0.10git log --format='' --follow <file> | wc -l (cached)Percentile rank among all project files
6Name/path match0.05Simple substring / token overlap against searchTermsJaccard similarity of path tokens vs. query tokens

Weights are configurable at the call site so agents can boost signals that matter for their current task (e.g. boost recency during debugging, boost dependency proximity during refactoring).

Integration

New Module

src/cache/ranking.ts

interface RankedFile {
  path: string;
  score: number;
  signals: Record<string, number>; // per-signal breakdown for debugging
}
 
function rankFiles(
  files: string[],
  context: RankingContext,
  projectRoot: string,
  weights?: Partial<Record<string, number>>
): RankedFile[];

New MCP Tool

get_relevant_files — returns the top-N most relevant files for a given context.

get_relevant_files(context: RankingContext, limit?: number)
  -> { files: RankedFile[] }

Default limit: 20.

Existing Tool Enhancement

Add an optional ranked: boolean parameter to get_project_map. When true, the file list is sorted by relevance score instead of alphabetically.

Data Dependencies

SignalRequires
Task proximitytask memory tables (tasks, task_explored_files) + dependency graph
Dependency proximitydependency graph (file_dependencies)
Recencyfs.stat or task memory last_accessed
File typefile summaries (purpose field) or extension heuristic
Change frequencygit history (cache in SQLite, refresh on scan)
Name/path matchno additional storage

All dependencies already exist or are trivially derivable. No new tables required — change frequency can be stored as a column on file_summaries.

Evaluation

A good ranking means the agent reads top-ranked files early instead of scanning broadly. To validate:

  1. Offline: replay real agent sessions. For each task, compare the ranked order against the files the agent actually opened. Measure precision@k (k = 5, 10, 20).
  2. Online: log which files are returned by get_relevant_files and which the agent subsequently reads. Track hit rate over time.
  3. Baseline: compare against alphabetical order and recency-only sorting to confirm the composite score adds value.

Target: precision@10 >= 0.6 (at least 6 of the top 10 ranked files are ones the agent would have read).

Shipped Weights (0.13.0)

The search-efficiency audit found that in the only production call path the design above degenerated to a constant: cacheStore was never passed (recency froze at its default), change frequency was a hardcoded placeholder, and without a task_id the proximity signals floored — so every top result tied at 0.325 and the “ranking” was alphabetical within file-type buckets. The 0.13.0 rework keeps the weighted-sum architecture but changes the signal set:

SignalWeightNotes
Relationship0.30New — the candidate’s relationship to the query file (imports/imported-by = 1.0, transitive = 0.5, same-directory = 0.25). The strongest evidence available was already computed and then thrown away.
Dependency proximity0.25Now anchored to the query file (1.0 direct, decaying by 1/2^(distance-1)).
Recency0.15Now live — the cache store is actually passed, so recently checked files score higher.
Task context0.15Directory adjacency to the active task’s explored/flagged files.
File type0.10Mild prior: source over config over tests.
Centrality0.05New — log-scaled degree centrality from the persisted graph; a deliberately small importance prior (the Aider PageRank direction, at 5% of the score).

Change frequency (git-log counting) and name/path match were deleted rather than implemented: the former was never built and costs a subprocess per file, and the latter belongs to search_by_purpose. With the new signals, repo-memory’s own files tier cleanly — direct imports 0.76–0.87, transitive ~0.5, same-directory below — instead of tying.