disambiguate 0.1.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.
Files changed (34) hide show
  1. disambiguate-0.1.0/.agents/skills/documenting-decisions/README.md +35 -0
  2. disambiguate-0.1.0/.gitignore +216 -0
  3. disambiguate-0.1.0/LICENSE +22 -0
  4. disambiguate-0.1.0/PKG-INFO +102 -0
  5. disambiguate-0.1.0/README.md +79 -0
  6. disambiguate-0.1.0/docs/glossary/basename-resolution.md +20 -0
  7. disambiguate-0.1.0/docs/glossary/cross-reference.md +15 -0
  8. disambiguate-0.1.0/docs/glossary/dependency.md +14 -0
  9. disambiguate-0.1.0/docs/glossary/disambiguate.md +27 -0
  10. disambiguate-0.1.0/docs/glossary/from-mode.md +22 -0
  11. disambiguate-0.1.0/docs/glossary/github-format.md +18 -0
  12. disambiguate-0.1.0/docs/glossary/glossary-format.md +25 -0
  13. disambiguate-0.1.0/docs/glossary/glossary.md +12 -0
  14. disambiguate-0.1.0/docs/glossary/lint.md +29 -0
  15. disambiguate-0.1.0/docs/glossary/obsidian-format.md +18 -0
  16. disambiguate-0.1.0/docs/glossary/resolver.md +17 -0
  17. disambiguate-0.1.0/docs/glossary/slug.md +18 -0
  18. disambiguate-0.1.0/docs/glossary/term.md +12 -0
  19. disambiguate-0.1.0/docs/glossary/topological-order.md +14 -0
  20. disambiguate-0.1.0/hatch_build.py +64 -0
  21. disambiguate-0.1.0/pyproject.toml +148 -0
  22. disambiguate-0.1.0/src/disambiguate/__init__.py +10 -0
  23. disambiguate-0.1.0/src/disambiguate/__main__.py +13 -0
  24. disambiguate-0.1.0/src/disambiguate/bundled.py +58 -0
  25. disambiguate-0.1.0/src/disambiguate/cli.py +297 -0
  26. disambiguate-0.1.0/src/disambiguate/discovery.py +150 -0
  27. disambiguate-0.1.0/src/disambiguate/from_mode.py +62 -0
  28. disambiguate-0.1.0/src/disambiguate/glossary.py +131 -0
  29. disambiguate-0.1.0/src/disambiguate/lint.py +215 -0
  30. disambiguate-0.1.0/src/disambiguate/logging_config.py +51 -0
  31. disambiguate-0.1.0/src/disambiguate/parser.py +165 -0
  32. disambiguate-0.1.0/src/disambiguate/py.typed +0 -0
  33. disambiguate-0.1.0/src/disambiguate/renderer.py +73 -0
  34. disambiguate-0.1.0/src/disambiguate/resolver.py +92 -0
@@ -0,0 +1,35 @@
1
+ # Agent Instructions for Checkpoint Awareness
2
+
3
+ These are deliberately minimal — per the ETH Zurich AGENTbench study, verbose instruction files increase agent step count and cost without improving outcomes. Include only what the agent cannot infer from the codebase itself.
4
+
5
+ ## Combining blocks
6
+
7
+ Pick the minimal version plus whichever additional blocks match your risk profile. A typical combination for a web app with auth:
8
+
9
+ 1. decision-markers.md (always)
10
+ 2. pre-approval-gate.md (if tasks are large or loosely specified)
11
+ 3. security-hardening.md (if auth/payments/user data exist)
12
+ 4. irreversibility-protection.md (if the agent has DB access)
13
+
14
+ Resist the urge to add all blocks. Each instruction the agent reads adds steps and cost. Start minimal, add rules only after you observe a failure mode that the rule would have prevented.
15
+
16
+ If using the CODER/REVIEWER/TESTER subagent architecture:
17
+
18
+ ```markdown
19
+ ## Review protocol
20
+
21
+ CODER: When making noteworthy decisions during implementation, annotate them
22
+ inline with DECISION:<CATEGORY> markers. After completing the task, generate
23
+ DECISION_LOG.md from all markers in changed files.
24
+
25
+ REVIEWER: Verify decision markers against the actual diff:
26
+
27
+ - Every checkpoint-category change in the diff has a corresponding DECISION: marker
28
+ - No DECISION: markers reference code that doesn't exist
29
+ - Run: git diff origin/main --name-only | xargs grep -n "DECISION:" 2>/dev/null
30
+ - Flag any unlogged checkpoint changes as "UNLOGGED: [category] — [description]"
31
+ - If UNLOGGED items exist, the PR should not auto-merge regardless of test results
32
+
33
+ TESTER: Verify that tests exist for any DECISION:IFACE changes and that
34
+ DECISION:SEC changes have corresponding security test cases.
35
+ ```
@@ -0,0 +1,216 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ # Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ # poetry.lock
109
+ # poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ # pdm.lock
116
+ # pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ # pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # Redis
135
+ *.rdb
136
+ *.aof
137
+ *.pid
138
+
139
+ # RabbitMQ
140
+ mnesia/
141
+ rabbitmq/
142
+ rabbitmq-data/
143
+
144
+ # ActiveMQ
145
+ activemq-data/
146
+
147
+ # SageMath parsed files
148
+ *.sage.py
149
+
150
+ # Environments
151
+ .env
152
+ .envrc
153
+ .venv
154
+ env/
155
+ venv/
156
+ ENV/
157
+ env.bak/
158
+ venv.bak/
159
+
160
+ # Spyder project settings
161
+ .spyderproject
162
+ .spyproject
163
+
164
+ # Rope project settings
165
+ .ropeproject
166
+
167
+ # mkdocs documentation
168
+ /site
169
+
170
+ # mypy
171
+ .mypy_cache/
172
+ .dmypy.json
173
+ dmypy.json
174
+
175
+ # Pyre type checker
176
+ .pyre/
177
+
178
+ # pytype static type analyzer
179
+ .pytype/
180
+
181
+ # Cython debug symbols
182
+ cython_debug/
183
+
184
+ # PyCharm
185
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
186
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
187
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
188
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
189
+ .idea/
190
+
191
+ # Abstra
192
+ # Abstra is an AI-powered process automation framework.
193
+ # Ignore directories containing user credentials, local state, and settings.
194
+ # Learn more at https://abstra.io/docs
195
+ .abstra/
196
+
197
+ # Visual Studio Code
198
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
199
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
200
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
201
+ # you could uncomment the following to ignore the entire vscode folder
202
+ # .vscode/
203
+
204
+ # Ruff stuff:
205
+ .ruff_cache/
206
+
207
+ # PyPI configuration file
208
+ .pypirc
209
+
210
+ # Marimo
211
+ marimo/_static/
212
+ marimo/_lsp/
213
+ __marimo__/
214
+
215
+ # Streamlit
216
+ .streamlit/secrets.toml
@@ -0,0 +1,22 @@
1
+
2
+ MIT License
3
+
4
+ Copyright (c) 2026 Frankify
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -0,0 +1,102 @@
1
+ Metadata-Version: 2.4
2
+ Name: disambiguate
3
+ Version: 0.1.0
4
+ Summary: A tool to resolve markdown glossary terms and their transitive dependencies in topological order in a GitHub project or Obsidian vault.
5
+ Project-URL: Bug Tracker, https://github.com/frankify-app/disambiguate/issues
6
+ Project-URL: Changelog, https://github.com/frankify-app/disambiguate/blob/main/CHANGELOG.md
7
+ Project-URL: documentation, https://disambiguate.readthedocs.io
8
+ Project-URL: repository, https://github.com/frankify-app/disambiguate
9
+ Author-email: Frankify <creator@frankify.app>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Classifier: Development Status :: 2 - Pre-Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Natural Language :: English
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Topic :: Software Development :: Libraries
21
+ Requires-Python: >=3.12
22
+ Description-Content-Type: text/markdown
23
+
24
+ # Disambiguate
25
+
26
+ <p align="center">
27
+ <a href="https://github.com/frankify-app/disambiguate/actions/workflows/ci.yml?query=branch%3Amain">
28
+ <img src="https://img.shields.io/github/actions/workflow/status/frankify-app/disambiguate/ci.yml?branch=main&label=CI&logo=github&style=flat-square" alt="CI Status" >
29
+ </a>
30
+ <a href="https://codecov.io/gh/frankify-app/disambiguate">
31
+ <img src="https://img.shields.io/codecov/c/github/frankify-app/disambiguate.svg?logo=codecov&logoColor=fff&style=flat-square" alt="Test coverage percentage">
32
+ </a>
33
+ </p>
34
+ <p align="center">
35
+ <a href="https://github.com/astral-sh/uv">
36
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json" alt="uv">
37
+ </a>
38
+ <a href="https://github.com/astral-sh/ruff">
39
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff">
40
+ </a>
41
+ <a href="https://github.com/j178/prek">
42
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/j178/prek/master/docs/assets/badge-v0.json" alt="prek">
43
+ </a>
44
+ </p>
45
+ <p align="center">
46
+ <a href="https://pypi.org/project/disambiguate/">
47
+ <img src="https://img.shields.io/pypi/v/disambiguate.svg?logo=python&logoColor=fff&style=flat-square" alt="PyPI Version">
48
+ </a>
49
+ <img src="https://img.shields.io/pypi/pyversions/disambiguate.svg?style=flat-square&logo=python&amp;logoColor=fff" alt="Supported Python versions">
50
+ <img src="https://img.shields.io/pypi/l/disambiguate.svg?style=flat-square" alt="License">
51
+ </p>
52
+
53
+ ---
54
+
55
+ **Source Code**: <a href="https://github.com/frankify-app/disambiguate" target="_blank">https://github.com/frankify-app/disambiguate </a>
56
+
57
+ ---
58
+
59
+ Disambiguate resolves markdown glossary terms and their transitive
60
+ dependencies in topological order. Point it at a directory of `*.md` term
61
+ files in either [GitHub format](docs/glossary/github-format.md) or
62
+ [Obsidian format](docs/glossary/obsidian-format.md), ask for a slug or two,
63
+ and get back a self-contained markdown document where every term is
64
+ defined before it is referenced.
65
+
66
+ ## Quickstart
67
+
68
+ ```bash
69
+ uvx disambiguate # render the entire glossary
70
+ uvx disambiguate topological-order # render one term and its dependency closure
71
+ uvx disambiguate --from notes.md # extract glossary-shaped links from a doc
72
+ uvx disambiguate --explain # render Disambiguate's own bundled spec
73
+ uvx disambiguate --lint # validate the glossary
74
+ ```
75
+
76
+ The runtime is stdlib-only — `pip install disambiguate` brings in nothing
77
+ else. `uvx` works without an explicit install.
78
+
79
+ ## Installation
80
+
81
+ ```bash
82
+ pip install disambiguate
83
+ ```
84
+
85
+ ## How it works
86
+
87
+ The pipeline parses each [term](docs/glossary/term.md) into a body plus a
88
+ list of [cross-references](docs/glossary/cross-reference.md), builds a
89
+ [dependency](docs/glossary/dependency.md) graph from those references, then
90
+ runs the [resolver](docs/glossary/resolver.md) to produce
91
+ [topological order](docs/glossary/topological-order.md). The same pipeline
92
+ backs [from-mode](docs/glossary/from-mode.md) and `--explain`.
93
+
94
+ For the architectural map, see [docs/architecture.md](docs/architecture.md).
95
+ For the full vocabulary, see the
96
+ [bundled glossary](docs/glossary/disambiguate.md) — Disambiguate's own
97
+ dogfood.
98
+
99
+ ## Contributing
100
+
101
+ See [CONTRIBUTING.md](CONTRIBUTING.md). Conventional commits required —
102
+ the release workflow uses them to compute the next version.
@@ -0,0 +1,79 @@
1
+ # Disambiguate
2
+
3
+ <p align="center">
4
+ <a href="https://github.com/frankify-app/disambiguate/actions/workflows/ci.yml?query=branch%3Amain">
5
+ <img src="https://img.shields.io/github/actions/workflow/status/frankify-app/disambiguate/ci.yml?branch=main&label=CI&logo=github&style=flat-square" alt="CI Status" >
6
+ </a>
7
+ <a href="https://codecov.io/gh/frankify-app/disambiguate">
8
+ <img src="https://img.shields.io/codecov/c/github/frankify-app/disambiguate.svg?logo=codecov&logoColor=fff&style=flat-square" alt="Test coverage percentage">
9
+ </a>
10
+ </p>
11
+ <p align="center">
12
+ <a href="https://github.com/astral-sh/uv">
13
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json" alt="uv">
14
+ </a>
15
+ <a href="https://github.com/astral-sh/ruff">
16
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff">
17
+ </a>
18
+ <a href="https://github.com/j178/prek">
19
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/j178/prek/master/docs/assets/badge-v0.json" alt="prek">
20
+ </a>
21
+ </p>
22
+ <p align="center">
23
+ <a href="https://pypi.org/project/disambiguate/">
24
+ <img src="https://img.shields.io/pypi/v/disambiguate.svg?logo=python&logoColor=fff&style=flat-square" alt="PyPI Version">
25
+ </a>
26
+ <img src="https://img.shields.io/pypi/pyversions/disambiguate.svg?style=flat-square&logo=python&amp;logoColor=fff" alt="Supported Python versions">
27
+ <img src="https://img.shields.io/pypi/l/disambiguate.svg?style=flat-square" alt="License">
28
+ </p>
29
+
30
+ ---
31
+
32
+ **Source Code**: <a href="https://github.com/frankify-app/disambiguate" target="_blank">https://github.com/frankify-app/disambiguate </a>
33
+
34
+ ---
35
+
36
+ Disambiguate resolves markdown glossary terms and their transitive
37
+ dependencies in topological order. Point it at a directory of `*.md` term
38
+ files in either [GitHub format](docs/glossary/github-format.md) or
39
+ [Obsidian format](docs/glossary/obsidian-format.md), ask for a slug or two,
40
+ and get back a self-contained markdown document where every term is
41
+ defined before it is referenced.
42
+
43
+ ## Quickstart
44
+
45
+ ```bash
46
+ uvx disambiguate # render the entire glossary
47
+ uvx disambiguate topological-order # render one term and its dependency closure
48
+ uvx disambiguate --from notes.md # extract glossary-shaped links from a doc
49
+ uvx disambiguate --explain # render Disambiguate's own bundled spec
50
+ uvx disambiguate --lint # validate the glossary
51
+ ```
52
+
53
+ The runtime is stdlib-only — `pip install disambiguate` brings in nothing
54
+ else. `uvx` works without an explicit install.
55
+
56
+ ## Installation
57
+
58
+ ```bash
59
+ pip install disambiguate
60
+ ```
61
+
62
+ ## How it works
63
+
64
+ The pipeline parses each [term](docs/glossary/term.md) into a body plus a
65
+ list of [cross-references](docs/glossary/cross-reference.md), builds a
66
+ [dependency](docs/glossary/dependency.md) graph from those references, then
67
+ runs the [resolver](docs/glossary/resolver.md) to produce
68
+ [topological order](docs/glossary/topological-order.md). The same pipeline
69
+ backs [from-mode](docs/glossary/from-mode.md) and `--explain`.
70
+
71
+ For the architectural map, see [docs/architecture.md](docs/architecture.md).
72
+ For the full vocabulary, see the
73
+ [bundled glossary](docs/glossary/disambiguate.md) — Disambiguate's own
74
+ dogfood.
75
+
76
+ ## Contributing
77
+
78
+ See [CONTRIBUTING.md](CONTRIBUTING.md). Conventional commits required —
79
+ the release workflow uses them to compute the next version.
@@ -0,0 +1,20 @@
1
+ ## Basename resolution
2
+
3
+ The rule that a [cross-reference](cross-reference.md) is resolved to a term
4
+ purely by its basename, ignoring any directory components and the `.md`
5
+ extension.
6
+
7
+ All three of the following resolve identically to the term with
8
+ [slug](slug.md) `foo`:
9
+
10
+ - `[label](foo.md)`
11
+ - `[label](path/to/foo.md)`
12
+ - `[[foo]]`
13
+
14
+ This means a glossary can be moved or reorganized without rewriting links,
15
+ and the same term can be referenced consistently regardless of where the
16
+ referencing file lives. The trade-off: two terms cannot share a basename
17
+ even if they live in different subdirectories.
18
+
19
+ Non-`.md` links and absolute URLs are not subject to basename resolution and
20
+ are ignored entirely by the resolver.
@@ -0,0 +1,15 @@
1
+ ## Cross-reference
2
+
3
+ A link from one [term](term.md) to another. Cross-references come in two
4
+ syntactic forms, both supported:
5
+
6
+ - Standard markdown: `[some text](path/to/foo.md)` — resolves to the term
7
+ whose slug matches the link's basename, regardless of path.
8
+ - Wiki-style: `[[foo]]` — resolves directly to the term with slug `foo`.
9
+
10
+ Cross-references are the edges of the dependency graph. A term that
11
+ cross-references another depends on it: when rendered, the referenced term
12
+ must come first.
13
+
14
+ Cross-references inside fenced code blocks are ignored — code samples that
15
+ happen to contain link-shaped text do not create edges.
@@ -0,0 +1,14 @@
1
+ ## Dependency
2
+
3
+ A directed edge from one [term](term.md) to another, created by a
4
+ [cross-reference](cross-reference.md) inside the term's body. If term `a`
5
+ cross-references term `b`, then `a` depends on `b`: `b` must appear before
6
+ `a` in the rendered output, because `a`'s definition assumes `b` is already
7
+ defined.
8
+
9
+ Dependencies are transitive. Resolving a term pulls in everything it depends
10
+ on, recursively. The complete dependency closure of a term is the set of all
11
+ terms reachable by following edges out from it.
12
+
13
+ The dependency graph is required to be acyclic. Cycles are a lint error —
14
+ they make ordering impossible.
@@ -0,0 +1,27 @@
1
+ ## Disambiguate
2
+
3
+ The CLI tool this glossary describes. Capitalized "Disambiguate" when
4
+ referring to the tool as a proper noun; lowercase only as the command-line
5
+ invocation `uvx disambiguate`.
6
+
7
+ Disambiguate takes a markdown [glossary](glossary.md), follows the
8
+ [dependency](dependency.md) edges between [terms](term.md), and emits the
9
+ selected closure in [topological order](topological-order.md). Three
10
+ operating modes:
11
+
12
+ - **Default**: render selected slugs (or the whole glossary) — the
13
+ [resolver](resolver.md) is the engine.
14
+ - **`--from <doc>`**: extract the slugs implicitly used in a document and
15
+ resolve those — see [from-mode](from-mode.md).
16
+ - **`--lint`**: validate the glossary's structural integrity — see
17
+ [lint](lint.md).
18
+
19
+ Plus `--explain`, which always renders Disambiguate's own bundled glossary
20
+ (this very glossary) regardless of which user glossary is in scope. The
21
+ intended audience for `--explain` is an LLM agent that needs to understand
22
+ Disambiguate's vocabulary before generating glossary content of its own.
23
+
24
+ Disambiguate has no third-party runtime dependencies. The implementation
25
+ fits inside the Python standard library — `argparse`, `graphlib`,
26
+ `pathlib`, `re`, `glob`, `importlib.resources`, `logging`. Installable as a
27
+ single wheel; runnable via `uvx disambiguate` with no environment setup.
@@ -0,0 +1,22 @@
1
+ ## From-mode
2
+
3
+ The CLI mode triggered by `--from <path>`: extract glossary-shaped
4
+ [cross-references](cross-reference.md) from a document, then run the
5
+ [resolver](resolver.md) over the extracted [slugs](slug.md).
6
+
7
+ The path argument can be `-` (or omitted entirely) to read the source
8
+ document from standard input. Useful for piping prose through Disambiguate
9
+ to produce a glossary preamble for whatever vocabulary it actually uses.
10
+
11
+ Link classification:
12
+
13
+ - A link whose basename matches a slug in the active glossary is treated as
14
+ a request for that term.
15
+ - A glossary-shaped link with a broken slug — basename ending in `.md` but
16
+ not matching any term — is an error. From-mode does not silently ignore
17
+ unresolvable references.
18
+ - Non-glossary links (external URLs, image paths, links to non-`.md` files)
19
+ are silently ignored.
20
+
21
+ Output is identical to a direct `disambiguate <slug> ...` invocation: the
22
+ dependency closure in topological order.
@@ -0,0 +1,18 @@
1
+ ## GitHub format
2
+
3
+ The [glossary-format](glossary-format.md) variant intended for GitHub
4
+ projects. Terms live at `docs/glossary/` (or another path inside the repo)
5
+ and are rendered by GitHub's standard markdown renderer.
6
+
7
+ [Cross-references](cross-reference.md) use standard markdown links:
8
+ `[label](other.md)` or `[label](path/to/other.md)`. GitHub renders these
9
+ inline; the link target resolves at the repository level when viewed on
10
+ GitHub.
11
+
12
+ Wiki-style `[[slug]]` links also work for Disambiguate's purposes — they
13
+ will not render as live links on GitHub, but the resolver still picks them
14
+ up. Use them only if you also intend the glossary to be browsable as an
15
+ Obsidian vault.
16
+
17
+ This is the default variant. A new project setting up a glossary should
18
+ assume the GitHub format unless there is a specific reason to do otherwise.
@@ -0,0 +1,25 @@
1
+ ## Glossary format
2
+
3
+ The shared shape of a Disambiguate-compatible [glossary](glossary.md). A
4
+ single directory containing one [term](term.md) per markdown file.
5
+
6
+ Per-file structure:
7
+
8
+ - File basename (with `.md` stripped) is the [slug](slug.md). Slugs must be
9
+ unique across the directory and use lowercase ASCII letters, digits, and
10
+ hyphens.
11
+ - The first H2 heading (`## Canonical Name`) is the term's display name. The
12
+ H2 is mandatory.
13
+ - Body is free-form markdown.
14
+ - [Cross-references](cross-reference.md) to other terms use either standard
15
+ markdown (`[text](other.md)`) or wiki-style (`[[other]]`). Both resolve by
16
+ basename.
17
+
18
+ The format is intentionally minimal — anything outside of H2 + cross-link
19
+ syntax is just markdown, rendered as-is. This keeps glossaries portable
20
+ between platforms with different markdown extensions, while letting each
21
+ platform's variant of the format add its own conventions on top.
22
+
23
+ Two such variants exist today — one for GitHub-rendered repositories and
24
+ one for Obsidian vaults. Both are special cases of the format defined here,
25
+ with platform-specific tweaks.
@@ -0,0 +1,12 @@
1
+ ## Glossary
2
+
3
+ A directory of [term](term.md) files. The glossary is the unit Disambiguate
4
+ operates on: load it, resolve from it, render from it, lint it.
5
+
6
+ By convention the glossary lives at `docs/glossary/` or `glossary/` at the
7
+ root of a project. Disambiguate auto-discovers the nearest such directory by
8
+ walking up from the current working directory. The location can be overridden
9
+ with `--glossary <path>` or the `DISAMBIGUATE_GLOSSARY` environment variable.
10
+
11
+ A glossary contains zero or more terms. Slug uniqueness is enforced across
12
+ the directory — two files with the same basename are an error.
@@ -0,0 +1,29 @@
1
+ ## Lint
2
+
3
+ The `--lint` mode validates a [glossary](glossary.md) against six
4
+ constraints. Any violation is fatal — the command exits non-zero with the
5
+ problem reported to stderr.
6
+
7
+ Checks:
8
+
9
+ - **Cycles** in the [dependency](dependency.md) graph. A cycle makes
10
+ topological ordering impossible.
11
+ - **Broken cross-references**: a [cross-reference](cross-reference.md) whose
12
+ basename does not match any term in the glossary.
13
+ - **Duplicate slugs**: two term files sharing a basename.
14
+ - **Missing H2 heading**: a term file with no `## ` heading on any line. The
15
+ H2 is the canonical name; without it the term has no identity.
16
+ - **Invalid slug format**: a [slug](slug.md) that does not match the canonical
17
+ format `^[a-z0-9]+(?:-[a-z0-9]+)*$` — lowercase letters, digits, and single
18
+ hyphens between segments.
19
+ - **Reachability orphans**: terms that no configured root document can reach
20
+ by following markdown links. Roots default to the repository's
21
+ `README.md`; override with `--roots` or `DISAMBIGUATE_ROOTS`.
22
+
23
+ Reachability uses a visited-set walk over both glossary terms and external
24
+ markdown documents. Cycles in external documents are tolerated — the walk
25
+ does not topo-sort, it just collects everything visitable.
26
+
27
+ The orphan check exists to keep the glossary honest. If a term is not
28
+ linked from anywhere a reader is likely to start, it is dead vocabulary,
29
+ and the lint says so.
@@ -0,0 +1,18 @@
1
+ ## Obsidian format
2
+
3
+ The [glossary-format](glossary-format.md) variant intended for use as an
4
+ Obsidian vault. Terms live in a folder inside the vault, browsed and edited
5
+ through Obsidian.
6
+
7
+ [Cross-references](cross-reference.md) typically use the wiki-style syntax:
8
+ `[[slug]]`. Obsidian renders these as live, clickable backlinks and shows
9
+ them in the graph view, which is the main reason to choose this variant.
10
+
11
+ Standard markdown links (`[label](other.md)`) also work for the resolver
12
+ and render correctly in Obsidian, but lose the backlink and graph view
13
+ benefits. Use wiki-style links by preference; fall back to markdown links
14
+ only when a particular section needs custom link text.
15
+
16
+ The on-disk file shape is identical to the GitHub format variant — the
17
+ same glossary directory can serve both audiences if links are written in
18
+ either syntax consistently.