An agent asked to change code it has never read has one default move: open files until something looks relevant. arcade-agent replaces that with three task-shaped questions answered from a dependency graph — ranked, capped, and explained file by file.
context_for_taskGive it a natural-language task and it returns the minimal ranked set of files to read — at most max_files (default 15), each with a primary_role (direct match, dependency of match, dependent of match, component sibling) and a plain-language reason.
api_surfaceOnce the agent knows where to work, this says what is callable from outside: public top-level types and functions grouped by package, public members nested under their owner type, no implementation bodies.
dependency_coneReachability from one entity or file — upstream (what it depends on), downstream (what depends on it) or both — with a max_depth and an optional per-direction node cap.
A captured context_for_task run against a shallow clone of pallets/click, trimmed for length. The full run — plus the no-match branch, which returns an error key rather than raising — is on the context_for_task page.
→ context_for_task(dep_graph="fe538dededcc",
task="add shell completion support for a new shell",
architecture="7abc279063c7", max_files=5)
{
"task": "add shell completion support for a new shell",
"keywords": ["add", "shell", "completion", "support", "for", "new", "shell"],
"num_files": 5,
"files": [
{
"file_path": "click/shell_completion.py",
"score": 1191.8,
"primary_role": "direct match",
"entities": [ /* 36 entities, all "direct match" */ ],
"reason": "matches 'add', 'completion', 'for', 'shell';
depended on by BashComplete; depended on by ZshComplete"
}
// … 4 more files: click/core.py, click/types.py,
// click/exceptions.py, click/formatting.py
]
}Ranking is a heuristic over the parsed graph, not a search index — the score seeds on keyword hits and decays across one hop of dependencies and dependents.
Because reading one relevant file in full can cost more than the answer does. In the one measured example published on this site — an agent scoping a signature change in click.core.Context.invoke — the context_for_task response came in 56% under the dependency-graph-derived raw baseline for the same question. That's one scenario on one repo, with the estimator, the caveats and the reproduction steps written out in full:
max_tokens degrades instead of erroring, and how to recover the untruncated payload with get_full_result.Worth knowing before you rely on it.
· context_for_task tokenizes the task by length with no stopword list, so short words in a task string can pull in incidental path matches — read the reason field, don't trust rank alone.
· Passing architecture only ever adds candidates (component siblings); it never narrows the result, and omitting it never fails the call.
· dependency_cone resolves a file target by exact FQN, then exact path, then path suffix; when a target matches several distinct files it reports ambiguous: true with candidate_files instead of silently unioning them.
· "Public" in api_surface is derived structurally from the underscore-prefix naming convention, and a signature is name + kind (plus superclass and interfaces for types) — parsers don't store parameter or return types.
All three tools take a dep_graph — a parse session ID — so the chain is ingest → parse (→ recover, optional, for component names), or a single analyze call that runs the whole pipeline and hands back per-stage session IDs. Config snippets for Claude Code, Cursor, Claude Desktop, VS Code and Windsurf are on the agent tools page.
pip install "arcade-agent[languages,mcp]", point your MCP client at arcade-mcp, and run the first analysis — the getting-started page walks a real captured transcript end to end.