Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Supported Ecosystems

ManifestKindWorkspace support
package.jsonnpmworkspace: protocol versions normalized
go.modgogo.work member metadata
go.workgouse directives parsed for workspace context
Cargo.tomlcargoworkspace = true deps resolved from root
pyproject.tomlpython—
pom.xmlmavenParent POM inheritance (groupId, version)
build.gradle / build.gradle.ktsgradlesettings.gradle project inclusion
cpanfileperlrequires / on 'test' blocks
Gemfilerubygem / group :test blocks
flake.nixnixinputs attrset (dotted and block forms)

Package naming

A package’s name is the join key everything else carries (symbols.package, dependencies.package, the package filter on every MCP tool), so it is never empty:

ManifestName
package.json, pyproject.toml, Cargo.tomlthe declared name
go.modthe last segment of the module path
pom.xml, build.gradlegroup:artifact (artifact alone when there is no group)
cpanfile, Gemfile, flake.nixno name field exists — see below

When a manifest declares no name (a Gemfile, a tooling-only root pyproject.toml, a private package.json), the name is derived from its location: a nested manifest takes its directory path with / replaced by - (services/api/Gemfile → services-api), and a manifest at the repo root takes the repository directory’s own name.

Two Gradle subprojects can compute the same group:projectName (two directories both called app). The one indexed first keeps that name; the colliding one falls back to its path-derived name, with -2, -3… appended if that name is taken as well. A warning naming both directories is logged, and neither package is dropped.

Symbol extraction

Shire extracts symbols (functions, classes, types, methods, interfaces) from source files using tree-sitter, with full signatures, parameters, and return types.

Private and unexported symbols are indexed too, not skipped. Every symbol carries a visibility — public, protected, internal or private — derived from the language’s own convention (the Visibility column below). A member is narrowed by its enclosing type: a public method of a private class is private. Search ranks private symbols after the others (see MCP Tools), and symbols.include_private = false drops them (see Configuration) — only private ones: internal (e.g. Java package-private, Rust pub(crate)) and protected symbols are always kept. Where a language has no visibility rule that Shire reads, every symbol is public.

LanguageExtractorVisibility
TypeScript / JavaScripttree-sitterModule-level declarations: exported (export ... or named in an export { ... } clause) is public, anything else private. Methods: private / #name / protected modifiers. CommonJS module.exports is not recognised.
Gotree-sitterCapitalised name public, otherwise private
Rusttree-sitterpub → public; pub(crate) / pub(super) / pub(in …) → internal; no modifier or pub(self) → private. Trait-impl methods are public.
Pythontree-sitterLeading _ → private; dunder names (__init__) are public
Javatree-sitterpublic / protected / private; package-private (no modifier) → internal. Interface members and enum constants are implicitly public.
Kotlintree-sitterprivate / protected / internal; no modifier → public
Darttree-sitterLeading _ → private (including named constructors such as Foo._internal)
Protobuftree-sitterall public
Ctree-sitterstatic → private, otherwise public
C++tree-sitterClass members from the nearest public: / protected: / private: label (default private in a class, public in a struct); non-member static → private
C#tree-sitterpublic / protected / internal / private; with no modifier a class member is private, an interface member public, a top-level type internal
Swifttree-sitterprivate / fileprivate → private; explicit internal → internal; no modifier → public
PHPtree-sitterprivate / protected; no modifier → public
Scalatree-sitterprivate / private[this] → private; private[pkg] → internal; protected
Zigtree-sitterpub → public, otherwise private
Bash / Shelltree-sitterall public
Rtree-sitterall public
Haskelltree-sitterall public (export lists are not read)
YAMLtree-sitterall public
SQLtree-sitterall public
HCL / Terraformtree-sitterall public
TOMLtree-sitterall public
Perltree-sitterLeading _ → private
Rubytree-sitterMethods after a bare private / protected line, or written private def …; private :name is not tracked
OCamltree-sitterall public (.mli signatures are not read)
Luatree-sitterlocal function / local f = function → private
Elixirtree-sitterdefp / defmacrop / defguardp / @typep → private
Clojuretree-sitterdefn- and ^:private metadata → private
Erlangtree-sitterall public (-export lists are not read)
Juliatree-sitterall public (export statements are not read)
Gleamtree-sitterpub → public, otherwise private
Odintree-sitterall public
Nixtree-sitterall public
Nimtree-sitter* export marker → public, otherwise private
COBOLregex-basedall public

An index built by an older Shire picks the private symbols up on its first build after upgrading: the extractor version is stored in the index, and a mismatch re-extracts every source file once.

Reference extraction

Shire extracts cross-references (calls, type references, imports, and interface implementations) for a subset of languages. These are stored in the symbol_refs table and exposed via the symbol_references, symbol_callers, and symbol_callees MCP tools.

LanguageCallTypeImportImpl
Goyesyesyes— (implicit interfaces)
Pythonyesyesyesyes
Javayesyesyesyes
TypeScriptyesyesyesyes
JavaScriptyes—yesyes
Perlyes—yes—
Rubyyesyesyesyes
Scalayesyesyesyes

All other languages: symbol definitions only; references are not extracted.