AST-native code intelligence for Python — MCP server for Claude Code (12 agent tools) + standalone audit CLI (dead code, import graph, swallowed exceptions, 500+ language LOC via Linguist port).
Project description
symbol
AST-native code intelligence for Python. A CLI for humans, an MCP server for agents.
Point symbol at a directory and ask it questions a human or a coding agent actually has:
- What frameworks does this project use, where are the entry points, which files are dead, what runs on import, where the TODOs and swallowed exceptions hide?
- Where is
UserServicedefined, who callsdb.commit, what's the body ofprocess_payment— without re-reading 800 lines of file?
Static analysis only — symbol never imports or executes the target code.
Status:
wyolet-symbolon PyPI (CLI command issymbol— the bare name is reserved by PyPI policy). Python is the proving ground; Go and TypeScript are next on the roadmap.
Install
CLI only
uv tool install wyolet-symbol # or: pipx install wyolet-symbol
Then symbol audit /path/to/project, symbol loc, symbol map work from any directory.
Claude Code plugin (CLI + MCP server + skill + hooks)
For full agent integration — MCP tools (SearchSymbol, SymbolBody, MultiPatch, …), the symbol skill, and soft-nudge PreToolUse / PostToolUse hooks that steer Claude away from native Grep/Read/Edit on indexed Python files:
# 1. Install the CLI from PyPI
uv tool install wyolet-symbol
# 2. Install the plugin in Claude Code (bundles MCP server registration, skill, hooks)
claude plugin install git+https://github.com/wyolet/symbol@main
Other agent coding tools
The MCP server is plain stdio MCP — it works anywhere MCP works. opencode setup is documented in docs/integrations/opencode.md. Cursor, Continue, and Zed integrations are tracked in #8; help wanted. The Claude-Code-specific glue (skill + hooks) does not port automatically.
Updating / uninstall
uv tool upgrade wyolet-symbol # or: uv tool uninstall wyolet-symbol
claude plugin update symbol # or: claude plugin uninstall symbol
Commands
symbol audit <path> — Full codebase audit
Runs all registered checkers: stack detection, entry points, orphan files, side effects, swallowed exceptions, TODOs, unused deps, code structure metrics.
symbol audit /path/to/project
symbol -v audit /path/to/project # verbose — full detail
symbol /path/to/project # shortcut — defaults to audit
symbol loc <path> — Lines of code
GitHub Linguist port: 500+ languages, real GitHub colors, multi-strategy detection (modeline, shebang, filename, extension, XML, manpage). Colored bar chart by default.
symbol loc /path/to/project
symbol map <path> — Import graph analysis
Circular imports, hotspots, fragile modules, deep chains, leaf modules, blast radius.
symbol map /path/to/project
symbol map /path/to/project --blast src/models.py # blast radius
symbol map /path/to/project --min-chain 3 # show shorter chains
symbol map /path/to/project --min-fan-in 3 # lower hotspot threshold
Symbol-level inspection
symbol search UserService # exact / suffix match on qualified path
symbol search user service --fixed # all patterns must appear as substrings
symbol search '^get_' --regex # Python regex
symbol search save --kind method
symbol code services.user.UserService # body by qualified path
symbol code services.user.UserService.save # method
symbol code src/services/user.py:120-145 # by explicit line range
symbol outline src/services/user.py # parent-child tree of one file
symbol callers UserService # textual tier-1 reference scan
symbol patch <file> — Byte-range edit
Edit by line range without sending an old_string payload. Replace (with content), delete (empty content), or insert (zero-width range).
symbol patch src/foo.py --range 10-20 --content 'new body' # replace
symbol patch src/foo.py --range 10-20 --content '' # delete
symbol patch src/foo.py --range 10-10 --content 'import os' # insert before line 10
symbol patch src/foo.py --range 10-20 --content '...' --dry-run # preview diff
symbol patch src/foo.py --range 10-20 --content '...' --force # skip read-cache check
symbol patch src/foo.py --range 10-20 --content '...' --agent # plain text for LLMs
Exit codes: 0 applied/dry-run, 1 error, 2 needs_read_confirmation.
Plus
symbol analyze <file>, symbol dump <path>, symbol init <path>, symbol update-linguist, symbol undo, symbol refresh [--full].
MCP surface (12 agent tools)
When run as symbol mcp (or installed via the plugin), symbol exposes:
| Read | Write | Safety |
|---|---|---|
SearchSymbol |
Patch |
Undo |
SymbolBody |
MultiPatch |
Refresh |
SymbolOutline |
InsertSymbol |
|
SymbolCallers |
DeleteSymbol |
|
RenameSymbol |
||
ReplaceSymbol |
Undo is transactional and operates on .symbol/transactions/ — no git involvement, no staged changes touched. Refresh is the escape hatch when the index drifts.
Configuration
Use symbol.toml at the project root, or add the same tables under
[tool.symbol] in pyproject.toml.
# symbol.toml
[checker]
exclude = ["alembic/*", "scripts/*"]
[checkers.orphans]
severity = "warning" # default: error
ignore = ["alembic/*", "src/main.py"]
[checkers.side_effects]
severity = "info" # default: warning
ignore = ["*.include_router()", "*.add_middleware()"]
[checkers.unused_deps]
severity = "error" # default: error
ignore = ["greenlet", "psycopg"]
In pyproject.toml, prefix those tables with tool.symbol:
[tool.symbol.checker]
exclude = ["alembic/*", "scripts/*"]
[tool.symbol.checkers.orphans]
severity = "warning"
ignore = ["alembic/*", "src/main.py"]
The config schema lives at
schemas/symbol.config.schema.json. With
Taplo, you can wire it up for both forms:
[[rule]]
include = ["symbol.toml"]
schema = { path = "schemas/symbol.config.schema.json" }
[[rule]]
include = ["pyproject.toml"]
keys = ["tool", "symbol"]
schema = { path = "schemas/symbol.config.schema.json" }
See docs/spec-schema.md for the package/spec schema.
Global options
-v, --verbose Show full detail instead of compact output
--format json Output as JSON (for CI/CD pipelines)
-i, --include PATTERN Only analyze files matching glob pattern
-e, --exclude PATTERN Skip files matching glob pattern
Why
Most Python tools find problems inside files (lint, types, dead code). symbol finds problems between files — and exposes the result to agents in tokens, not line ranges:
- knip does this for JavaScript/TypeScript. Python didn't have an equivalent.
symbolfills that gap. - GitHub Linguist ported to Python — accurate detection for 500+ languages with real GitHub colors.
- scc-style LOC with language breakdown and colored bar chart.
- Import-graph analysis — circular imports, hotspots, blast radius. Things no other Python tool surfaces.
- Agent-friendly write surface — symbol-level patch / rename / replace with byte-range edits and a transactional undo log, so coding agents don't have to re-read entire files to make safe changes.
First thing you run on an unfamiliar codebase, before reading a single line of code.
Architecture
src/wyolet/symbol/
├── cli.py Typer root CLI
├── commands/ Thin command views (audit, loc, map, analyze,
│ search, code, outline, callers, patch, refresh,
│ undo, init, + symbol-level ops for MCP)
├── checkers/ @register'd checkers
│ ├── stack.py tech stack from deps
│ ├── entrypoints.py __main__ guards, framework hooks
│ ├── orphans.py unreachable files
│ ├── side_effects.py bare module-level calls
│ ├── swallowed.py silenced exceptions
│ ├── todos.py TODO/FIXME/HACK/XXX
│ ├── unused_deps.py declared but unimported
│ └── code_structure.py functions, classes, type coverage
├── shared/ Core infrastructure
│ ├── context.py AnalysisContext (root, spec, cache, config)
│ ├── ast_cache.py parse once, share across checkers
│ ├── registry.py @register + views()
│ ├── runner.py dispatches file/project checkers
│ ├── spec.py spec loader
│ ├── config_resolver.py spec → packages → project-config layering
│ ├── framework_detector.py
│ ├── pipeline.py @hook(pipeline, priority)
│ ├── graph.py import graph primitives
│ ├── symbol_index.py qualified-path index for MCP read/write tools
│ └── linguist/ GitHub Linguist port (500+ langs)
└── data/
├── spec.toml Global baseline spec
└── specs/NAME/ Per-package specs (237 packages: django, fastapi,
celery, sqlalchemy, langchain, pydantic, ...)
Contributing
The fastest ways to help:
- Add a package spec for a library we don't cover yet — no Python required, just TOML. See #3 and
CONTRIBUTING.md. - Run
symbolon your real Python project and file false positives. See #6. - Benchmark the MCP surface against native Read/Grep/Edit on representative agent tasks. See #7.
- Wire
symbol mcpinto opencode / Cursor / Continue / Zed. See #8.
Pinned issues on the repo show what's most useful right now.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file wyolet_symbol-0.2.0.tar.gz.
File metadata
- Download URL: wyolet_symbol-0.2.0.tar.gz
- Upload date:
- Size: 10.5 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f6bfd41c46fb9b16ac336f37a4081629c1cb8004a3b25456c2fb3a28a75a7db4
|
|
| MD5 |
15266115604e59fe6e1fe4f4cd38d6ec
|
|
| BLAKE2b-256 |
422220a8befb289857a398e83bca2c2aac09b85c75f7937738270f621e71a678
|
Provenance
The following attestation bundles were made for wyolet_symbol-0.2.0.tar.gz:
Publisher:
release.yml on wyolet/symbol
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wyolet_symbol-0.2.0.tar.gz -
Subject digest:
f6bfd41c46fb9b16ac336f37a4081629c1cb8004a3b25456c2fb3a28a75a7db4 - Sigstore transparency entry: 1589034237
- Sigstore integration time:
-
Permalink:
wyolet/symbol@2cb6b8c060e3fa319c6e7e1cdc6feacf8599c8cc -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/wyolet
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@2cb6b8c060e3fa319c6e7e1cdc6feacf8599c8cc -
Trigger Event:
push
-
Statement type:
File details
Details for the file wyolet_symbol-0.2.0-py3-none-any.whl.
File metadata
- Download URL: wyolet_symbol-0.2.0-py3-none-any.whl
- Upload date:
- Size: 10.5 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
699de5005df77d64af65c53365b2e41de96044b918cceef8fbc7c06b00207b9d
|
|
| MD5 |
b8dd6de97b12c833a6d91ece4f538f63
|
|
| BLAKE2b-256 |
6a9e552a4377079dd1ba9204571d84b79b0ef94ca34ddd2014a0e806160e8c86
|
Provenance
The following attestation bundles were made for wyolet_symbol-0.2.0-py3-none-any.whl:
Publisher:
release.yml on wyolet/symbol
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wyolet_symbol-0.2.0-py3-none-any.whl -
Subject digest:
699de5005df77d64af65c53365b2e41de96044b918cceef8fbc7c06b00207b9d - Sigstore transparency entry: 1589034275
- Sigstore integration time:
-
Permalink:
wyolet/symbol@2cb6b8c060e3fa319c6e7e1cdc6feacf8599c8cc -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/wyolet
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@2cb6b8c060e3fa319c6e7e1cdc6feacf8599c8cc -
Trigger Event:
push
-
Statement type: