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.1.tar.gz (20.8 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.1-py3-none-any.whl (20.8 MB view details)

Uploaded Python 3

File details

Details for the file wyolet_symbol-0.2.1.tar.gz.

File metadata

  • Download URL: wyolet_symbol-0.2.1.tar.gz
  • Upload date:
  • Size: 20.8 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.1.tar.gz
Algorithm Hash digest
SHA256 fb518ef1e9433ea318242225d05683e054d07b5a4915ead1396c0df92a2d9395
MD5 eb0baaecf48540361a6014d37ad3c057
BLAKE2b-256 044276853e34c97f3d10d4da1fae671b7430cdbec86750f01c45118ce87c02f4

See more details on using hashes here.

Provenance

The following attestation bundles were made for wyolet_symbol-0.2.1.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.1-py3-none-any.whl.

File metadata

  • Download URL: wyolet_symbol-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 20.8 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 591d65df9db4c3fc28037ba8745e035b337a6d8765072d0c58de1a96469bd430
MD5 682b2f51ae5fae82df0f83bb7c770317
BLAKE2b-256 fc34e6436f641531cf90149e99186936b18a427114e9795816cd7eb60e0d5c46

See more details on using hashes here.

Provenance

The following attestation bundles were made for wyolet_symbol-0.2.1-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