Symbol indexes and language-server setup for AI-assisted code navigation
Project description
uncoded
AI coding agents navigate codebases poorly. They grep for guessed keywords, skim the first few lines of files, and fill gaps from pretraining rather than reading the actual code. The result is plausible-looking output built on a hallucinated understanding of code that's sitting right there, unread.
uncoded builds a static navigation index so agents can orient themselves at the start of a task and navigate deterministically to what they need — no guessing, no grep.
It also wires up a language server so the agent can find references, rename, and edit symbols by name — no grep, no manual find-and-replace.
What it generates
Running uncoded sync produces:
.uncoded/namespace.yaml — a hierarchical YAML file listing every symbol:
directories, files, classes (with attributes and methods), functions. Covers
all configured source roots. An agent can load this at the start of a task
and immediately know the full vocabulary of the codebase.
.uncoded/stubs/ — one .pyi stub per source file, with imports, full
signatures (parameter names, types, return types), module constants, and
class attributes.
.claude/skills/coherence-review/SKILL.md and
.agents/skills/coherence-review/SKILL.md — a coherence review skill,
written to both Claude Code and Codex skill directories (see
Coherence review below).
uncoded also injects a navigation protocol into CLAUDE.md/AGENTS.md, so agents
working in the repo pick up the instructions automatically.
Install
pip install uncoded
Or with uv:
uv add uncoded
Configure
Add a [tool.uncoded] section to your pyproject.toml:
[tool.uncoded]
source-roots = ["src", "tests"]
Use
uncoded sync
Run it from the repo root. It reads pyproject.toml to find your source
roots, builds the index, and updates CLAUDE.md/AGENTS.md.
Commit the generated .uncoded/ directory so agents working
in the repo always have a current index.
Set up the language server
uncoded setup
Generates the MCP and Claude Code configuration that wires up Serena (language-server bridge) and ty (Python backend), so agents can find references, rename, and edit symbols by name. Safe to re-run. See Using uncoded with a language server below for the generated files and notes on non-Claude-Code agents.
Keep it current with pre-commit
Add uncoded sync as a pre-commit hook so the index stays in sync
automatically:
- repo: local
hooks:
- id: uncoded
name: uncoded
entry: uncoded sync
language: system
pass_filenames: false
Like ruff format: if uncoded sync modifies any files, the commit
fails and you stage the updated index before committing again.
You can also set up your CI to run pre-commit run --all-files to verify the index is up to date.
Verify the index is fresh
For CI or scripted checks that must not modify the working tree, use
the check subcommand:
uncoded check
It runs the same pipeline but writes nothing. Exits 0 if every generated file is byte-identical to what a rebuild would produce, and 1 otherwise — printing which files would change. A stale index is a silent failure mode (agents read misleading names and signatures), so gating on this in CI is worthwhile even alongside a pre-commit hook.
How agents use it
When uncoded is set up, a navigation section is automatically maintained in
the configured instruction files (by default, CLAUDE.md and AGENTS.md).
Agents following that protocol:
- Read
.uncoded/namespace.yamlto orient — every symbol, at a glance. - Read the relevant
.pyistubs to understand imports, signatures, constants, and class members. - Use Serena's
find_symbol(..., include_body=True)when they need implementation detail for a specific symbol.
The split is deliberate: uncoded provides a stable map and signature index;
Serena resolves the current source body. No grep, no stale line-number
coordinates, no offset arithmetic.
Coherence review
AI coding agents tend to leave codebases in an incoherent state: names that
no longer match behaviour, docstrings that describe stale signatures, dead
symbols, pattern changes applied in some places but not others. uncoded sync
installs a /coherence-review skill that runs a structured diagnostic sweep to
find these problems.
Invoke it in Claude Code:
/coherence-review
The review works in four sweeps:
- Orient — loads
namespace.yamland forms a vocabulary map. - Lexical — scans the namespace for naming inconsistency: concept
duplication, qualifier accretion (
_v2,_legacy,_final), vocabulary islands, name collision with drift. - Promissory — checks each public symbol's name / signature / docstring
triple for internal disagreement. Names and signatures come from the
stub; docstrings come from Serena's
find_symbol(include_body=True). - Structural — checks for boundary violations (private symbols imported across modules), overgrown public surfaces, cross-domain imports, and zero-caller public symbols.
Output is a timestamped Markdown report saved to .uncoded/reviews/, with
verbatim evidence and a confidence level (high / medium / low) for each
finding. The review only reports — it proposes no fixes. The human decides
what to follow up.
Using uncoded with a language server
Symbol-level operations — finding callers, reading or editing a single
symbol, renaming, safe deletion — are better served by a language server
than by grep and freeform text edits. Uncoded's map supplies the
name_path and relative_path these tools take as input.
The recommended setup is oraios/serena as the MCP bridge with
astral-sh/ty as the Python language-server backend. Serena launches
via uvx, so there's nothing to install globally; ty is downloaded by
Serena on first use.
Setup
uv run uncoded setup
Generates three files, tailored for Claude Code:
.mcp.json— registers Serena as an MCP server, launched viauvx..serena/project.yml— picks ty as the backend, ignores.uncoded/, and narrows Serena's tool surface (dropsexecute_shell_command, the memory tools, onboarding helpers, and the dashboard opener)..claude/settings.json— enables the Serena server and allowlists its navigation and edit tools.
Safe to re-run: JSON files merge into existing content (so pre-existing MCP servers and permissions are preserved), and the Serena project YAML is left alone once present. Restart your agent afterwards so the new MCP server is picked up.
If you're not using Claude Code, the generated .serena/project.yml is
MCP-client-agnostic, and .mcp.json can serve as a starting point —
replace claude-code with your client's context name.
Dev setup
Clone, install dependencies, and wire up the pre-commit hooks:
git clone https://github.com/alimanfoo/uncoded
cd uncoded
uv sync --extra dev
uv run pre-commit install
Run the tests (branch coverage is enforced; see [tool.coverage.report] in
pyproject.toml for the threshold):
uv run pytest
To run a subset of tests without the coverage gate:
uv run pytest tests/test_stubs.py --no-cov
Run the same checks CI's lint job runs:
uv run pre-commit run --all-files
Note for Windows contributors
CLAUDE.md is a symlink to AGENTS.md (single source). macOS and Linux
handle this transparently; on Windows, git's core.symlinks setting must
be enabled, or the checkout writes CLAUDE.md as a plain file containing
the literal string AGENTS.md and the navigation section drifts.
Releasing
GitHub releases publish to PyPI through .github/workflows/publish.yml.
The workflow uses PyPI Trusted Publishing, so it does not need a PYPI_TOKEN
or any other long-lived publishing secret.
The PyPI trusted publisher is configured for:
- PyPI project:
uncoded - Owner:
alimanfoo - Repository:
uncoded - Workflow:
publish.yml - Environment:
pypi
To release, create and publish a GitHub release from the release tag. The
published release event builds the source distribution and wheel, then
uploads them to PyPI.
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
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 uncoded-0.7.1.tar.gz.
File metadata
- Download URL: uncoded-0.7.1.tar.gz
- Upload date:
- Size: 93.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
36d062a519fd4c95cd0e3ba420fa72afe24fa31f76d6504c48bdcca177dc9575
|
|
| MD5 |
a6aae1dfbb29f7a88f3f6fade2f19d3e
|
|
| BLAKE2b-256 |
245d87729b7420c0493d244822b02a23e65f3158e75adb5263caddd846239b40
|
Provenance
The following attestation bundles were made for uncoded-0.7.1.tar.gz:
Publisher:
publish.yml on alimanfoo/uncoded
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
uncoded-0.7.1.tar.gz -
Subject digest:
36d062a519fd4c95cd0e3ba420fa72afe24fa31f76d6504c48bdcca177dc9575 - Sigstore transparency entry: 1538109103
- Sigstore integration time:
-
Permalink:
alimanfoo/uncoded@a32588c0e73a5e3744baf900a1cdcec8e1807b93 -
Branch / Tag:
refs/tags/v0.7.1 - Owner: https://github.com/alimanfoo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a32588c0e73a5e3744baf900a1cdcec8e1807b93 -
Trigger Event:
release
-
Statement type:
File details
Details for the file uncoded-0.7.1-py3-none-any.whl.
File metadata
- Download URL: uncoded-0.7.1-py3-none-any.whl
- Upload date:
- Size: 32.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9c05b69190d8f2645d0d2fdb73af046586ed7ed5e47e5ef261b494f0a40e7b5e
|
|
| MD5 |
e02a01acdd120082f9aecf580c0eb370
|
|
| BLAKE2b-256 |
481508213bd264df48bc9151ffe2e39ac3857472fc9ce0c1175b817a422a8fbd
|
Provenance
The following attestation bundles were made for uncoded-0.7.1-py3-none-any.whl:
Publisher:
publish.yml on alimanfoo/uncoded
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
uncoded-0.7.1-py3-none-any.whl -
Subject digest:
9c05b69190d8f2645d0d2fdb73af046586ed7ed5e47e5ef261b494f0a40e7b5e - Sigstore transparency entry: 1538109261
- Sigstore integration time:
-
Permalink:
alimanfoo/uncoded@a32588c0e73a5e3744baf900a1cdcec8e1807b93 -
Branch / Tag:
refs/tags/v0.7.1 - Owner: https://github.com/alimanfoo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a32588c0e73a5e3744baf900a1cdcec8e1807b93 -
Trigger Event:
release
-
Statement type: