uncoded 1.2.0__tar.gz → 2.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- uncoded-1.2.0/AGENTS.md → uncoded-2.0.0/.agents/skills/uncoded-code-navigation/SKILL.md +15 -86
- {uncoded-1.2.0/.agents/skills/coherence-review → uncoded-2.0.0/.agents/skills/uncoded-coherence-review}/SKILL.md +2 -2
- uncoded-2.0.0/.agents/skills/uncoded-doc-navigation/SKILL.md +22 -0
- uncoded-2.0.0/.claude/skills/uncoded-code-navigation/SKILL.md +109 -0
- {uncoded-1.2.0/.claude/skills/coherence-review → uncoded-2.0.0/.claude/skills/uncoded-coherence-review}/SKILL.md +2 -2
- uncoded-2.0.0/.claude/skills/uncoded-doc-navigation/SKILL.md +22 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/docs.yaml +2 -5
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/namespace.yaml +44 -75
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/src/uncoded/cli.pyi +4 -2
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/src/uncoded/config.pyi +0 -2
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/src/uncoded/docs_map.pyi +1 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/src/uncoded/extract.pyi +1 -0
- uncoded-2.0.0/.uncoded/stubs/src/uncoded/read_helpers.pyi +7 -0
- uncoded-2.0.0/.uncoded/stubs/src/uncoded/skill.pyi +30 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/tests/test_cli.pyi +6 -21
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/tests/test_config.pyi +0 -10
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/tests/test_docs_map.pyi +6 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/tests/test_extract.pyi +3 -0
- uncoded-2.0.0/.uncoded/stubs/tests/test_skill.pyi +95 -0
- uncoded-2.0.0/AGENTS.md +70 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/PKG-INFO +83 -20
- {uncoded-1.2.0 → uncoded-2.0.0}/README.md +81 -19
- {uncoded-1.2.0 → uncoded-2.0.0}/pyproject.toml +1 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/src/uncoded/cli.py +83 -94
- uncoded-1.2.0/src/uncoded/dispatch_rule.md → uncoded-2.0.0/src/uncoded/code_navigation.md +11 -12
- {uncoded-1.2.0 → uncoded-2.0.0}/src/uncoded/coherence_review.md +0 -5
- {uncoded-1.2.0 → uncoded-2.0.0}/src/uncoded/config.py +0 -10
- uncoded-2.0.0/src/uncoded/doc_navigation.md +17 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/src/uncoded/docs_map.py +13 -2
- {uncoded-1.2.0 → uncoded-2.0.0}/src/uncoded/extract.py +11 -6
- uncoded-2.0.0/src/uncoded/read_helpers.py +25 -0
- uncoded-2.0.0/src/uncoded/skill.py +138 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/src/uncoded/sync.py +2 -2
- {uncoded-1.2.0 → uncoded-2.0.0}/tests/test_cli.py +31 -158
- {uncoded-1.2.0 → uncoded-2.0.0}/tests/test_config.py +2 -35
- {uncoded-1.2.0 → uncoded-2.0.0}/tests/test_docs_map.py +21 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/tests/test_extract.py +15 -0
- uncoded-2.0.0/tests/test_skill.py +313 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/uv.lock +23 -0
- uncoded-1.2.0/.uncoded/stubs/src/uncoded/instruction_files.pyi +0 -25
- uncoded-1.2.0/.uncoded/stubs/src/uncoded/skill.pyi +0 -12
- uncoded-1.2.0/.uncoded/stubs/tests/test_instruction_files.pyi +0 -109
- uncoded-1.2.0/.uncoded/stubs/tests/test_skill.pyi +0 -45
- uncoded-1.2.0/src/uncoded/docs_rule.md +0 -5
- uncoded-1.2.0/src/uncoded/instruction_files.py +0 -135
- uncoded-1.2.0/src/uncoded/skill.py +0 -43
- uncoded-1.2.0/tests/test_instruction_files.py +0 -380
- uncoded-1.2.0/tests/test_skill.py +0 -112
- {uncoded-1.2.0 → uncoded-2.0.0}/.github/workflows/ci.yml +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.github/workflows/publish.yml +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.gitignore +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.markdownlint-cli2.yaml +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.pre-commit-config.yaml +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/src/uncoded/__init__.pyi +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/src/uncoded/ast_helpers.pyi +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/src/uncoded/body.pyi +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/src/uncoded/namespace_map.pyi +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/src/uncoded/refs.pyi +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/src/uncoded/resolver.pyi +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/src/uncoded/stubs.pyi +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/src/uncoded/sync.pyi +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/src/uncoded/yaml_tree.pyi +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/tests/test_body.pyi +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/tests/test_namespace_map.pyi +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/tests/test_refs.pyi +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/tests/test_stubs.pyi +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/tests/test_sync.pyi +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/.uncoded/stubs/tests/test_uncoded.pyi +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/CLAUDE.md +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/LICENSE +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/src/uncoded/__init__.py +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/src/uncoded/ast_helpers.py +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/src/uncoded/body.py +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/src/uncoded/namespace_map.py +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/src/uncoded/refs.py +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/src/uncoded/resolver.py +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/src/uncoded/stubs.py +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/src/uncoded/yaml_tree.py +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/tests/__init__.py +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/tests/test_body.py +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/tests/test_namespace_map.py +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/tests/test_refs.py +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/tests/test_stubs.py +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/tests/test_sync.py +0 -0
- {uncoded-1.2.0 → uncoded-2.0.0}/tests/test_uncoded.py +0 -0
|
@@ -1,79 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
name: uncoded-code-navigation
|
|
3
|
+
description: Use before searching, reading, or editing Python source in a codebase indexed by uncoded — locating a symbol, reading a definition, or checking references before a refactor, rename, or delete.
|
|
4
|
+
---
|
|
2
5
|
|
|
3
|
-
|
|
6
|
+
# Code Navigation
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
reading the actual code. System prompts encourage this with "make reasonable
|
|
8
|
-
assumptions." The result is plausible-looking output built on a hallucinated
|
|
9
|
-
understanding of code that's sitting right there, unread.
|
|
10
|
-
|
|
11
|
-
## Approach
|
|
12
|
-
|
|
13
|
-
A static, pre-computed index gives agents a top-down view of a codebase.
|
|
14
|
-
The agent loads the index at the start of a task, sees the full vocabulary
|
|
15
|
-
of the code, and navigates deterministically to what it needs — no guessing,
|
|
16
|
-
no grep.
|
|
17
|
-
|
|
18
|
-
Index artefacts — generated from the configured roots:
|
|
19
|
-
|
|
20
|
-
1. **Namespace map** (`.uncoded/namespace.yaml`) — a hierarchical YAML file
|
|
21
|
-
listing all symbols: directories, files, classes (with attributes
|
|
22
|
-
and methods), and functions. Covers both source and tests. Loaded into
|
|
23
|
-
context before any task begins. Gives the agent a world view.
|
|
24
|
-
|
|
25
|
-
2. **Stub files** (`.uncoded/stubs/`) — one `.pyi` per source file, with
|
|
26
|
-
imports, full signatures (parameter names, types, return types),
|
|
27
|
-
module constants, and class attributes.
|
|
28
|
-
|
|
29
|
-
3. **Doc map** (`.uncoded/docs.yaml`) — a heading outline of every Markdown
|
|
30
|
-
file in configured `doc-roots`. Each file nests its ATX headings as keys.
|
|
31
|
-
Agents load this to orient to the documentation, then navigate to a
|
|
32
|
-
heading with `Read` or `grep`. Generated only when `doc-roots` is set.
|
|
33
|
-
Outline only — no `uncoded body`, `uncoded refs`, or stubs for Markdown.
|
|
34
|
-
|
|
35
|
-
Alongside the index, uncoded ships `uncoded body` to read symbol bodies and
|
|
36
|
-
`uncoded refs` to find all references. See "How to read and edit code in
|
|
37
|
-
this codebase" below for the dispatch rule.
|
|
38
|
-
|
|
39
|
-
## Commands
|
|
40
|
-
|
|
41
|
-
This project uses [uv](https://docs.astral.sh/uv/). Run `uncoded` commands
|
|
42
|
-
via `uvx` so they run the published package without needing to install it;
|
|
43
|
-
run project tooling (`pytest`, `pre-commit`) via `uv run`.
|
|
44
|
-
|
|
45
|
-
```sh
|
|
46
|
-
# Generate (or update) the namespace map, stub files, docs.yaml,
|
|
47
|
-
# and instruction-file sections
|
|
48
|
-
uvx uncoded sync
|
|
49
|
-
|
|
50
|
-
# Verify the index without writing; exits non-zero if any file would change
|
|
51
|
-
uvx uncoded check
|
|
52
|
-
|
|
53
|
-
# Print the source body of a named symbol to stdout
|
|
54
|
-
uvx uncoded body <name_path> --in <relative_path>
|
|
55
|
-
|
|
56
|
-
# Find references to a symbol
|
|
57
|
-
uvx uncoded refs <name_path> --in <relative_path>
|
|
58
|
-
|
|
59
|
-
# Run tests (branch coverage enforced; see [tool.coverage.report]
|
|
60
|
-
# in pyproject.toml)
|
|
61
|
-
uv run pytest
|
|
62
|
-
|
|
63
|
-
# Run a subset of tests without the coverage gate
|
|
64
|
-
uv run pytest tests/test_stubs.py --no-cov
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
<!-- uncoded:start sha256=5d50217d -->
|
|
68
|
-
## How to read and edit code in this codebase
|
|
69
|
-
|
|
70
|
-
This repo uses [uncoded](https://github.com/alimanfoo/uncoded) to maintain
|
|
71
|
-
a symbol index over its source code, with two associated tools:
|
|
8
|
+
This codebase uses [uncoded](https://github.com/alimanfoo/uncoded) to maintain
|
|
9
|
+
a symbol index over its source code, with two associated CLI tools:
|
|
72
10
|
`uncoded body` for reading a symbol's body and `uncoded refs` for finding
|
|
73
11
|
references.
|
|
74
|
-
The point of this scaffolding is one rule.
|
|
75
12
|
|
|
76
|
-
|
|
13
|
+
## The dispatch rule
|
|
77
14
|
|
|
78
15
|
**If your search term is the name of a Python symbol — a class, function,
|
|
79
16
|
method, attribute, or module-level constant — use the index. If it's a
|
|
@@ -81,17 +18,17 @@ pattern, regex, or free-text phrase, use grep.**
|
|
|
81
18
|
|
|
82
19
|
This applies to every tool call where you are trying to find code, not
|
|
83
20
|
just the first one in the session. The pretrained reflex for "find X" is
|
|
84
|
-
grep, and that reflex is wrong here. `grep -rn 'def
|
|
85
|
-
function's body
|
|
86
|
-
'
|
|
87
|
-
|
|
88
|
-
dead code
|
|
21
|
+
grep, and that reflex is wrong here. `grep -rn 'def parse_config'` to read a
|
|
22
|
+
function's body applies the rule — that is `uncoded body`. `grep -rn
|
|
23
|
+
'validate_input'` to check whether something has callers before a refactor is
|
|
24
|
+
another case — that is `uncoded refs`. `grep` then `Edit` to delete
|
|
25
|
+
dead code fits the same pattern — that is `uncoded refs` to confirm dead,
|
|
89
26
|
then `Edit`. The grep version of any of these is noisier and less reliable:
|
|
90
27
|
grep matches comments, strings, and unrelated attributes; grep misses
|
|
91
28
|
re-exports (so caller and delete checks come back incomplete); grep forces
|
|
92
29
|
offset arithmetic to slice a body. The indexed tools don't.
|
|
93
30
|
|
|
94
|
-
|
|
31
|
+
## How to execute the rule
|
|
95
32
|
|
|
96
33
|
The index has two parts (a namespace map and per-file stubs) and three
|
|
97
34
|
steps (orient, understand, act).
|
|
@@ -154,7 +91,7 @@ With the map and stub loaded, you have the exact `relative_path` and
|
|
|
154
91
|
- **Safely delete.** `uvx uncoded refs <name_path> --in <relative_path>` must
|
|
155
92
|
return empty; then `Edit` to remove.
|
|
156
93
|
|
|
157
|
-
|
|
94
|
+
## Where Read, Edit, and grep are still the right tools
|
|
158
95
|
|
|
159
96
|
The rule is about source navigation by symbol name. Outside that, Read,
|
|
160
97
|
Edit, and grep stay correct:
|
|
@@ -170,11 +107,3 @@ Edit, and grep stay correct:
|
|
|
170
107
|
|
|
171
108
|
The dispatch rule turns on the search term: a symbol name → the index; a
|
|
172
109
|
regex or free-text phrase → grep.
|
|
173
|
-
<!-- uncoded:end -->
|
|
174
|
-
<!-- uncoded:docs:start sha256=6a530a01 -->
|
|
175
|
-
## How to read documentation in this codebase
|
|
176
|
-
|
|
177
|
-
`.uncoded/docs.yaml` is an orientation outline: it lists every Markdown file
|
|
178
|
-
and its heading hierarchy. Headings are literal text — use `Read` or `grep`
|
|
179
|
-
to navigate to a section.
|
|
180
|
-
<!-- uncoded:docs:end -->
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: coherence-review
|
|
3
|
-
description:
|
|
2
|
+
name: uncoded-coherence-review
|
|
3
|
+
description: 'Perform a coherence review of a Python codebase: a diagnostic sweep for semantic drift, naming inconsistency, promissory mismatch, and structural incoherence. Produces a Markdown report of findings with verbatim evidence and confidence levels, for human investigation. Assumes uncoded is installed (.uncoded/namespace.yaml and .uncoded/stubs/ present).'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Coherence Review
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: uncoded-doc-navigation
|
|
3
|
+
description: Use before searching or reading a codebase's Markdown documentation indexed by uncoded — locating which file and section cover a topic, or orienting to what documentation exists.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Documentation Navigation
|
|
7
|
+
|
|
8
|
+
This codebase uses [uncoded](https://github.com/alimanfoo/uncoded) to maintain
|
|
9
|
+
a documentation index.
|
|
10
|
+
|
|
11
|
+
**Step 1 — Orient. Read the docs map first.** Before answering the
|
|
12
|
+
user, before any other tool call:
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
Read .uncoded/docs.yaml
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`.uncoded/docs.yaml` is an orientation outline: it lists every Markdown file
|
|
19
|
+
and its heading hierarchy. Read it in full, now.
|
|
20
|
+
|
|
21
|
+
**Step 2 — Navigate.** Headings in the map are literal text. Use `Read` or
|
|
22
|
+
`grep` to navigate to a specific section identified in the map.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: uncoded-code-navigation
|
|
3
|
+
description: Use before searching, reading, or editing Python source in a codebase indexed by uncoded — locating a symbol, reading a definition, or checking references before a refactor, rename, or delete.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Code Navigation
|
|
7
|
+
|
|
8
|
+
This codebase uses [uncoded](https://github.com/alimanfoo/uncoded) to maintain
|
|
9
|
+
a symbol index over its source code, with two associated CLI tools:
|
|
10
|
+
`uncoded body` for reading a symbol's body and `uncoded refs` for finding
|
|
11
|
+
references.
|
|
12
|
+
|
|
13
|
+
## The dispatch rule
|
|
14
|
+
|
|
15
|
+
**If your search term is the name of a Python symbol — a class, function,
|
|
16
|
+
method, attribute, or module-level constant — use the index. If it's a
|
|
17
|
+
pattern, regex, or free-text phrase, use grep.**
|
|
18
|
+
|
|
19
|
+
This applies to every tool call where you are trying to find code, not
|
|
20
|
+
just the first one in the session. The pretrained reflex for "find X" is
|
|
21
|
+
grep, and that reflex is wrong here. `grep -rn 'def parse_config'` to read a
|
|
22
|
+
function's body applies the rule — that is `uncoded body`. `grep -rn
|
|
23
|
+
'validate_input'` to check whether something has callers before a refactor is
|
|
24
|
+
another case — that is `uncoded refs`. `grep` then `Edit` to delete
|
|
25
|
+
dead code fits the same pattern — that is `uncoded refs` to confirm dead,
|
|
26
|
+
then `Edit`. The grep version of any of these is noisier and less reliable:
|
|
27
|
+
grep matches comments, strings, and unrelated attributes; grep misses
|
|
28
|
+
re-exports (so caller and delete checks come back incomplete); grep forces
|
|
29
|
+
offset arithmetic to slice a body. The indexed tools don't.
|
|
30
|
+
|
|
31
|
+
## How to execute the rule
|
|
32
|
+
|
|
33
|
+
The index has two parts (a namespace map and per-file stubs) and three
|
|
34
|
+
steps (orient, understand, act).
|
|
35
|
+
|
|
36
|
+
**Step 1 — Orient. Read the namespace map first.** Before answering the
|
|
37
|
+
user, before any other tool call:
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
Read .uncoded/namespace.yaml
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
This lists every symbol in the codebase — directories, files, classes,
|
|
44
|
+
methods, functions. Without it loaded, "find X" answers come from
|
|
45
|
+
pretrained guesses about what a project like this *probably* contains,
|
|
46
|
+
rather than what is actually here. Read it once, in full, at session
|
|
47
|
+
start.
|
|
48
|
+
|
|
49
|
+
**Step 2 — Understand. Read the `.pyi` stub before any `.py` source.**
|
|
50
|
+
Stub paths mirror source paths under `.uncoded/stubs/`:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
src/foo/bar.py → .uncoded/stubs/src/foo/bar.pyi
|
|
54
|
+
tests/test_foo.py → .uncoded/stubs/tests/test_foo.pyi
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Every file you intend to touch or reference, including tests. The stub
|
|
58
|
+
contains imports, every signature with types, module-level assignments,
|
|
59
|
+
and class attributes — enough for most navigation. Skipping straight to
|
|
60
|
+
source means reading many lines to learn what the stub would have told
|
|
61
|
+
you in one. If no stub exists at the expected path, the file has no
|
|
62
|
+
symbols indexed; in that narrow case, read source directly.
|
|
63
|
+
|
|
64
|
+
**Step 3 — Act. Use `uncoded body` to read a symbol's body;
|
|
65
|
+
use `uncoded refs` to find every reference to a symbol; use `Edit` (with
|
|
66
|
+
`uncoded body`'s output as `old_string`) to change a symbol.**
|
|
67
|
+
With the map and stub loaded, you have the exact `relative_path` and
|
|
68
|
+
`name_path` each tool needs (`ClassName/method` for a method,
|
|
69
|
+
`function_name` for a top-level function). Per task:
|
|
70
|
+
|
|
71
|
+
- **Read a symbol's body.** `uvx uncoded body <name_path> --in <relative_path>` —
|
|
72
|
+
prints the symbol's source text to stdout, byte-identical to disk.
|
|
73
|
+
Returns exactly the symbol; no offset arithmetic, no risk of reading
|
|
74
|
+
too much. Its output has every byte `Edit` needs as `old_string` — no
|
|
75
|
+
extra `Read` required for partial edits. Stay on stubs for a
|
|
76
|
+
wider sweep.
|
|
77
|
+
|
|
78
|
+
- **Find every reference to a symbol.**
|
|
79
|
+
`uvx uncoded refs <name_path> --in <relative_path>`. Prints one reference
|
|
80
|
+
per line as `file:line:col`, sorted. Grep on the name misses re-exports
|
|
81
|
+
and adds false positives from comments, strings, and attribute lookups
|
|
82
|
+
on other types. If the next move depends on the answer being complete,
|
|
83
|
+
grep cannot give you that.
|
|
84
|
+
|
|
85
|
+
- **Edit a symbol.** `uvx uncoded body <name_path> --in <relative_path>` gives
|
|
86
|
+
the exact `old_string`; then `Edit` to apply the change.
|
|
87
|
+
|
|
88
|
+
- **Rename.** `uvx uncoded refs <name_path> --in <relative_path>` enumerates
|
|
89
|
+
every site; then `Edit` at each.
|
|
90
|
+
|
|
91
|
+
- **Safely delete.** `uvx uncoded refs <name_path> --in <relative_path>` must
|
|
92
|
+
return empty; then `Edit` to remove.
|
|
93
|
+
|
|
94
|
+
## Where Read, Edit, and grep are still the right tools
|
|
95
|
+
|
|
96
|
+
The rule is about source navigation by symbol name. Outside that, Read,
|
|
97
|
+
Edit, and grep stay correct:
|
|
98
|
+
|
|
99
|
+
- Free-text or pattern search outside source: Markdown, YAML, TOML,
|
|
100
|
+
configs, commit messages, notebook JSON, fixture data.
|
|
101
|
+
- Pattern search across signatures (regex over type annotations,
|
|
102
|
+
decorator usage, alias declarations) — these are not symbol-name
|
|
103
|
+
lookups even though they sit inside source.
|
|
104
|
+
- Partial-line edits inside a symbol body, once you have retrieved it
|
|
105
|
+
via `uncoded body`.
|
|
106
|
+
- The rare stub-less Python file that needs exploratory reading.
|
|
107
|
+
|
|
108
|
+
The dispatch rule turns on the search term: a symbol name → the index; a
|
|
109
|
+
regex or free-text phrase → grep.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: coherence-review
|
|
3
|
-
description:
|
|
2
|
+
name: uncoded-coherence-review
|
|
3
|
+
description: 'Perform a coherence review of a Python codebase: a diagnostic sweep for semantic drift, naming inconsistency, promissory mismatch, and structural incoherence. Produces a Markdown report of findings with verbatim evidence and confidence levels, for human investigation. Assumes uncoded is installed (.uncoded/namespace.yaml and .uncoded/stubs/ present).'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Coherence Review
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: uncoded-doc-navigation
|
|
3
|
+
description: Use before searching or reading a codebase's Markdown documentation indexed by uncoded — locating which file and section cover a topic, or orienting to what documentation exists.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Documentation Navigation
|
|
7
|
+
|
|
8
|
+
This codebase uses [uncoded](https://github.com/alimanfoo/uncoded) to maintain
|
|
9
|
+
a documentation index.
|
|
10
|
+
|
|
11
|
+
**Step 1 — Orient. Read the docs map first.** Before answering the
|
|
12
|
+
user, before any other tool call:
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
Read .uncoded/docs.yaml
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`.uncoded/docs.yaml` is an orientation outline: it lists every Markdown file
|
|
19
|
+
and its heading hierarchy. Read it in full, now.
|
|
20
|
+
|
|
21
|
+
**Step 2 — Navigate.** Headings in the map are literal text. Use `Read` or
|
|
22
|
+
`grep` to navigate to a specific section identified in the map.
|
|
@@ -21,14 +21,11 @@ README.md:
|
|
|
21
21
|
Coherence review:
|
|
22
22
|
Dev setup:
|
|
23
23
|
Note for Windows contributors:
|
|
24
|
+
Upgrading from v1:
|
|
24
25
|
Releasing:
|
|
25
26
|
AGENTS.md:
|
|
26
27
|
uncoded:
|
|
27
28
|
Problem:
|
|
28
29
|
Approach:
|
|
29
30
|
Commands:
|
|
30
|
-
|
|
31
|
-
The dispatch rule:
|
|
32
|
-
How to execute the rule:
|
|
33
|
-
Where Read, Edit, and grep are still the right tools:
|
|
34
|
-
How to read documentation in this codebase:
|
|
31
|
+
Skills:
|
|
@@ -18,6 +18,7 @@ src/:
|
|
|
18
18
|
resolve_body:
|
|
19
19
|
_extract_body:
|
|
20
20
|
cli.py:
|
|
21
|
+
_sync_code_artefacts:
|
|
21
22
|
_sync:
|
|
22
23
|
_body:
|
|
23
24
|
_refs:
|
|
@@ -28,7 +29,6 @@ src/:
|
|
|
28
29
|
project_root:
|
|
29
30
|
source_roots:
|
|
30
31
|
doc_roots:
|
|
31
|
-
instruction_files:
|
|
32
32
|
find_pyproject_toml:
|
|
33
33
|
_has_uncoded_section:
|
|
34
34
|
_find_config_file:
|
|
@@ -54,24 +54,12 @@ src/:
|
|
|
54
54
|
extract_module:
|
|
55
55
|
iter_source_files:
|
|
56
56
|
extract_modules:
|
|
57
|
-
instruction_files.py:
|
|
58
|
-
MARKER_END:
|
|
59
|
-
MARKER_DOCS_END:
|
|
60
|
-
MARKER_START_PREFIX:
|
|
61
|
-
MARKER_DOCS_START_PREFIX:
|
|
62
|
-
DEFAULT_INSTRUCTION_FILES:
|
|
63
|
-
_CODE_SECTION_BODY:
|
|
64
|
-
MARKER_START:
|
|
65
|
-
SECTION_CODE:
|
|
66
|
-
_DOCS_SECTION_BODY:
|
|
67
|
-
MARKER_DOCS_START:
|
|
68
|
-
SECTION_DOCS:
|
|
69
|
-
_apply_section:
|
|
70
|
-
sync_instruction_file:
|
|
71
57
|
namespace_map.py:
|
|
72
58
|
HEADER:
|
|
73
59
|
build_map:
|
|
74
60
|
render_map:
|
|
61
|
+
read_helpers.py:
|
|
62
|
+
_read_file_text_as_utf8:
|
|
75
63
|
refs.py:
|
|
76
64
|
TY_VERSION:
|
|
77
65
|
Reference:
|
|
@@ -105,10 +93,18 @@ src/:
|
|
|
105
93
|
resolve_ast_node_from_source:
|
|
106
94
|
_resolve_class_member:
|
|
107
95
|
skill.py:
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
96
|
+
SKILL_ROOTS:
|
|
97
|
+
SKILLS:
|
|
98
|
+
Skill:
|
|
99
|
+
name:
|
|
100
|
+
description:
|
|
101
|
+
body_file:
|
|
102
|
+
gate:
|
|
103
|
+
legacy_names:
|
|
104
|
+
_skill_path:
|
|
105
|
+
_render_content:
|
|
106
|
+
_remove_skill_file:
|
|
107
|
+
sync_skills:
|
|
112
108
|
stubs.py:
|
|
113
109
|
VALUE_WIDTH_CAP:
|
|
114
110
|
StubParam:
|
|
@@ -211,11 +207,12 @@ tests/:
|
|
|
211
207
|
TestResolveBodyByteIdentical:
|
|
212
208
|
test_exact_source_returned:
|
|
213
209
|
test_cli.py:
|
|
210
|
+
_CODE_SKILL_PATHS:
|
|
211
|
+
_DOC_SKILL_PATHS:
|
|
212
|
+
_SKILL_PATHS:
|
|
214
213
|
TestSyncApplyMode:
|
|
215
|
-
|
|
214
|
+
test_writes_namespace_map_stubs_and_skills:
|
|
216
215
|
test_idempotent_second_run:
|
|
217
|
-
test_dedupes_when_claude_md_is_symlink_to_agents_md:
|
|
218
|
-
test_error_when_instruction_file_outside_project_root:
|
|
219
216
|
test_error_when_no_config_file:
|
|
220
217
|
test_error_when_source_root_outside_project_root:
|
|
221
218
|
test_error_when_source_root_missing:
|
|
@@ -229,8 +226,6 @@ tests/:
|
|
|
229
226
|
test_returns_zero_when_index_is_up_to_date:
|
|
230
227
|
test_returns_one_when_source_changes_after_sync:
|
|
231
228
|
test_returns_one_when_source_file_deleted:
|
|
232
|
-
test_returns_one_when_instruction_file_drifts:
|
|
233
|
-
test_dedupes_when_claude_md_is_symlink_to_agents_md:
|
|
234
229
|
test_error_still_returns_one:
|
|
235
230
|
TestMainDispatch:
|
|
236
231
|
test_sync_subcommand_runs_in_apply_mode:
|
|
@@ -266,13 +261,11 @@ tests/:
|
|
|
266
261
|
test_doc_only_writes_docs_yaml:
|
|
267
262
|
test_doc_only_does_not_write_namespace_yaml:
|
|
268
263
|
test_doc_only_does_not_write_stubs:
|
|
269
|
-
test_doc_only_instruction_file_has_docs_section_only:
|
|
270
264
|
test_doc_root_single_md_file:
|
|
271
265
|
test_error_when_doc_root_missing:
|
|
272
266
|
test_error_when_doc_root_is_non_md_file:
|
|
273
267
|
test_error_when_doc_root_outside_project_root:
|
|
274
268
|
test_both_roots_writes_both_artefacts:
|
|
275
|
-
test_both_roots_instruction_file_has_both_sections:
|
|
276
269
|
test_source_root_removal_cleans_code_artefacts:
|
|
277
270
|
test_doc_root_removal_cleans_docs_yaml:
|
|
278
271
|
test_check_returns_one_when_docs_yaml_stale:
|
|
@@ -296,9 +289,6 @@ tests/:
|
|
|
296
289
|
test_both_roots_empty_when_section_absent:
|
|
297
290
|
test_project_root_is_config_file_parent:
|
|
298
291
|
test_finds_pyproject_in_parent_directory:
|
|
299
|
-
test_instruction_files_default_when_key_absent:
|
|
300
|
-
test_instruction_files_configured:
|
|
301
|
-
test_instruction_files_empty_list_respected:
|
|
302
292
|
test_returns_frozen_dataclass:
|
|
303
293
|
test_finds_uncoded_toml_when_no_pyproject:
|
|
304
294
|
test_uncoded_toml_top_level_keys:
|
|
@@ -341,6 +331,8 @@ tests/:
|
|
|
341
331
|
test_directory_nested_subdir:
|
|
342
332
|
test_empty_directory_yields_nothing:
|
|
343
333
|
test_rel_path_is_relative_to_project_root:
|
|
334
|
+
test_skips_non_utf8_file_with_warning:
|
|
335
|
+
test_single_file_root_unreadable_yields_nothing:
|
|
344
336
|
TestBuildDocsMap:
|
|
345
337
|
test_empty_files:
|
|
346
338
|
test_headingless_file_maps_to_null:
|
|
@@ -381,51 +373,12 @@ tests/:
|
|
|
381
373
|
test_includes_init_with_symbols:
|
|
382
374
|
test_skips_empty_init:
|
|
383
375
|
test_skips_syntax_errors:
|
|
376
|
+
test_skips_non_utf8_file_with_warning:
|
|
384
377
|
TestExtractModulesFromFiles:
|
|
385
378
|
test_returns_module_info_per_parseable_file:
|
|
386
379
|
test_preserves_source_order:
|
|
387
380
|
test_module_with_only_constants_is_kept:
|
|
388
381
|
test_skips_files_with_no_symbols:
|
|
389
|
-
test_instruction_files.py:
|
|
390
|
-
TestCodeSection:
|
|
391
|
-
test_contains_markers:
|
|
392
|
-
test_markers_in_order:
|
|
393
|
-
test_ends_with_newline:
|
|
394
|
-
TestDocsSection:
|
|
395
|
-
test_contains_markers:
|
|
396
|
-
test_markers_in_order:
|
|
397
|
-
test_ends_with_newline:
|
|
398
|
-
test_mentions_docs_yaml:
|
|
399
|
-
TestSyncInstructionFile:
|
|
400
|
-
test_creates_file_with_code_section:
|
|
401
|
-
test_appends_code_section_to_existing_file:
|
|
402
|
-
test_replaces_existing_code_section:
|
|
403
|
-
test_preserves_content_after_code_section:
|
|
404
|
-
test_removes_code_section_on_none:
|
|
405
|
-
test_appends_docs_section:
|
|
406
|
-
test_removes_docs_section_on_none:
|
|
407
|
-
test_both_sections_appended_in_order:
|
|
408
|
-
test_both_sections_replaced_independently:
|
|
409
|
-
test_code_only_does_not_write_docs_markers:
|
|
410
|
-
test_docs_only_does_not_write_code_markers:
|
|
411
|
-
test_idempotent:
|
|
412
|
-
test_returns_true_on_first_write:
|
|
413
|
-
test_returns_false_when_clean:
|
|
414
|
-
test_returns_false_when_both_none_and_file_absent:
|
|
415
|
-
test_remove_section_absent_is_noop:
|
|
416
|
-
TestSyncInstructionFileCheckMode:
|
|
417
|
-
test_does_not_create_file:
|
|
418
|
-
test_does_not_update_existing_file:
|
|
419
|
-
test_reports_no_change_when_clean:
|
|
420
|
-
TestSyncInstructionFileProjectRootAnchor:
|
|
421
|
-
test_project_root_anchors_create_independent_of_cwd:
|
|
422
|
-
test_project_root_anchors_update_of_existing_file:
|
|
423
|
-
TestSyncInstructionFileFingerprint:
|
|
424
|
-
test_reflowed_body_survives_sync:
|
|
425
|
-
test_reflowed_body_passes_check:
|
|
426
|
-
test_different_fingerprint_refreshes_section:
|
|
427
|
-
test_plain_marker_refreshes_once_then_stable:
|
|
428
|
-
test_prose_mention_of_prefix_before_section_is_ignored:
|
|
429
382
|
test_namespace_map.py:
|
|
430
383
|
TestBuildMap:
|
|
431
384
|
test_single_file:
|
|
@@ -475,19 +428,35 @@ tests/:
|
|
|
475
428
|
_init_response:
|
|
476
429
|
_shutdown_response:
|
|
477
430
|
test_skill.py:
|
|
478
|
-
|
|
479
|
-
|
|
431
|
+
TestSyncSkills:
|
|
432
|
+
test_skill_registry:
|
|
480
433
|
test_writes_skill_files:
|
|
481
434
|
test_creates_parent_directories:
|
|
482
|
-
|
|
483
|
-
|
|
435
|
+
test_content_has_frontmatter_and_body:
|
|
436
|
+
test_renderer_supplies_separator_for_body_without_leading_newline:
|
|
437
|
+
test_returns_change_count_on_first_write:
|
|
438
|
+
test_returns_zero_when_already_in_sync:
|
|
484
439
|
test_idempotent:
|
|
485
440
|
test_check_mode_does_not_write:
|
|
486
441
|
test_check_mode_reports_change_when_missing:
|
|
487
442
|
test_check_mode_reports_no_change_when_in_sync:
|
|
488
443
|
test_removes_legacy_skill_files:
|
|
489
|
-
|
|
490
|
-
|
|
444
|
+
test_check_mode_reports_legacy_files_without_removing:
|
|
445
|
+
test_source_false_removes_existing_skill_files:
|
|
446
|
+
test_source_false_returns_zero_when_already_absent:
|
|
447
|
+
test_source_false_check_mode_reports_without_removing:
|
|
448
|
+
test_gate_unmet_removal_prunes_empty_directory:
|
|
449
|
+
test_legacy_removal_prunes_empty_directory:
|
|
450
|
+
test_pruning_skipped_when_directory_has_other_files:
|
|
451
|
+
test_docs_gate_builds_when_docs_true:
|
|
452
|
+
test_docs_gate_skips_when_docs_false:
|
|
453
|
+
test_no_legacy_names_skips_legacy_removal:
|
|
454
|
+
test_code_navigation_written_when_source_set:
|
|
455
|
+
test_code_navigation_not_written_when_source_absent:
|
|
456
|
+
test_doc_navigation_written_when_docs_set:
|
|
457
|
+
test_doc_navigation_not_written_when_docs_absent:
|
|
458
|
+
test_doc_navigation_content_includes_orient_step:
|
|
459
|
+
TestSyncSkillsProjectRootAnchor:
|
|
491
460
|
test_project_root_anchors_writes_independent_of_cwd:
|
|
492
461
|
test_project_root_anchors_legacy_removal_independent_of_cwd:
|
|
493
462
|
test_stubs.py:
|
|
@@ -7,14 +7,16 @@ from uncoded.body import resolve_body
|
|
|
7
7
|
from uncoded.config import ConfigError, read_config
|
|
8
8
|
from uncoded.docs_map import build_docs_map, iter_doc_files, render_docs_map
|
|
9
9
|
from uncoded.extract import extract_modules, iter_source_files
|
|
10
|
-
from uncoded.instruction_files import SECTION_CODE, SECTION_DOCS, sync_instruction_file
|
|
11
10
|
from uncoded.namespace_map import build_map, render_map
|
|
12
11
|
from uncoded.refs import find_refs
|
|
13
12
|
from uncoded.resolver import NamePath, SymbolNotFound, UnsupportedNamePath
|
|
14
|
-
from uncoded.skill import
|
|
13
|
+
from uncoded.skill import sync_skills
|
|
15
14
|
from uncoded.stubs import build_stubs, remove_all_stubs
|
|
16
15
|
from uncoded.sync import remove_file, sync_file
|
|
17
16
|
|
|
17
|
+
def _sync_code_artefacts(*, build: bool, configured_source_roots: list[Path], project_root: Path, resolved_project_root: Path, check: bool) -> int | None:
|
|
18
|
+
...
|
|
19
|
+
|
|
18
20
|
def _sync(*, start: Path | None, check: bool) -> int:
|
|
19
21
|
...
|
|
20
22
|
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import tomllib
|
|
4
4
|
from dataclasses import dataclass
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from uncoded.instruction_files import DEFAULT_INSTRUCTION_FILES
|
|
7
6
|
|
|
8
7
|
def find_pyproject_toml(start: Path) -> Path | None:
|
|
9
8
|
...
|
|
@@ -24,4 +23,3 @@ class Config:
|
|
|
24
23
|
project_root: Path
|
|
25
24
|
source_roots: list[Path]
|
|
26
25
|
doc_roots: list[Path]
|
|
27
|
-
instruction_files: list[Path]
|
|
@@ -6,6 +6,7 @@ from collections.abc import Iterable, Iterator
|
|
|
6
6
|
from dataclasses import dataclass, field
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from uncoded.ast_helpers import assign_target_name, property_kind
|
|
9
|
+
from uncoded.read_helpers import _read_file_text_as_utf8
|
|
9
10
|
|
|
10
11
|
def extract_module(source: str, rel_path: str) -> ModuleInfo:
|
|
11
12
|
...
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# src/uncoded/skill.py
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from importlib.resources import files
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Literal
|
|
7
|
+
import yaml
|
|
8
|
+
from uncoded.sync import remove_file, sync_file
|
|
9
|
+
|
|
10
|
+
SKILL_ROOTS = [Path('.claude/skills'), Path('.agents/skills')]
|
|
11
|
+
SKILLS: list[Skill] = ...
|
|
12
|
+
|
|
13
|
+
def _skill_path(root: Path, name: str) -> Path:
|
|
14
|
+
...
|
|
15
|
+
|
|
16
|
+
def _render_content(*, skill: Skill) -> str:
|
|
17
|
+
...
|
|
18
|
+
|
|
19
|
+
def _remove_skill_file(*, path: Path, project_root: Path, check: bool) -> bool:
|
|
20
|
+
...
|
|
21
|
+
|
|
22
|
+
def sync_skills(*, source: bool, docs: bool, project_root: Path, check: bool) -> int:
|
|
23
|
+
...
|
|
24
|
+
|
|
25
|
+
class Skill:
|
|
26
|
+
name: str
|
|
27
|
+
description: str
|
|
28
|
+
body_file: str
|
|
29
|
+
gate: Literal['code', 'docs']
|
|
30
|
+
legacy_names: tuple[str, ...] = ()
|