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.
- disambiguate-0.1.0/.agents/skills/documenting-decisions/README.md +35 -0
- disambiguate-0.1.0/.gitignore +216 -0
- disambiguate-0.1.0/LICENSE +22 -0
- disambiguate-0.1.0/PKG-INFO +102 -0
- disambiguate-0.1.0/README.md +79 -0
- disambiguate-0.1.0/docs/glossary/basename-resolution.md +20 -0
- disambiguate-0.1.0/docs/glossary/cross-reference.md +15 -0
- disambiguate-0.1.0/docs/glossary/dependency.md +14 -0
- disambiguate-0.1.0/docs/glossary/disambiguate.md +27 -0
- disambiguate-0.1.0/docs/glossary/from-mode.md +22 -0
- disambiguate-0.1.0/docs/glossary/github-format.md +18 -0
- disambiguate-0.1.0/docs/glossary/glossary-format.md +25 -0
- disambiguate-0.1.0/docs/glossary/glossary.md +12 -0
- disambiguate-0.1.0/docs/glossary/lint.md +29 -0
- disambiguate-0.1.0/docs/glossary/obsidian-format.md +18 -0
- disambiguate-0.1.0/docs/glossary/resolver.md +17 -0
- disambiguate-0.1.0/docs/glossary/slug.md +18 -0
- disambiguate-0.1.0/docs/glossary/term.md +12 -0
- disambiguate-0.1.0/docs/glossary/topological-order.md +14 -0
- disambiguate-0.1.0/hatch_build.py +64 -0
- disambiguate-0.1.0/pyproject.toml +148 -0
- disambiguate-0.1.0/src/disambiguate/__init__.py +10 -0
- disambiguate-0.1.0/src/disambiguate/__main__.py +13 -0
- disambiguate-0.1.0/src/disambiguate/bundled.py +58 -0
- disambiguate-0.1.0/src/disambiguate/cli.py +297 -0
- disambiguate-0.1.0/src/disambiguate/discovery.py +150 -0
- disambiguate-0.1.0/src/disambiguate/from_mode.py +62 -0
- disambiguate-0.1.0/src/disambiguate/glossary.py +131 -0
- disambiguate-0.1.0/src/disambiguate/lint.py +215 -0
- disambiguate-0.1.0/src/disambiguate/logging_config.py +51 -0
- disambiguate-0.1.0/src/disambiguate/parser.py +165 -0
- disambiguate-0.1.0/src/disambiguate/py.typed +0 -0
- disambiguate-0.1.0/src/disambiguate/renderer.py +73 -0
- 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&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&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.
|