Skip to main content

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 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 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.

symbol audit on a FastAPI app

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. 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 and CONTRIBUTING.md.
  • Run symbol on 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 mcp into opencode / Cursor / Continue / Zed. See #8.

Pinned issues on the repo show what's most useful right now.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wyolet_symbol-0.2.0.tar.gz (10.5 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

wyolet_symbol-0.2.0-py3-none-any.whl (10.5 MB view details)

Uploaded Python 3

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

Hashes for wyolet_symbol-0.2.0.tar.gz
Algorithm Hash digest
SHA256 f6bfd41c46fb9b16ac336f37a4081629c1cb8004a3b25456c2fb3a28a75a7db4
MD5 15266115604e59fe6e1fe4f4cd38d6ec
BLAKE2b-256 422220a8befb289857a398e83bca2c2aac09b85c75f7937738270f621e71a678

See more details on using hashes here.

Provenance

The following attestation bundles were made for wyolet_symbol-0.2.0.tar.gz:

Publisher: release.yml on wyolet/symbol

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for wyolet_symbol-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 699de5005df77d64af65c53365b2e41de96044b918cceef8fbc7c06b00207b9d
MD5 b8dd6de97b12c833a6d91ece4f538f63
BLAKE2b-256 6a9e552a4377079dd1ba9204571d84b79b0ef94ca34ddd2014a0e806160e8c86

See more details on using hashes here.

Provenance

The following attestation bundles were made for wyolet_symbol-0.2.0-py3-none-any.whl:

Publisher: release.yml on wyolet/symbol

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page