get_file_outline
Declarations under a path, grouped by file, with kind, signature and range. Use it for a package; one small file is cheaper to read.
Arguments
Section titled “Arguments”| Argument | Type | Default | Meaning |
|---|---|---|---|
repository | string | none, required | The repository name. Rejected with INVALID_ARGUMENT when empty or padded with whitespace, and with REPOSITORY_NOT_FOUND when the published graph does not hold it. |
path | string | none, required | A repository-relative file, or a directory whose files are all wanted. An absolute path is rejected, and so is any .. segment; a trailing / is trimmed. |
kind | string | unset | Keeps only rows whose kind is exactly this string. |
include_members | boolean | false | Adds the rows that belong to the declaration above them: field, property, enum_member and variant. They are off by default because on a real file they are about half the payload. |
limit | integer | 200 | Symbols per page. Must be between 1 and 500; anything else is rejected with INVALID_ARGUMENT. |
cursor | string | unset | The opaque next_cursor of a previous page of the same query. |
response_format | string | concise | concise or detailed. detailed adds stable_key and canonical_identity, and restores the fully qualified signature; in the compact view it is also what puts a signature on a row at all. Any other value is rejected with INVALID_ARGUMENT. |
view | string | compact | The granularity of the answer, never a different answer. compact states the repository, the package and whatever every declaration shares once, and lists the declarations by file as name@start-end entries. full is the field-per-row shape. files answers only which files hold the page’s declarations and how many each holds. Any other value is rejected with INVALID_ARGUMENT. |
Answers
Section titled “Answers”This is how to read the shape of code without opening it: what is declared under a path, of what kind and on which lines.
By default the answer is the compact view. results is one object stating the
repository, the path asked about, the package when the whole page sits in
one — packages when it does not — and then whatever every declaration of the
page shares: kind when they are all of one kind, exported when they are all
visible or all not. files groups the declarations by file, and an entry of a
group’s at is name@start, or name@start-end when the declaration spans
more than one line, using the qualified name when the row has one. An entry
becomes an array when the page could not hoist a column: the elements after the
label are appended in a fixed order — the name, the kind, exported or
unexported, the signature, the stable key, the canonical identity — skipping
everything the header already states and everything concise withholds. There is
no languages field: a path’s extension says the language.
With view: "full", results carries repository, path, packages,
languages and files, each entry of files having a path and its symbols,
and each symbol row carrying name, kind, signature, exported,
start_line and end_line, plus qualified_name only when it differs from
name.
Those rows are what the rest of the surface accepts: the repository, the path
of the group and the qualified name are exactly the triple get_symbol,
get_source, find_references and the traversal tools take, so the next call
is built out of the answer you just got. Under
response_format: "detailed" each row also carries its stable key. Measured over
the private benchmark corpus, one directory outline went from 633 to 248 tokens with a single
shared kind; a larger directory with no single shared kind or exported
went from 3.667 to 3.184 once the second grouping tier below applied.
When kind and exported do not both hoist to the header, results.groups
replaces files: each entry states its own kind and exported pair and
holds the declarations that share it, grouped by file exactly like the flat
page. See when a page groups for the
mechanism shared by six tools, and the grouped example
below for a captured page.
get_file_outline publishes no coverage counters at all. The four categories
grade resolved relations and the confidence behind each one, and an outline
returns the declarations of one repository, so none of them applies — total
and returned already say how many declarations there are. The compact view
omits the coverage key entirely; the full view still writes the four zeros,
because that view writes every field by contract.
completeness states how far the page reaches, and the question names a place
rather than a symbol, so no failed request for a name can bound it: the only
failure that can is a scope of the repository asked for that the index could not
read, named in invisible_scopes. There is no fallback pattern here —
without a symbol there is nothing to grep for. An outline that lists nothing
under a path is saying nothing is declared there, so the verdict is spent
where the answer could be mistaken for that proof — a page with no rows, a
truncated one, and every LOWER_BOUND — while a page of declarations claims no
absence and carries no verdict at all. See
the completeness verdict for the two values and
the rest of the block.
Example
Section titled “Example”{ "repository": "kivgraph", "path": "internal/mcp/instructions.go"}{"snapshot_id":30,"total":2,"returned":2,"results":{"repository":"kivgraph","path":"internal/mcp/instructions.go","package":"github.com/Luqueee/kivgraph/internal/mcp","kind":"const","exported":false,"files":[{"file":"internal/mcp/instructions.go","at":["staleServerInstructions@36","serverInstructions@21-27"]}]}}Both declarations are unexported constants of the same package, so the header
carries the package, the kind and the visibility and each entry is the bare
label: one line for staleServerInstructions, lines 21 to 27 for
serverInstructions. Nothing was dropped — there was nothing left to say per
row.
The same call in the full view, the field-per-row shape:
{ "repository": "kivgraph", "path": "internal/mcp/instructions.go", "view": "full"}{"snapshot_id":30,"snapshot_age_ms":9020,"total":2,"returned":2,"truncated":false,"next_cursor":null,"coverage":{"exact":0,"candidate":0,"unresolved_related":0,"package_level":0},"results":{"repository":"kivgraph","path":"internal/mcp/instructions.go","packages":["github.com/Luqueee/kivgraph/internal/mcp"],"languages":["go"],"files":[{"path":"internal/mcp/instructions.go","symbols":[{"name":"staleServerInstructions","kind":"const","signature":"untyped string","exported":false,"start_line":36,"end_line":36},{"name":"serverInstructions","kind":"const","signature":"untyped string","exported":false,"start_line":21,"end_line":27}]}]}}The files view
Section titled “The files view”When the question is which files declare anything, view: "files" answers with
the file list and a count each, and nothing about what is declared:
{ "repository": "kivgraph", "path": "internal/mcp/instructions.go", "view": "files"}{"snapshot_id":30,"total":2,"returned":2,"results":{"repository":"kivgraph","path":"internal/mcp/instructions.go","files":[{"file":"internal/mcp/instructions.go","declarations":2}]}}It is the shape of the question over a directory, where the answer is a dozen
files rather than one. declarations counts what this page holds for the file,
so on a truncated page it is the page’s count and not the file’s total.
These responses come from snapshot 30 of two repositories, kivgraph and
mole.
Example: grouped
Section titled “Example: grouped”A directory whose declarations do not share one kind or one exported:
{ "repository": "mole", "path": "internal/admin"}{ "snapshot_id": 1, "total": 32, "returned": 19, "results": { "repository": "mole", "path": "internal/admin", "package": "github.com/Luqueee/mole/internal/admin", "groups": [ { "kind": "method", "exported": true, "files": [{ "file": "internal/admin/admin.go", "at": [ "Stats.OnConnect@30-33", "Server.WithPortController@89-92", "PortController.RemoveDiscover@74", "Server.Handler@95-104", "Server.WithPorts@81-84", "Stats.OnDialFail@41-43", "Stats.OnDisconnect@36-38", "PortController.AddDiscover@73" ] }] }, { "kind": "method", "exported": false, "files": [{ "file": "internal/admin/admin.go", "at": [ "Server.handleStatus@106-129", "Server.handlePortAdd@150-169", "Server.handleHealth@131-134", "Server.handlePortDelete@175-188" ] }] }, { "kind": "func", "exported": true, "files": [{ "file": "internal/admin/admin.go", "at": ["New@54-56", "NewStats@25-27"] }] }, { "kind": "type", "exported": true, "files": [{ "file": "internal/admin/admin.go", "at": ["PortController@72-75", "Server@58-63", "Stats@16-22"] }] }, { "kind": "type", "exported": false, "files": [{ "file": "internal/admin/admin.go", "at": ["portRequest@139-141", "snapshot@45-50"] }] } ] }}Five groups over one file: repository, path and package cover the whole
page and stay in the header as always, but kind and exported each take four
or more values between them, so neither hoists and every group states its own
pair. Nothing here needed a column beyond the pair — no group mixed two
signatures or two visibilities inside itself — so every entry is still the bare
name@start-end label; a group with a residual disagreement of its own would
turn an entry into an array exactly as the flat page does.
Limits
Section titled “Limits”limit defaults to 200 and cannot exceed 500. A value outside 1 to 500 is
rejected rather than clamped.
truncated is true and next_cursor is a token whenever the page did not
exhaust total; the compact view omits both when it did. The cursor is an
opaque, checksummed base64url token about 31 characters long — a binary body,
where the previous version spelled 314 characters of base64-wrapped JSON — and
it is bound to the snapshot identifier, to the sorting version stable-key-v1
and to the query identity: the tool name, repository, path, kind and
include_members. Change any of those and the token no longer matches, which
fails as CURSOR_INVALID, and so does a token that was edited, truncated,
re-encoded or decodes with trailing bytes after its checksum. A token minted by a
server of the previous cursor version fails closed the same way: the body
declares version 2 and version 1 is never reinterpreted under the new layout. A
token issued against an older generation fails as CURSOR_SNAPSHOT_EXPIRED. All
of them mean the pagination has to restart. view is not part of the identity,
so one cursor can continue the outline in another view.
kind and include_members filter the page after it is taken, so total
counts every symbol under the path and returned counts what survived the
filter. A page can therefore return fewer rows than limit and still be
truncated.
A path the graph does not know is an error naming both the repository and the
path, SYMBOL_NOT_FOUND, never an empty page. An empty page would read as
“nothing is declared here”, which is a different and more misleading answer.
guidance is never emitted by this tool. Groups follow the order the page
first mentions each file, and packages is sorted, so two calls over the same
page of the same snapshot produce byte-identical responses.
response_format accepts concise and detailed. Concise drops the stable
key, which on a 155-declaration file was half the tokens, and prints the
signature the way the declaring source reads it, with the symbol’s own package
path removed. Types from other packages keep their path. detailed restores
the key, the full signature and canonical_identity. In the compact view the
signature is on a row only under detailed: it is the largest field a row can
carry, and a reader choosing between declarations is choosing between names.
Where it loses
Section titled “Where it loses”One small file is cheaper to read than to outline: the outline is a second
round trip and it gives you names where the file gives you the code.
get_file_outline earns its cost on a directory or a package, where it
replaces a dozen reads with one answer, and when you need the ranges before
deciding which body to fetch with get_source.