uncoded 2.1.1__tar.gz → 3.0.1__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.
Files changed (105) hide show
  1. {uncoded-2.1.1/.claude → uncoded-3.0.1/.agents}/skills/uncoded-code-navigation/SKILL.md +34 -27
  2. uncoded-3.0.1/.agents/skills/uncoded-consistency-review/SKILL.md +145 -0
  3. uncoded-3.0.1/.agents/skills/uncoded-doc-navigation/SKILL.md +29 -0
  4. uncoded-2.1.1/src/uncoded/code_navigation.md → uncoded-3.0.1/.claude/skills/uncoded-code-navigation/SKILL.md +40 -26
  5. uncoded-3.0.1/.claude/skills/uncoded-consistency-review/SKILL.md +145 -0
  6. uncoded-3.0.1/.claude/skills/uncoded-doc-navigation/SKILL.md +29 -0
  7. {uncoded-2.1.1 → uncoded-3.0.1}/.github/workflows/ci.yml +2 -2
  8. uncoded-3.0.1/.github/workflows/docs.yml +43 -0
  9. {uncoded-2.1.1 → uncoded-3.0.1}/.pre-commit-config.yaml +12 -0
  10. {uncoded-2.1.1 → uncoded-3.0.1}/AGENTS.md +24 -23
  11. uncoded-3.0.1/PKG-INFO +35 -0
  12. uncoded-3.0.1/README.md +19 -0
  13. uncoded-3.0.1/docs/agent-workflow.md +73 -0
  14. uncoded-3.0.1/docs/architecture.md +43 -0
  15. uncoded-3.0.1/docs/commands.md +85 -0
  16. uncoded-3.0.1/docs/configuration.md +57 -0
  17. uncoded-3.0.1/docs/contributing.md +73 -0
  18. uncoded-3.0.1/docs/getting-started.md +83 -0
  19. uncoded-3.0.1/docs/index.md +79 -0
  20. uncoded-3.0.1/docs/keeping-current.md +48 -0
  21. uncoded-3.0.1/docs/stylesheets/extra.css +214 -0
  22. uncoded-3.0.1/docs/upgrading.md +64 -0
  23. uncoded-3.0.1/dreamcatcher.toml +39 -0
  24. uncoded-3.0.1/mkdocs.yml +71 -0
  25. {uncoded-2.1.1 → uncoded-3.0.1}/pyproject.toml +8 -2
  26. {uncoded-2.1.1 → uncoded-3.0.1}/src/uncoded/cli.py +13 -6
  27. uncoded-2.1.1/.agents/skills/uncoded-code-navigation/SKILL.md → uncoded-3.0.1/src/uncoded/code_navigation.md +33 -33
  28. {uncoded-2.1.1 → uncoded-3.0.1}/src/uncoded/config.py +43 -36
  29. uncoded-3.0.1/src/uncoded/consistency_review.md +138 -0
  30. uncoded-3.0.1/src/uncoded/doc_navigation.md +22 -0
  31. {uncoded-2.1.1 → uncoded-3.0.1}/src/uncoded/refs.py +11 -8
  32. {uncoded-2.1.1 → uncoded-3.0.1}/src/uncoded/resolver.py +43 -26
  33. {uncoded-2.1.1 → uncoded-3.0.1}/src/uncoded/skill.py +68 -43
  34. {uncoded-2.1.1 → uncoded-3.0.1}/src/uncoded/stubs.py +32 -21
  35. {uncoded-2.1.1 → uncoded-3.0.1}/src/uncoded/sync.py +3 -4
  36. {uncoded-2.1.1 → uncoded-3.0.1}/tests/test_body.py +20 -13
  37. {uncoded-2.1.1 → uncoded-3.0.1}/tests/test_cli.py +60 -25
  38. {uncoded-2.1.1 → uncoded-3.0.1}/tests/test_refs.py +30 -9
  39. {uncoded-2.1.1 → uncoded-3.0.1}/tests/test_skill.py +62 -63
  40. uncoded-3.0.1/uv.lock +1101 -0
  41. uncoded-2.1.1/.agents/skills/uncoded-coherence-review/SKILL.md +0 -371
  42. uncoded-2.1.1/.agents/skills/uncoded-doc-navigation/SKILL.md +0 -24
  43. uncoded-2.1.1/.claude/skills/uncoded-coherence-review/SKILL.md +0 -371
  44. uncoded-2.1.1/.claude/skills/uncoded-doc-navigation/SKILL.md +0 -24
  45. uncoded-2.1.1/.uncoded/docs.yaml +0 -36
  46. uncoded-2.1.1/.uncoded/namespace.yaml +0 -594
  47. uncoded-2.1.1/.uncoded/stubs/src/uncoded/__init__.pyi +0 -6
  48. uncoded-2.1.1/.uncoded/stubs/src/uncoded/ast_helpers.pyi +0 -10
  49. uncoded-2.1.1/.uncoded/stubs/src/uncoded/body.pyi +0 -13
  50. uncoded-2.1.1/.uncoded/stubs/src/uncoded/cli.pyi +0 -41
  51. uncoded-2.1.1/.uncoded/stubs/src/uncoded/config.pyi +0 -26
  52. uncoded-2.1.1/.uncoded/stubs/src/uncoded/docs_map.pyi +0 -31
  53. uncoded-2.1.1/.uncoded/stubs/src/uncoded/extract.pyi +0 -33
  54. uncoded-2.1.1/.uncoded/stubs/src/uncoded/markers.pyi +0 -4
  55. uncoded-2.1.1/.uncoded/stubs/src/uncoded/namespace_map.pyi +0 -15
  56. uncoded-2.1.1/.uncoded/stubs/src/uncoded/read_helpers.pyi +0 -15
  57. uncoded-2.1.1/.uncoded/stubs/src/uncoded/refs.pyi +0 -56
  58. uncoded-2.1.1/.uncoded/stubs/src/uncoded/resolver.pyi +0 -36
  59. uncoded-2.1.1/.uncoded/stubs/src/uncoded/skill.pyi +0 -32
  60. uncoded-2.1.1/.uncoded/stubs/src/uncoded/stubs.pyi +0 -101
  61. uncoded-2.1.1/.uncoded/stubs/src/uncoded/sync.pyi +0 -10
  62. uncoded-2.1.1/.uncoded/stubs/src/uncoded/yaml_tree.pyi +0 -11
  63. uncoded-2.1.1/.uncoded/stubs/tests/test_body.pyi +0 -149
  64. uncoded-2.1.1/.uncoded/stubs/tests/test_cli.pyi +0 -215
  65. uncoded-2.1.1/.uncoded/stubs/tests/test_config.pyi +0 -62
  66. uncoded-2.1.1/.uncoded/stubs/tests/test_docs_map.pyi +0 -154
  67. uncoded-2.1.1/.uncoded/stubs/tests/test_encoding_gate.pyi +0 -8
  68. uncoded-2.1.1/.uncoded/stubs/tests/test_extract.pyi +0 -86
  69. uncoded-2.1.1/.uncoded/stubs/tests/test_markers.pyi +0 -21
  70. uncoded-2.1.1/.uncoded/stubs/tests/test_namespace_map.pyi +0 -47
  71. uncoded-2.1.1/.uncoded/stubs/tests/test_refs.pyi +0 -89
  72. uncoded-2.1.1/.uncoded/stubs/tests/test_skill.pyi +0 -100
  73. uncoded-2.1.1/.uncoded/stubs/tests/test_stubs.pyi +0 -237
  74. uncoded-2.1.1/.uncoded/stubs/tests/test_sync.pyi +0 -54
  75. uncoded-2.1.1/.uncoded/stubs/tests/test_uncoded.pyi +0 -10
  76. uncoded-2.1.1/PKG-INFO +0 -318
  77. uncoded-2.1.1/README.md +0 -295
  78. uncoded-2.1.1/src/uncoded/coherence_review.md +0 -364
  79. uncoded-2.1.1/src/uncoded/doc_navigation.md +0 -17
  80. uncoded-2.1.1/uv.lock +0 -406
  81. {uncoded-2.1.1 → uncoded-3.0.1}/.github/workflows/publish.yml +0 -0
  82. {uncoded-2.1.1 → uncoded-3.0.1}/.gitignore +0 -0
  83. {uncoded-2.1.1 → uncoded-3.0.1}/.markdownlint-cli2.yaml +0 -0
  84. {uncoded-2.1.1 → uncoded-3.0.1}/.prettierrc +0 -0
  85. {uncoded-2.1.1 → uncoded-3.0.1}/CLAUDE.md +0 -0
  86. {uncoded-2.1.1 → uncoded-3.0.1}/LICENSE +0 -0
  87. {uncoded-2.1.1 → uncoded-3.0.1}/src/uncoded/__init__.py +0 -0
  88. {uncoded-2.1.1 → uncoded-3.0.1}/src/uncoded/ast_helpers.py +0 -0
  89. {uncoded-2.1.1 → uncoded-3.0.1}/src/uncoded/body.py +0 -0
  90. {uncoded-2.1.1 → uncoded-3.0.1}/src/uncoded/docs_map.py +0 -0
  91. {uncoded-2.1.1 → uncoded-3.0.1}/src/uncoded/extract.py +0 -0
  92. {uncoded-2.1.1 → uncoded-3.0.1}/src/uncoded/markers.py +0 -0
  93. {uncoded-2.1.1 → uncoded-3.0.1}/src/uncoded/namespace_map.py +0 -0
  94. {uncoded-2.1.1 → uncoded-3.0.1}/src/uncoded/read_helpers.py +0 -0
  95. {uncoded-2.1.1 → uncoded-3.0.1}/src/uncoded/yaml_tree.py +0 -0
  96. {uncoded-2.1.1 → uncoded-3.0.1}/tests/__init__.py +0 -0
  97. {uncoded-2.1.1 → uncoded-3.0.1}/tests/test_config.py +0 -0
  98. {uncoded-2.1.1 → uncoded-3.0.1}/tests/test_docs_map.py +0 -0
  99. {uncoded-2.1.1 → uncoded-3.0.1}/tests/test_encoding_gate.py +0 -0
  100. {uncoded-2.1.1 → uncoded-3.0.1}/tests/test_extract.py +0 -0
  101. {uncoded-2.1.1 → uncoded-3.0.1}/tests/test_markers.py +0 -0
  102. {uncoded-2.1.1 → uncoded-3.0.1}/tests/test_namespace_map.py +0 -0
  103. {uncoded-2.1.1 → uncoded-3.0.1}/tests/test_stubs.py +0 -0
  104. {uncoded-2.1.1 → uncoded-3.0.1}/tests/test_sync.py +0 -0
  105. {uncoded-2.1.1 → uncoded-3.0.1}/tests/test_uncoded.py +0 -0
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: uncoded-code-navigation
3
- description: Use before searching, reading, or editing Python source in a codebase indexed by uncoded. This covers locating a symbol, reading a definition, or checking references before you refactor, rename, or delete.
3
+ description: Load once per session, before the first search, read, or edit of Python source in a codebase indexed by uncoded. Covers locating a symbol, reading a definition, or checking references before you refactor, rename, or delete.
4
4
  ---
5
5
 
6
6
  <!-- Generated by uncoded — do not edit; regeneration overwrites. -->
@@ -17,23 +17,25 @@ for reading a symbol's body and `uncoded refs` for finding references.
17
17
  symbols are classes, functions, methods, attributes, and module-level constants.
18
18
  If it's a pattern, regex, or free-text phrase, use grep.**
19
19
 
20
- This applies to every tool call where you find code, not just the first in the
21
- session. The pretrained reflex for "find X" is grep, and that reflex is wrong
22
- here. Reaching for `grep -rn 'def parse_config'` to read a function's body is a
23
- case for `uncoded body`. Reaching for `grep -rn 'validate_input'` to check
24
- callers before a refactor is a case for `uncoded refs`. Reaching for `grep` then
25
- `Edit` to delete dead code is a case for `uncoded refs` to confirm the code is
26
- dead, then `Edit`. The grep version of any of these is noisier and less
27
- reliable. Grep matches comments, strings, and unrelated attributes. Grep misses
28
- re-exports, so caller and delete checks come back incomplete. Grep forces offset
29
- arithmetic to slice a body. The indexed tools don't.
20
+ This dispatch rule applies to every tool call where you find code, not just the
21
+ first in the session. The pretrained reflex for "find X" is grep, and that
22
+ reflex is wrong here. Reaching for `grep -rn 'def parse_config'` to read a
23
+ function's body is a case for `uncoded body`. Reaching for
24
+ `grep -rn 'validate_input'` to check callers before a refactor is a case for
25
+ `uncoded refs`. Reaching for `grep` then `Edit` to delete dead code is a case
26
+ for `uncoded refs` to confirm the code is dead, then `Edit`. The grep version of
27
+ any of these is noisier and less reliable. Grep matches comments, strings, and
28
+ unrelated attributes. Grep misses re-exports, so caller and delete checks come
29
+ back incomplete. Grep forces offset arithmetic to slice a body. The indexed
30
+ tools don't.
30
31
 
31
32
  ## How to execute the rule
32
33
 
33
- The index has two parts (a namespace map and per-file stubs) and three steps
34
- (orient, understand, act).
34
+ The index has two parts: a namespace map and per-file stubs. Start with the map
35
+ and add detail only when the task needs it.
35
36
 
36
- **Step 1: Orient. Read the namespace map first.** Before answering the user,
37
+ **Step 1: Orient. Read the namespace map first.** If the map is missing, run the
38
+ repository's configured `uncoded sync` command. Then, before answering the user,
37
39
  before any other tool call:
38
40
 
39
41
  ```text
@@ -53,18 +55,18 @@ src/foo/bar.py → .uncoded/stubs/src/foo/bar.pyi
53
55
  tests/test_foo.py → .uncoded/stubs/tests/test_foo.pyi
54
56
  ```
55
57
 
56
- Read the stub for every file you intend to touch or reference, including tests.
57
- The stub contains imports, every signature with types, module-level assignments,
58
- and class attributes. That is enough for most navigation. Skipping straight to
59
- source means reading many lines to learn what the stub would have told you in
60
- one. If no stub exists at the expected path, the file has no symbols indexed. In
61
- that narrow case, read source directly.
58
+ The stub contains imports, parameter names and annotations, return types,
59
+ module-level assignments, and class attributes. It omits parameter defaults,
60
+ decorators, docstrings, and function bodies. Read source when the task depends
61
+ on an omitted detail or needs exact code. If no stub exists at the expected
62
+ path, the file has no symbols indexed. In that narrow case, read source
63
+ directly.
62
64
 
63
65
  **Step 3: Act.** Use `uncoded body` to read a symbol's body. Use `uncoded refs`
64
66
  to find every reference to a symbol. Use `Edit` (with `uncoded body`'s output as
65
- `old_string`) to change a symbol. With the map and stub loaded, you have the
66
- exact `relative_path` and `name_path` each tool needs. Use `ClassName/method`
67
- for a method and `function_name` for a top-level function. Per task:
67
+ `old_string`) to change a symbol. Use the exact `relative_path` and `name_path`
68
+ from the map. Use `ClassName/method` for a method and `function_name` for a
69
+ top-level function. Per task:
68
70
 
69
71
  - **Read a symbol's body.** `uvx uncoded body <name_path> --in <relative_path>`
70
72
  prints the symbol's source text to stdout, byte-identical to disk. Returns
@@ -74,10 +76,11 @@ for a method and `function_name` for a top-level function. Per task:
74
76
 
75
77
  - **Find every reference to a symbol.**
76
78
  `uvx uncoded refs <name_path> --in <relative_path>`. Prints one reference per
77
- line as `file:line:col`, sorted. Grep on the name misses re-exports and adds
78
- false positives from comments, strings, and attribute lookups on other types.
79
- If the next move depends on the answer being complete, grep cannot give you
80
- that.
79
+ line as `<path>:<line>:<col>`, sorted by path, then line, then column. Each
80
+ path is relative to the current working directory when possible and otherwise
81
+ absolute. Grep on the name misses re-exports and adds false positives from
82
+ comments, strings, and attribute lookups on other types. If the next move
83
+ depends on the answer being complete, grep cannot give you that.
81
84
 
82
85
  - **Edit a symbol.** `uvx uncoded body <name_path> --in <relative_path>` gives
83
86
  the exact `old_string`; then `Edit` to apply the change.
@@ -88,6 +91,10 @@ for a method and `function_name` for a top-level function. Per task:
88
91
  - **Safely delete.** `uvx uncoded refs <name_path> --in <relative_path>` must
89
92
  return empty; then `Edit` to remove.
90
93
 
94
+ **Step 4: Refresh.** After every modification to indexed Python source, run the
95
+ repository's configured `uncoded sync` command before the next code-navigation
96
+ operation. The modification can change the namespace map and stubs.
97
+
91
98
  ## Where Read, Edit, and grep are still the right tools
92
99
 
93
100
  The rule is about source navigation by symbol name. Outside that, Read, Edit,
@@ -0,0 +1,145 @@
1
+ ---
2
+ name: uncoded-consistency-review
3
+ description: Review a Python codebase for semantic and naming consistency. It reports only concrete disagreements between two claims about the same concept, with verbatim evidence for each claim. It assumes uncoded is installed (.uncoded/namespace.yaml and .uncoded/stubs/ present).
4
+ ---
5
+
6
+ <!-- Generated by uncoded — do not edit; regeneration overwrites. -->
7
+
8
+ # Semantic Consistency Review
9
+
10
+ Review a Python codebase for concrete disagreements in its vocabulary and symbol
11
+ contracts. A finding must identify two claims about the same concept that ought
12
+ to agree, but do not.
13
+
14
+ ## Guardrails
15
+
16
+ Admit a finding only when the codebase supports both claims, their observable
17
+ difference, and the reason that they should agree. Quote both claims verbatim.
18
+ Omit a candidate when either claim or the reason for comparing them is
19
+ unsupported.
20
+
21
+ Review semantic and naming consistency, not formatting or style consistency. Do
22
+ not report general bugs, complexity, performance, security, or design
23
+ preferences unless they appear as a disagreement between two supported claims.
24
+ Do not report overgrown public surfaces, private imports, cross-domain imports,
25
+ zero-reference symbols, or redundant public surfaces merely because they exist.
26
+
27
+ ## Prerequisites
28
+
29
+ Run the repository's configured `uncoded sync` command. Read the repository's
30
+ agent instructions and follow its navigation rules.
31
+
32
+ ## Orientation
33
+
34
+ Read `.uncoded/namespace.yaml` in full. Use its package structure and symbol
35
+ names to map the codebase's main concepts and vocabulary.
36
+
37
+ ## Vocabulary sweep
38
+
39
+ Use the namespace and stubs to find candidates, then confirm semantic overlap
40
+ from signatures, docstrings, or bodies. Look for:
41
+
42
+ - **Competing terms:** different names for substantively the same concept.
43
+ - **Conflicting use:** the same term used incompatibly within a shared context.
44
+ - **Stale qualifiers:** names such as `legacy`, `v2`, or `final` whose
45
+ distinction conflicts with another symbol or a symbol's docstring.
46
+
47
+ Similar spelling, low vocabulary overlap, or the presence of a qualifier is not
48
+ evidence on its own. A finding needs two concrete claims that establish the
49
+ shared concept and the disagreement.
50
+
51
+ ## Symbol-contract sweep
52
+
53
+ Compare a symbol's name, signature, docstring, and, when needed, behaviour.
54
+ Findings may cover:
55
+
56
+ - name-signature disagreement
57
+ - name-docstring disagreement
58
+ - docstring-signature disagreement
59
+ - name-behaviour disagreement
60
+
61
+ Read each relevant source file's stub for names and signatures. Run the
62
+ repository's configured `uncoded body` command only when a docstring or
63
+ implementation is needed to confirm a candidate. Do not retrieve every symbol
64
+ body.
65
+
66
+ ## Report
67
+
68
+ Return the report directly as the final turn output.
69
+
70
+ Use this structure:
71
+
72
+ ```markdown
73
+ ## Semantic Consistency Review
74
+
75
+ ### Scope
76
+
77
+ <What was reviewed and intentionally omitted.>
78
+
79
+ ### Summary
80
+
81
+ <Two or three sentences that summarise the supported findings.>
82
+
83
+ ### Vocabulary findings
84
+
85
+ #### 1. <Summary>
86
+
87
+ **Claim A** — `<path>` · `<symbol>` · name | signature | docstring | body
88
+
89
+ > Verbatim evidence
90
+
91
+ **Claim B** — `<path>` · `<symbol>` · name | signature | docstring | body
92
+
93
+ > Verbatim evidence
94
+
95
+ **How they differ:** <The observable disagreement.>
96
+
97
+ **Why these should agree:** <Evidence that both claims describe the same
98
+ concept.>
99
+
100
+ ### Symbol-contract findings
101
+
102
+ #### 1. <Summary>
103
+
104
+ <Use the same finding structure.>
105
+ ```
106
+
107
+ Keep both finding headings. If a group has no supported findings, state that
108
+ under its heading. Number findings independently within each group.
109
+
110
+ ## Examples
111
+
112
+ ### Vocabulary finding
113
+
114
+ #### 1. Customer lookup uses competing verbs
115
+
116
+ **Claim A** — `storage.py` · `fetch_customer` · signature
117
+
118
+ > `fetch_customer(customer_id: str) -> Customer`
119
+
120
+ **Claim B** — `adapter.py` · `load_customer` · signature
121
+
122
+ > `load_customer(customer_id: str) -> Customer`
123
+
124
+ **How they differ:** The same lookup uses `fetch` in one module and `load` in
125
+ another.
126
+
127
+ **Why these should agree:** Both signatures accept a customer ID and return a
128
+ customer through sibling adapters.
129
+
130
+ ### Symbol-contract finding
131
+
132
+ #### 1. Predicate name promises a boolean but returns a value
133
+
134
+ **Claim A** — `cache.py` · `is_cached` · name
135
+
136
+ > `is_cached`
137
+
138
+ **Claim B** — `cache.py` · `is_cached` · signature
139
+
140
+ > `is_cached(key: str) -> str | None`
141
+
142
+ **How they differ:** The name promises a predicate, while the return type holds
143
+ a cached value or absence.
144
+
145
+ **Why these should agree:** Both claims describe the contract of `is_cached`.
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: uncoded-doc-navigation
3
+ description: Load once per session, before the first search or read of a codebase's Markdown documentation indexed by uncoded. Covers locating which file and section cover a topic, or orienting to what documentation exists.
4
+ ---
5
+
6
+ <!-- Generated by uncoded — do not edit; regeneration overwrites. -->
7
+
8
+ # Documentation Navigation
9
+
10
+ This codebase uses [uncoded](https://github.com/alimanfoo/uncoded) to maintain a
11
+ documentation index.
12
+
13
+ **Step 1: Orient. Read the docs map first.** If the map is missing, run the
14
+ repository's configured `uncoded sync` command. Then, before answering the user,
15
+ before any other tool call:
16
+
17
+ ```text
18
+ Read .uncoded/docs.yaml
19
+ ```
20
+
21
+ `.uncoded/docs.yaml` is an orientation outline: it lists every Markdown file and
22
+ its heading hierarchy. Read it once, in full, at session start.
23
+
24
+ **Step 2: Navigate.** Headings in the map are literal text. Use `Read` or `grep`
25
+ to navigate to a specific section identified in the map.
26
+
27
+ **Step 3: Refresh.** After every modification to indexed Markdown, run the
28
+ repository's configured `uncoded sync` command before the next
29
+ documentation-navigation operation. The modification can change the heading map.
@@ -1,3 +1,10 @@
1
+ ---
2
+ name: uncoded-code-navigation
3
+ description: Load once per session, before the first search, read, or edit of Python source in a codebase indexed by uncoded. Covers locating a symbol, reading a definition, or checking references before you refactor, rename, or delete.
4
+ ---
5
+
6
+ <!-- Generated by uncoded — do not edit; regeneration overwrites. -->
7
+
1
8
  # Code Navigation
2
9
 
3
10
  This codebase uses [uncoded](https://github.com/alimanfoo/uncoded) to maintain a
@@ -10,23 +17,25 @@ for reading a symbol's body and `uncoded refs` for finding references.
10
17
  symbols are classes, functions, methods, attributes, and module-level constants.
11
18
  If it's a pattern, regex, or free-text phrase, use grep.**
12
19
 
13
- This applies to every tool call where you find code, not just the first in the
14
- session. The pretrained reflex for "find X" is grep, and that reflex is wrong
15
- here. Reaching for `grep -rn 'def parse_config'` to read a function's body is a
16
- case for `uncoded body`. Reaching for `grep -rn 'validate_input'` to check
17
- callers before a refactor is a case for `uncoded refs`. Reaching for `grep` then
18
- `Edit` to delete dead code is a case for `uncoded refs` to confirm the code is
19
- dead, then `Edit`. The grep version of any of these is noisier and less
20
- reliable. Grep matches comments, strings, and unrelated attributes. Grep misses
21
- re-exports, so caller and delete checks come back incomplete. Grep forces offset
22
- arithmetic to slice a body. The indexed tools don't.
20
+ This dispatch rule applies to every tool call where you find code, not just the
21
+ first in the session. The pretrained reflex for "find X" is grep, and that
22
+ reflex is wrong here. Reaching for `grep -rn 'def parse_config'` to read a
23
+ function's body is a case for `uncoded body`. Reaching for
24
+ `grep -rn 'validate_input'` to check callers before a refactor is a case for
25
+ `uncoded refs`. Reaching for `grep` then `Edit` to delete dead code is a case
26
+ for `uncoded refs` to confirm the code is dead, then `Edit`. The grep version of
27
+ any of these is noisier and less reliable. Grep matches comments, strings, and
28
+ unrelated attributes. Grep misses re-exports, so caller and delete checks come
29
+ back incomplete. Grep forces offset arithmetic to slice a body. The indexed
30
+ tools don't.
23
31
 
24
32
  ## How to execute the rule
25
33
 
26
- The index has two parts (a namespace map and per-file stubs) and three steps
27
- (orient, understand, act).
34
+ The index has two parts: a namespace map and per-file stubs. Start with the map
35
+ and add detail only when the task needs it.
28
36
 
29
- **Step 1: Orient. Read the namespace map first.** Before answering the user,
37
+ **Step 1: Orient. Read the namespace map first.** If the map is missing, run the
38
+ repository's configured `uncoded sync` command. Then, before answering the user,
30
39
  before any other tool call:
31
40
 
32
41
  ```text
@@ -46,18 +55,18 @@ src/foo/bar.py → .uncoded/stubs/src/foo/bar.pyi
46
55
  tests/test_foo.py → .uncoded/stubs/tests/test_foo.pyi
47
56
  ```
48
57
 
49
- Read the stub for every file you intend to touch or reference, including tests.
50
- The stub contains imports, every signature with types, module-level assignments,
51
- and class attributes. That is enough for most navigation. Skipping straight to
52
- source means reading many lines to learn what the stub would have told you in
53
- one. If no stub exists at the expected path, the file has no symbols indexed. In
54
- that narrow case, read source directly.
58
+ The stub contains imports, parameter names and annotations, return types,
59
+ module-level assignments, and class attributes. It omits parameter defaults,
60
+ decorators, docstrings, and function bodies. Read source when the task depends
61
+ on an omitted detail or needs exact code. If no stub exists at the expected
62
+ path, the file has no symbols indexed. In that narrow case, read source
63
+ directly.
55
64
 
56
65
  **Step 3: Act.** Use `uncoded body` to read a symbol's body. Use `uncoded refs`
57
66
  to find every reference to a symbol. Use `Edit` (with `uncoded body`'s output as
58
- `old_string`) to change a symbol. With the map and stub loaded, you have the
59
- exact `relative_path` and `name_path` each tool needs. Use `ClassName/method`
60
- for a method and `function_name` for a top-level function. Per task:
67
+ `old_string`) to change a symbol. Use the exact `relative_path` and `name_path`
68
+ from the map. Use `ClassName/method` for a method and `function_name` for a
69
+ top-level function. Per task:
61
70
 
62
71
  - **Read a symbol's body.** `uvx uncoded body <name_path> --in <relative_path>`
63
72
  prints the symbol's source text to stdout, byte-identical to disk. Returns
@@ -67,10 +76,11 @@ for a method and `function_name` for a top-level function. Per task:
67
76
 
68
77
  - **Find every reference to a symbol.**
69
78
  `uvx uncoded refs <name_path> --in <relative_path>`. Prints one reference per
70
- line as `file:line:col`, sorted. Grep on the name misses re-exports and adds
71
- false positives from comments, strings, and attribute lookups on other types.
72
- If the next move depends on the answer being complete, grep cannot give you
73
- that.
79
+ line as `<path>:<line>:<col>`, sorted by path, then line, then column. Each
80
+ path is relative to the current working directory when possible and otherwise
81
+ absolute. Grep on the name misses re-exports and adds false positives from
82
+ comments, strings, and attribute lookups on other types. If the next move
83
+ depends on the answer being complete, grep cannot give you that.
74
84
 
75
85
  - **Edit a symbol.** `uvx uncoded body <name_path> --in <relative_path>` gives
76
86
  the exact `old_string`; then `Edit` to apply the change.
@@ -81,6 +91,10 @@ for a method and `function_name` for a top-level function. Per task:
81
91
  - **Safely delete.** `uvx uncoded refs <name_path> --in <relative_path>` must
82
92
  return empty; then `Edit` to remove.
83
93
 
94
+ **Step 4: Refresh.** After every modification to indexed Python source, run the
95
+ repository's configured `uncoded sync` command before the next code-navigation
96
+ operation. The modification can change the namespace map and stubs.
97
+
84
98
  ## Where Read, Edit, and grep are still the right tools
85
99
 
86
100
  The rule is about source navigation by symbol name. Outside that, Read, Edit,
@@ -0,0 +1,145 @@
1
+ ---
2
+ name: uncoded-consistency-review
3
+ description: Review a Python codebase for semantic and naming consistency. It reports only concrete disagreements between two claims about the same concept, with verbatim evidence for each claim. It assumes uncoded is installed (.uncoded/namespace.yaml and .uncoded/stubs/ present).
4
+ ---
5
+
6
+ <!-- Generated by uncoded — do not edit; regeneration overwrites. -->
7
+
8
+ # Semantic Consistency Review
9
+
10
+ Review a Python codebase for concrete disagreements in its vocabulary and symbol
11
+ contracts. A finding must identify two claims about the same concept that ought
12
+ to agree, but do not.
13
+
14
+ ## Guardrails
15
+
16
+ Admit a finding only when the codebase supports both claims, their observable
17
+ difference, and the reason that they should agree. Quote both claims verbatim.
18
+ Omit a candidate when either claim or the reason for comparing them is
19
+ unsupported.
20
+
21
+ Review semantic and naming consistency, not formatting or style consistency. Do
22
+ not report general bugs, complexity, performance, security, or design
23
+ preferences unless they appear as a disagreement between two supported claims.
24
+ Do not report overgrown public surfaces, private imports, cross-domain imports,
25
+ zero-reference symbols, or redundant public surfaces merely because they exist.
26
+
27
+ ## Prerequisites
28
+
29
+ Run the repository's configured `uncoded sync` command. Read the repository's
30
+ agent instructions and follow its navigation rules.
31
+
32
+ ## Orientation
33
+
34
+ Read `.uncoded/namespace.yaml` in full. Use its package structure and symbol
35
+ names to map the codebase's main concepts and vocabulary.
36
+
37
+ ## Vocabulary sweep
38
+
39
+ Use the namespace and stubs to find candidates, then confirm semantic overlap
40
+ from signatures, docstrings, or bodies. Look for:
41
+
42
+ - **Competing terms:** different names for substantively the same concept.
43
+ - **Conflicting use:** the same term used incompatibly within a shared context.
44
+ - **Stale qualifiers:** names such as `legacy`, `v2`, or `final` whose
45
+ distinction conflicts with another symbol or a symbol's docstring.
46
+
47
+ Similar spelling, low vocabulary overlap, or the presence of a qualifier is not
48
+ evidence on its own. A finding needs two concrete claims that establish the
49
+ shared concept and the disagreement.
50
+
51
+ ## Symbol-contract sweep
52
+
53
+ Compare a symbol's name, signature, docstring, and, when needed, behaviour.
54
+ Findings may cover:
55
+
56
+ - name-signature disagreement
57
+ - name-docstring disagreement
58
+ - docstring-signature disagreement
59
+ - name-behaviour disagreement
60
+
61
+ Read each relevant source file's stub for names and signatures. Run the
62
+ repository's configured `uncoded body` command only when a docstring or
63
+ implementation is needed to confirm a candidate. Do not retrieve every symbol
64
+ body.
65
+
66
+ ## Report
67
+
68
+ Return the report directly as the final turn output.
69
+
70
+ Use this structure:
71
+
72
+ ```markdown
73
+ ## Semantic Consistency Review
74
+
75
+ ### Scope
76
+
77
+ <What was reviewed and intentionally omitted.>
78
+
79
+ ### Summary
80
+
81
+ <Two or three sentences that summarise the supported findings.>
82
+
83
+ ### Vocabulary findings
84
+
85
+ #### 1. <Summary>
86
+
87
+ **Claim A** — `<path>` · `<symbol>` · name | signature | docstring | body
88
+
89
+ > Verbatim evidence
90
+
91
+ **Claim B** — `<path>` · `<symbol>` · name | signature | docstring | body
92
+
93
+ > Verbatim evidence
94
+
95
+ **How they differ:** <The observable disagreement.>
96
+
97
+ **Why these should agree:** <Evidence that both claims describe the same
98
+ concept.>
99
+
100
+ ### Symbol-contract findings
101
+
102
+ #### 1. <Summary>
103
+
104
+ <Use the same finding structure.>
105
+ ```
106
+
107
+ Keep both finding headings. If a group has no supported findings, state that
108
+ under its heading. Number findings independently within each group.
109
+
110
+ ## Examples
111
+
112
+ ### Vocabulary finding
113
+
114
+ #### 1. Customer lookup uses competing verbs
115
+
116
+ **Claim A** — `storage.py` · `fetch_customer` · signature
117
+
118
+ > `fetch_customer(customer_id: str) -> Customer`
119
+
120
+ **Claim B** — `adapter.py` · `load_customer` · signature
121
+
122
+ > `load_customer(customer_id: str) -> Customer`
123
+
124
+ **How they differ:** The same lookup uses `fetch` in one module and `load` in
125
+ another.
126
+
127
+ **Why these should agree:** Both signatures accept a customer ID and return a
128
+ customer through sibling adapters.
129
+
130
+ ### Symbol-contract finding
131
+
132
+ #### 1. Predicate name promises a boolean but returns a value
133
+
134
+ **Claim A** — `cache.py` · `is_cached` · name
135
+
136
+ > `is_cached`
137
+
138
+ **Claim B** — `cache.py` · `is_cached` · signature
139
+
140
+ > `is_cached(key: str) -> str | None`
141
+
142
+ **How they differ:** The name promises a predicate, while the return type holds
143
+ a cached value or absence.
144
+
145
+ **Why these should agree:** Both claims describe the contract of `is_cached`.
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: uncoded-doc-navigation
3
+ description: Load once per session, before the first search or read of a codebase's Markdown documentation indexed by uncoded. Covers locating which file and section cover a topic, or orienting to what documentation exists.
4
+ ---
5
+
6
+ <!-- Generated by uncoded — do not edit; regeneration overwrites. -->
7
+
8
+ # Documentation Navigation
9
+
10
+ This codebase uses [uncoded](https://github.com/alimanfoo/uncoded) to maintain a
11
+ documentation index.
12
+
13
+ **Step 1: Orient. Read the docs map first.** If the map is missing, run the
14
+ repository's configured `uncoded sync` command. Then, before answering the user,
15
+ before any other tool call:
16
+
17
+ ```text
18
+ Read .uncoded/docs.yaml
19
+ ```
20
+
21
+ `.uncoded/docs.yaml` is an orientation outline: it lists every Markdown file and
22
+ its heading hierarchy. Read it once, in full, at session start.
23
+
24
+ **Step 2: Navigate.** Headings in the map are literal text. Use `Read` or `grep`
25
+ to navigate to a specific section identified in the map.
26
+
27
+ **Step 3: Refresh.** After every modification to indexed Markdown, run the
28
+ repository's configured `uncoded sync` command before the next
29
+ documentation-navigation operation. The modification can change the heading map.
@@ -15,7 +15,7 @@ jobs:
15
15
  fetch-depth: 0
16
16
  - uses: astral-sh/setup-uv@v6
17
17
  - run: uv python install 3.12
18
- - run: uv sync --extra dev
18
+ - run: uv sync
19
19
  - run: uv run pre-commit run --all-files
20
20
 
21
21
  test:
@@ -29,7 +29,7 @@ jobs:
29
29
  fetch-depth: 0
30
30
  - uses: astral-sh/setup-uv@v6
31
31
  - run: uv python install ${{ matrix.python-version }}
32
- - run: uv sync --extra dev
32
+ - run: uv sync
33
33
  - run: uv run pytest -v -m "integration or not integration"
34
34
  env:
35
35
  PYTHONWARNDEFAULTENCODING: "1"
@@ -0,0 +1,43 @@
1
+ name: Docs
2
+
3
+ # The site is already built in strict mode by the pull request checks. This
4
+ # workflow repeats that build from main and publishes its output.
5
+ on:
6
+ push:
7
+ branches: [main]
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ concurrency:
14
+ group: pages
15
+ cancel-in-progress: false
16
+
17
+ jobs:
18
+ build:
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
22
+ with:
23
+ fetch-depth: 0
24
+ - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
25
+ - run: uv sync --locked
26
+ - run: uv run mkdocs build
27
+ - uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
28
+ with:
29
+ path: site
30
+
31
+ deploy:
32
+ needs: build
33
+ runs-on: ubuntu-latest
34
+ permissions:
35
+ actions: read
36
+ pages: write
37
+ id-token: write
38
+ environment:
39
+ name: github-pages
40
+ url: ${{ steps.deployment.outputs.page_url }}
41
+ steps:
42
+ - id: deployment
43
+ uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1
@@ -32,6 +32,11 @@ repos:
32
32
  entry: uv run ty check src tests
33
33
  language: system
34
34
  pass_filenames: false
35
+ - id: complexipy
36
+ name: complexipy
37
+ entry: uv run complexipy src tests
38
+ language: system
39
+ pass_filenames: false
35
40
  # Runs before uncoded so the generated skill files are built from
36
41
  # already-formatted sources. The generated skill dirs are excluded
37
42
  # because uncoded sync owns those files.
@@ -43,8 +48,15 @@ repos:
43
48
  args: ["--write"]
44
49
  files: \.md$
45
50
  exclude: ^(CLAUDE\.md|(\.claude|\.agents)/skills/.*)$
51
+ - id: mkdocs
52
+ name: build documentation
53
+ entry: uv run mkdocs build
54
+ language: system
55
+ always_run: true
56
+ pass_filenames: false
46
57
  - id: uncoded
47
58
  name: uncoded
48
59
  entry: uv run uncoded sync
49
60
  language: system
61
+ always_run: true
50
62
  pass_filenames: false