Symbol index with associated code reading tools for AI coding agent 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 the code.
uncoded builds a static navigation index for the codebase. Agents load it at the start of a task and navigate directly to what they need, without guessing or grepping.
It also ships uncoded body to read symbol bodies and uncoded refs to find
every reference to a symbol. References cover callers, dead-symbol checks, and
the full set of sites to update before a rename.
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.
.uncoded/docs.yaml: a heading outline of configured Markdown files. Each
file nests its #-prefixed headings as keys. Leaf headings map to null. Agents
load this to orient to the documentation. They then navigate to a heading with
Read or grep. uncoded generates it only when doc-roots is configured. It
is an outline only. uncoded body, uncoded refs, and stubs do not apply to
Markdown.
Skills, written to both .claude/skills/ and .agents/skills/:
uncoded-code-navigation: the code dispatch rule: loadnamespace.yamlfirst, read.pyistubs before source, useuncoded bodyanduncoded refsfor symbol operations. Generated whensource-rootsis configured.uncoded-doc-navigation: the docs navigation rule: loaddocs.yamlat session start, then useReadorgrepto reach a heading. Generated whendoc-rootsis configured.uncoded-coherence-review: a structured diagnostic sweep for naming drift and incoherence (see Coherence review). Generated whensource-rootsis configured.
Add these lines to your AGENTS.md or CLAUDE.md to load the navigation skills
every session. Skills are on-demand by default. Tying the load to an action
agents are about to take prompts them to act on it:
## Before you start
- Load the `uncoded-code-navigation` skill before searching, reading or editing any code.
- Load the `uncoded-doc-navigation` skill before searching, reading or editing any docs.
Install uv
uncoded runs via uv. Install uv if you don't
already have it. No separate uncoded install is needed. uvx runs it from PyPI
on demand.
Configure
Add a [tool.uncoded] section to your pyproject.toml:
[tool.uncoded]
source-roots = ["src", "tests"]
doc-roots = ["docs", "README.md"] # dirs walked for *.md, or individual .md files
source-roots and doc-roots are each optional. At least one must be set.
source-roots drives the code index (namespace.yaml + stubs). doc-roots
drives the doc index (docs.yaml). Entries in doc-roots can be directories (all
*.md files walked recursively) or individual .md files.
Non-Python repos can use .uncoded.toml in the project root instead, with
the same keys at the top level. No [tool.uncoded] wrapper is needed:
doc-roots = ["docs"]
pyproject.toml takes precedence over a sibling .uncoded.toml only when it
carries a [tool.uncoded] section. If both files configure uncoded in the same
directory, uncoded reports a configuration error. Configure in one file only.
Across directories, the nearer file wins. uncoded never reads either file from
inside the .uncoded/ directory.
Use
uvx uncoded sync
Run uvx uncoded sync from the repo root. It reads pyproject.toml (or
.uncoded.toml) to find your configured roots and builds the index and skill
files.
Commit the generated .uncoded/ directory so agents working in the repo always
have a current index.
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: uvx 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
Use the check subcommand for CI or scripted checks that must not modify the
working tree:
uvx uncoded check
It runs the same pipeline but writes nothing. It exits 0 if every generated file is byte-identical to what a rebuild would produce. It exits 1 otherwise, printing which files would change. A stale index is a silent failure mode. Agents read misleading names and signatures. Gate on this in CI even alongside a pre-commit hook.
Retrieve a symbol body
Use the body subcommand when you need a symbol's implementation, not just its
signature from the stub:
uvx uncoded body <name_path> --in <relative_path>
name_path is a slash-separated path: one segment (fn) for a top-level
symbol, two for a class member (Class/method). --in is the source file's
path (relative to cwd). The command prints the source text of the symbol to
stdout, byte-identical to what's on disk. No reformatting, no ast.unparse
normalisation.
For example, to retrieve the body of resolve_body from src/uncoded/body.py:
uvx uncoded body resolve_body --in src/uncoded/body.py
Find references to a symbol
Use the refs subcommand for impact analysis. Run it before a rename, signature
change, or delete. Run it also to confirm a symbol is dead before removing it:
uvx uncoded refs <name_path> --in <relative_path>
name_path follows the same convention as body: one segment for a top-level
symbol, two for a class member (Class/method).
Output is one reference per line as <rel_path>:<line>:<col>. Line and column
are 1-indexed. Results are sorted by path, then line, then column. It exits 0 on
success. Empty output means no references.
For example, to find all callers of resolve_body:
uvx uncoded refs resolve_body --in src/uncoded/body.py
How agents use it
Agents load the navigation skills and follow this protocol once uncoded is set
up:
- Load the orientation artefacts. Read
.uncoded/namespace.yamlto see every symbol at a glance. Whendoc-rootsis configured, also read.uncoded/docs.yaml, the heading outline of all docs. Headings are literal text. UseReadorgrepto navigate to a section. - Read the relevant
.pyistubs to understand imports, signatures, constants, and class members. - Run
uvx uncoded body <name_path> --in <relative_path>when they need implementation detail for a specific symbol. - Run
uvx uncoded refs <name_path> --in <relative_path>to find every reference to a symbol: callers, dead-symbol checks. See Find references to a symbol for detail. - Edit a symbol using
Editwithuncoded body's output asold_string. - Rename across the codebase using
uncoded refsto enumerate every site, thenEditat each. - Safely delete by running
uncoded refsfirst. The output must be empty. ThenEditto remove.
Each tool owns one job. uncoded provides the stable map and signature index,
code through namespace.yaml and docs through docs.yaml. uncoded body
resolves a symbol's source body. uncoded refs maps every reference. Agents do
not grep, guess line numbers, or do 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 an /uncoded-coherence-review skill that runs a
structured diagnostic sweep to find these problems.
Invoke it in Claude Code:
/uncoded-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
uncoded body. - Structural: checks for boundary violations (private symbols imported across modules), overgrown public surfaces, cross-domain imports, and zero-reference public symbols.
The review saves a timestamped Markdown report to .uncoded/reviews/, with
verbatim evidence and a confidence level (high / medium / low) for each finding.
The review only reports. The human decides what to follow up.
Upgrading from v1
Version 2.0.0 replaces injection with skills. In v1, uncoded sync always
injected navigation guidance into AGENTS.md/CLAUDE.md. In v2 it ships as
on-demand skills. Agents load them when relevant. Four manual steps after
upgrading:
-
Remove old marker blocks from your
AGENTS.mdandCLAUDE.md. Look for and delete these blocks:<!-- uncoded:start ... --> ... <!-- uncoded:end -->
and
<!-- uncoded:docs:start ... --> ... <!-- uncoded:docs:end -->
uncoded no longer manages these sections. Leaving them in place is harmless but they are now dead markup.
-
Update any skill pointer that references
coherence-reviewtouncoded-coherence-review. The coherence review skill was renamed with theuncoded-prefix to match the navigation skills. -
Remove the
instruction-filesconfig key if yourpyproject.tomlor.uncoded.tomlhas it. uncoded no longer reads this key. Leaving it in place causes no error. -
Restore always-on navigation if you want v1 behaviour back. Add these lines to your
AGENTS.mdandCLAUDE.md:## Before you start - Load the `uncoded-code-navigation` skill before searching, reading or editing any code. - Load the `uncoded-doc-navigation` skill before searching, reading or editing any docs.
Contributing
See AGENTS.md.
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 uncoded-2.1.1.tar.gz.
File metadata
- Download URL: uncoded-2.1.1.tar.gz
- Upload date:
- Size: 106.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 |
d79d9f7d0e2acea5b02dd48e7d8796bef73cb865b07e87b546ed5e67b8a527e5
|
|
| MD5 |
2a72c56538f5d51a91c68a2e7eaf2d58
|
|
| BLAKE2b-256 |
13f6da05131fc91ebbe6b8e42c40b870de6517fce8433d1ce7ecc4d183ec851f
|
Provenance
The following attestation bundles were made for uncoded-2.1.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-2.1.1.tar.gz -
Subject digest:
d79d9f7d0e2acea5b02dd48e7d8796bef73cb865b07e87b546ed5e67b8a527e5 - Sigstore transparency entry: 1964967842
- Sigstore integration time:
-
Permalink:
alimanfoo/uncoded@304e06057b4d7b66c14ca2822d0efd698f31c734 -
Branch / Tag:
refs/tags/v2.1.1 - Owner: https://github.com/alimanfoo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@304e06057b4d7b66c14ca2822d0efd698f31c734 -
Trigger Event:
release
-
Statement type:
File details
Details for the file uncoded-2.1.1-py3-none-any.whl.
File metadata
- Download URL: uncoded-2.1.1-py3-none-any.whl
- Upload date:
- Size: 41.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 |
f606ad737d44d285719c628eaa8c1fa1b8660d811f622afeefee5ca96267844a
|
|
| MD5 |
34f6d1c9ead92973cfe1035f54f01990
|
|
| BLAKE2b-256 |
c6cfbf525a0687545bed4c8baa9dcab897031db1182f9f1ea260ab05c115269d
|
Provenance
The following attestation bundles were made for uncoded-2.1.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-2.1.1-py3-none-any.whl -
Subject digest:
f606ad737d44d285719c628eaa8c1fa1b8660d811f622afeefee5ca96267844a - Sigstore transparency entry: 1964968044
- Sigstore integration time:
-
Permalink:
alimanfoo/uncoded@304e06057b4d7b66c14ca2822d0efd698f31c734 -
Branch / Tag:
refs/tags/v2.1.1 - Owner: https://github.com/alimanfoo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@304e06057b4d7b66c14ca2822d0efd698f31c734 -
Trigger Event:
release
-
Statement type: