https://github.com/wyolet/symbol
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).
https://github.com/wyolet/symbol
ast claude-code cli code-intelligence developer-tools linguist mcp python static-analysis
Last synced: 1 day ago
JSON representation
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).
- Host: GitHub
- URL: https://github.com/wyolet/symbol
- Owner: wyolet
- License: mit
- Created: 2026-04-12T12:59:21.000Z (about 1 month ago)
- Default Branch: main
- Last Pushed: 2026-05-21T01:59:18.000Z (4 days ago)
- Last Synced: 2026-05-21T03:14:49.117Z (4 days ago)
- Topics: ast, claude-code, cli, code-intelligence, developer-tools, linguist, mcp, python, static-analysis
- Language: Python
- Size: 798 KB
- Stars: 0
- Watchers: 0
- Forks: 2
- Open Issues: 6
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Security: SECURITY.md
Awesome Lists containing this project
README
# 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 `UserService` defined, who calls `db.commit`, what's the body of `process_payment` — without re-reading 800 lines of file?
Static analysis only — `symbol` never imports or executes the target code.
> **Status:** [`wyolet-symbol`](https://pypi.org/project/wyolet-symbol/) on PyPI (CLI command is `symbol` — the bare name is reserved by PyPI policy). Python is the proving ground; **Go** and **TypeScript** are next on the roadmap.

## Install
### CLI only
```bash
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:
```bash
# 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`](docs/integrations/opencode.md). Cursor, Continue, and Zed integrations are tracked in [#8](https://github.com/wyolet/symbol/issues/8); help wanted. The Claude-Code-specific glue (skill + hooks) does not port automatically.
### Updating / uninstall
```bash
uv tool upgrade wyolet-symbol # or: uv tool uninstall wyolet-symbol
claude plugin update symbol # or: claude plugin uninstall symbol
```
## Commands
### `symbol audit ` — Full codebase audit
Runs all registered checkers: stack detection, entry points, orphan files, side effects, swallowed exceptions, TODOs, unused deps, code structure metrics.
```bash
symbol audit /path/to/project
symbol -v audit /path/to/project # verbose — full detail
symbol /path/to/project # shortcut — defaults to audit
```
### `symbol loc ` — 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.
```bash
symbol loc /path/to/project
```
### `symbol map ` — Import graph analysis
Circular imports, hotspots, fragile modules, deep chains, leaf modules, blast radius.
```bash
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
```bash
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 ` — Byte-range edit
Edit by line range without sending an `old_string` payload. Replace (with content), delete (empty content), or insert (zero-width range).
```bash
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 `, `symbol dump `, `symbol init `, `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`.
```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`:
```toml
[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`](schemas/symbol.config.schema.json). With
Taplo, you can wire it up for both forms:
```toml
[[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`](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. `symbol` fills 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](https://github.com/wyolet/symbol/issues/3) and [`CONTRIBUTING.md`](CONTRIBUTING.md).
- **Run `symbol` on your real Python project** and file false positives. See [#6](https://github.com/wyolet/symbol/issues/6).
- **Benchmark the MCP surface** against native Read/Grep/Edit on representative agent tasks. See [#7](https://github.com/wyolet/symbol/issues/7).
- **Wire `symbol mcp` into opencode / Cursor / Continue / Zed**. See [#8](https://github.com/wyolet/symbol/issues/8).
Pinned issues on the repo show what's most useful right now.
## License
MIT