# get_context

The workhorse MCP tool. get_context returns batched context for files, modules or symbols: docs, ownership, freshness, plus optional callers and metrics.

If your agent only learns one tool, make it this one. `get_context`
absorbs what would otherwise be five or six separate calls (file
docs, symbol signatures, ownership, last-change history, callers and
callees, centrality metrics, community membership, and freshness) into
a single call with a configurable `include` list. Pass multiple targets
at once. The docs come from the [generated documentation](https://docs.repowise.dev/intelligence/auto-wiki),
and callers, callees and communities from the
[dependency graph](https://docs.repowise.dev/intelligence/dependency-graph). The other tools are on
[MCP tools](https://docs.repowise.dev/mcp/overview).

> **Warning**
>
> This is **not a source-body tool**. There is no `include=["source"]`:
> the triage card returns signatures, not bodies. For a whole file, ask
> for it in one call with `include=["skeleton"]` (body-elided, every
> signature, the most central symbols in full), or just Read it. Reach
> for [`get_symbol`](https://docs.repowise.dev/mcp/get-symbol) for a single body a response
> already named, never per signature in a loop.

## When to call

- **After `get_answer`** to verify or expand on cited files.
- **Before editing** any file: check ownership, dependents, freshness,
  and governing decisions.
- **Architectural questions**: pair with `include=["metrics", "community"]`
  to see centrality and cluster membership.
- **Always batch**: one call with five targets is far cheaper than
  five calls with one target each.

## Parameters

| Name | Type | Default | Description |
|---|---|---|---|
| `targets` | string[] |  | Required. File paths, module paths, qualified symbol IDs (e.g. "src/auth/service.py::verify_token"), "component:<name>", "change:<id>" (pr-123 or a commit sha), or "package:<name>". In a workspace, "<alias>:<target>" names the repo. Pass as many as you need. |
| `include` | string[] | `["docs", "freshness"]` | Blocks to include, on top of the always-on "docs" and "freshness". Options: "full_doc", "ownership", "last_change", "callers", "callees", "references", "metrics", "community", "decisions", "skeleton", "skeleton+", "health", "doc_drift", "symbols", "changes", "provenance", "suspects". An unknown key is named in ignored_arguments. No "source" option: this tool returns no source bytes, ever. |
| `symptom` | string |  | Issue text, an error message or a pasted stack trace for include=["suspects"] to rank against, in place of the words in the target paths. |
| `compact` | boolean | `true` | True returns signatures only (lighter). False adds the structure block, docstrings, and imported_by. |
| `repo` | string |  | Repository alias. Usually omitted: in a workspace, each target routes to the repo that owns it. "all" is not supported. |

## Returns

The response is a `targets` map keyed by the target string. Each entry contains:

| Block | What it gives you |
|---|---|
| `docs` | Wiki title, summary, and symbols list (name, kind, signature, line, docstring). Adds structure block and `imported_by` for files; child file pages for modules; `qualified_name`, `used_by` (files that call or reference this exact symbol, ranked by centrality), candidate matches for symbols |
| `full_doc` | Same as `docs` but with the full page content_md |
| `ownership` | `primary_owner`, `owner_pct`, `contributor_count`, `bus_factor`, plus `recent_owner` if the active maintainer differs from the historical primary, and one `agent_share` summary with its coverage. On a directory: `owners_by_files` (top 3, `owners_total` beyond) and `basis` |
| `last_change` | ISO date, author, days ago |
| `callers` / `callees` | For a **symbol** target: up to 50 each, filtered to confidence ≥ 0.7. Each entry: `symbol_id`, `name`, `kind`, `file`, `line`, `confidence`, `edge_type`. For a **file** target: a rolled-up view instead, capped at 20, with a different shape: `{file, imports?, inbound_calls?}` (`imports: true` when that file imports this one, `inbound_calls` counting cross-file call edges into any symbol this file defines). For either target, callers that reach an implementation through the interface it implements come after every direct caller, marked `via: "interface"` and counted in `callers_via_interface` |
| `metrics` | `pagerank`, `pagerank_percentile`, `betweenness`, `betweenness_percentile`, `in_degree`, `out_degree`, `community_id`, `community_label` |
| `community` | `id`, `label`, `cohesion`, `top_members`, `neighbors` with cross-edge counts |
| `freshness` | `confidence_score`, `freshness_status`, `is_stale` |
| `hotspot` | Always on. `true` when the target is a churn hotspot; a cue to follow up with `get_risk` |
| `fix_history` | Always on, appears only on files with counted bug fixes: `count`, age, and a `bug_magnet` flag |
| `episodes` | Always on. Count of dated episode records bound to this target |
| `decisions` | Governing records (accepted, with `currency`) under `decisions`, plus `candidates` (proposed, never accepted, up to 3) and `history` (accepted then withdrawn). Default returns titles only; `include=["decisions"]` returns full records |
| `health` | Code-health score and findings for the target |
| `doc_drift` | Documents that name this file, where in each, and whether those documents drift themselves. Ask before moving or renaming a file. See [Documentation drift](https://docs.repowise.dev/intelligence/doc-drift) |
| `skeleton` | The file with bodies elided: every signature, the import preamble, and the bodies of only the most central symbols (ranked by symbol PageRank / hotspot / query match), token-budgeted. Typically ~15% of the full file's tokens. Elision markers carry 1-indexed line ranges so anything can be range-read back |

| `references` | Every edit site of a symbol: definition, import, call and other live occurrence lines, checked against the files on disk, with `complete` and `reasons`. When `complete` is true, it is the whole edit set for a rename |
| `symbols` | Every symbol of a file, not only the top 15 |
| `skeleton+` | Every line except function bodies, each replaced by a marker with its line range |
| `changes` | On a file target, the newest Change Records that touched it |
| `provenance` | On a file target, its commits by source (agent, human-attested, unknown) with coverage. The agent share is withheld below 30% coverage, and reads `{"unavailable": "attribution_off"}` when attribution is off |
| `suspects` | One top-level block: changes merged in the last 14 days ranked against the targets' files and the words in their paths, or against `symptom` when given, at most 5 rows, each with the signals that fired and their evidence. A reading order, never a cause |

A **directory** target reads the indexed files under it, with or without a
module page (`index_status: "directory_without_module_page"` lists up to 15
`docs.files`). Git history is stored per file, so `ownership` counts the files
each person primarily owns, `last_change` gives the newest commit's date and
file, and `hotspot_files` counts hotspot files; no commit share or bus factor is
claimed.

An empty `callers`, `callees` or `used_by` comes with a `*_basis` field
saying how much of that language's calls the graph resolved. Read it before
concluding nothing calls a symbol. A `path::Symbol` target with
`include=["skeleton"]` returns its file's skeleton.

Top-level fields:

- `truncated`: `true` if output was capped at the token budget.
- `dropped_targets`, `dropped_symbols`: what got evicted when the
  budget was exceeded.
- `_meta.omitted`: when anything was dropped, the refs to get it back:
  `{ refs, tokens, restore }`. Resolve with `repowise expand <ref>` from
  a shell or [`get_symbol("repowise#<ref>")`](https://docs.repowise.dev/mcp/get-symbol) from
  any MCP client; truncation is never silent.

## Target kinds beyond files and symbols

| Target | Returns |
|---|---|
| `component:<name>` | The component's declared owner, system, criticality and tags, and `facts` rolled up over its files: health, hotspots, bus factor, test reach and dead code, each with a `basis` (`measured`, `inferred` or `unavailable`). `include=["ownership"]` adds declared teams with their activity over the last 90 days, a count of individual owners, and findings such as `critical_no_active_owner`. No other `include` applies |
| `change:<id>` | The Change Record: title, forge ref, `merged_at`, category, files and provenance with its coverage. A commit sha the change landed works as the id |
| `package:<name>` | Where a third-party package is imported (`package:requests`, `package:npm:lodash`): manifest declarations, components and owner teams, and up to 25 import sites with line, `mapping` (`declared` or `inferred`) and `reachability` (`reachable`, `unreachable`, `test` or `unknown`) |

Components come from `.repowise/components.yaml` or `catalog-info.yaml`,
or are derived from the index. Owners are named as teams; individuals
are counted.

## Example

```python
get_context(["src/auth/service.py"])

get_context(
    ["src/auth/service.py::verify_token"],
    include=["callers"],
)

get_context(
    ["src/auth/", "src/payments/"],
    include=["ownership", "metrics", "community"],
)

# Structure-level view of a large file at ~15% of the tokens
get_context(["src/big_module.py"], include=["skeleton"])

# A component, a change and a package in one call
get_context(["component:payments", "change:pr-412", "package:requests"])

# Every edit site before a rename
get_context(["src/auth/service.py::verify_token"], include=["references"])

# Recent changes ranked against a failing file
get_context(["src/payments/retry.py"], include=["suspects"])
get_context(["src/payments/retry.py"], include=["suspects"], symptom="TypeError: amount is None")

# Workspace: name the repo outright
get_context(["web:src/app.ts::App"])
```

## Things worth knowing

- **Budget**: responses fit 24,000 serialized characters, or 32,000 when
  `include` is non-empty.
  Truncation happens in stages: (1) strip heavy doc fields,
  (1.5) strip skeleton texts, largest first, (2) shrink symbol lists
  keeping query-matched symbols first, (3) drop whole targets. Largest
  targets are evicted first.
- **Symbol prioritisation**: within a target, symbols are ranked by
  exact name match → substring match → kind (class > function > method)
  → centrality. Navigationally important symbols survive truncation.
- **Target resolution order**: file_page → module_page → symbol
  (exact then fuzzy) → file by `target_path`. If none match, returns
  fuzzy path suggestions.
- **`freshness` is included by default**: critical for the agent to
  detect stale indices. `ownership` and `last_change` add 200 to 500 bytes
  each; omit them on multi-turn sessions to save the cache.
- **Workspace routing**: with `repo` omitted, a path or `path::Name`
  goes to the repo that has the file, and a bare symbol name such as
  `render` or `Client.send` goes to the repo that defines it. An
  ambiguous target returns `candidates`. One call can span repos.
- **Cross-repo enrichment (workspace mode)**: appends co-change
  partners and contract links (HTTP routes, gRPC services, topics)
  from other repos for files in a multi-repo workspace.

> **Note**
>
> **Pattern that works well:** call `get_answer` first, then
> `get_context(targets=fallback_targets, include=["ownership", "last_change"])`
> on whatever the answer cited. Two calls, complete picture.
