dotmd-parser 0.2.1__tar.gz → 0.6.2__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.
- dotmd_parser-0.6.2/PKG-INFO +424 -0
- dotmd_parser-0.6.2/README.md +387 -0
- {dotmd_parser-0.2.1 → dotmd_parser-0.6.2}/pyproject.toml +17 -2
- dotmd_parser-0.6.2/src/dotmd_parser/__init__.py +131 -0
- dotmd_parser-0.6.2/src/dotmd_parser/analyze.py +676 -0
- dotmd_parser-0.6.2/src/dotmd_parser/cli.py +585 -0
- dotmd_parser-0.6.2/src/dotmd_parser/digest.py +193 -0
- dotmd_parser-0.6.2/src/dotmd_parser/index.py +300 -0
- dotmd_parser-0.6.2/src/dotmd_parser/index_md.py +716 -0
- dotmd_parser-0.6.2/src/dotmd_parser/inventory.py +302 -0
- dotmd_parser-0.6.2/src/dotmd_parser/openrag.py +150 -0
- {dotmd_parser-0.2.1 → dotmd_parser-0.6.2}/src/dotmd_parser/parser.py +108 -39
- dotmd_parser-0.6.2/src/dotmd_parser/templates/SKILL.md +212 -0
- dotmd_parser-0.6.2/src/dotmd_parser/templates/__init__.py +1 -0
- dotmd_parser-0.6.2/src/dotmd_parser/templates/dotmd_index/SKILL.md +254 -0
- dotmd_parser-0.6.2/src/dotmd_parser/templates/dotmd_index/__init__.py +0 -0
- dotmd_parser-0.6.2/src/dotmd_parser/templates/prompts/__init__.py +1 -0
- dotmd_parser-0.6.2/src/dotmd_parser/templates/prompts/analyze-dependencies.md +42 -0
- dotmd_parser-0.6.2/src/dotmd_parser.egg-info/PKG-INFO +424 -0
- dotmd_parser-0.6.2/src/dotmd_parser.egg-info/SOURCES.txt +37 -0
- dotmd_parser-0.6.2/src/dotmd_parser.egg-info/requires.txt +14 -0
- dotmd_parser-0.6.2/tests/test_aggregate.py +149 -0
- dotmd_parser-0.6.2/tests/test_analyze.py +254 -0
- dotmd_parser-0.6.2/tests/test_cli_dotmd_index.py +133 -0
- dotmd_parser-0.6.2/tests/test_cost_estimate.py +148 -0
- dotmd_parser-0.6.2/tests/test_empty_warnings.py +116 -0
- dotmd_parser-0.6.2/tests/test_host_agent_plan.py +174 -0
- dotmd_parser-0.6.2/tests/test_index_md.py +233 -0
- dotmd_parser-0.6.2/tests/test_index_scope.py +195 -0
- dotmd_parser-0.6.2/tests/test_inventory.py +195 -0
- dotmd_parser-0.6.2/tests/test_openrag_push.py +199 -0
- {dotmd_parser-0.2.1 → dotmd_parser-0.6.2}/tests/test_parser.py +98 -97
- dotmd_parser-0.6.2/tests/test_skill_integration.py +315 -0
- dotmd_parser-0.6.2/tests/test_token_savings.py +263 -0
- dotmd_parser-0.2.1/PKG-INFO +0 -195
- dotmd_parser-0.2.1/README.md +0 -168
- dotmd_parser-0.2.1/src/dotmd_parser/__init__.py +0 -33
- dotmd_parser-0.2.1/src/dotmd_parser.egg-info/PKG-INFO +0 -195
- dotmd_parser-0.2.1/src/dotmd_parser.egg-info/SOURCES.txt +0 -11
- {dotmd_parser-0.2.1 → dotmd_parser-0.6.2}/LICENSE +0 -0
- {dotmd_parser-0.2.1 → dotmd_parser-0.6.2}/setup.cfg +0 -0
- {dotmd_parser-0.2.1 → dotmd_parser-0.6.2}/src/dotmd_parser.egg-info/dependency_links.txt +0 -0
- {dotmd_parser-0.2.1 → dotmd_parser-0.6.2}/src/dotmd_parser.egg-info/entry_points.txt +0 -0
- {dotmd_parser-0.2.1 → dotmd_parser-0.6.2}/src/dotmd_parser.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dotmd-parser
|
|
3
|
+
Version: 0.6.2
|
|
4
|
+
Summary: Dependency graph parser, single-file folder index (dotmd-index.md), and AI analyzer for .md skill files — parse @include/@delegate/@ref directives, build graphs, resolve templates, generate RAG-friendly overviews, and ingest into OpenRAG
|
|
5
|
+
Author: dotmd-projects
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/dotmd-projects/dotmd-parser
|
|
8
|
+
Project-URL: Repository, https://github.com/dotmd-projects/dotmd-parser
|
|
9
|
+
Project-URL: Issues, https://github.com/dotmd-projects/dotmd-parser/issues
|
|
10
|
+
Keywords: claude-code,ai-agent,skill-management,prompt-engineering,dependency-graph,SKILL.md,markdown,parser,dotmd,llm
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
21
|
+
Classifier: Topic :: Text Processing :: Markup :: Markdown
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Provides-Extra: openrag
|
|
27
|
+
Requires-Dist: openrag-sdk>=0.3.1; extra == "openrag"
|
|
28
|
+
Provides-Extra: pdf
|
|
29
|
+
Requires-Dist: pdfplumber>=0.10; extra == "pdf"
|
|
30
|
+
Provides-Extra: docx
|
|
31
|
+
Requires-Dist: python-docx>=1.0; extra == "docx"
|
|
32
|
+
Provides-Extra: all
|
|
33
|
+
Requires-Dist: openrag-sdk>=0.3.1; extra == "all"
|
|
34
|
+
Requires-Dist: pdfplumber>=0.10; extra == "all"
|
|
35
|
+
Requires-Dist: python-docx>=1.0; extra == "all"
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
# dotmd-parser
|
|
39
|
+
|
|
40
|
+
[](https://pypi.org/project/dotmd-parser/)
|
|
41
|
+
[](https://pypi.org/project/dotmd-parser/)
|
|
42
|
+
[](LICENSE)
|
|
43
|
+
|
|
44
|
+

|
|
45
|
+
|
|
46
|
+
> [日本語版 README はこちら](README.ja.md)
|
|
47
|
+
|
|
48
|
+
Dependency graph parser for `.md` skill files — built for AI agent prompt engineering with [Claude Code](https://docs.anthropic.com/en/docs/claude-code) and similar tools.
|
|
49
|
+
|
|
50
|
+
## Why dotmd-parser?
|
|
51
|
+
|
|
52
|
+
As AI agent projects grow, `.md` files start referencing each other via `@include`, `@delegate`, and `@ref` directives. Without tooling, you're left manually tracing dependencies to answer basic questions:
|
|
53
|
+
|
|
54
|
+
- *"Which files break if I edit `shared/role.md`?"*
|
|
55
|
+
- *"Is there a circular reference hiding in my skill tree?"*
|
|
56
|
+
- *"What `{{variables}}` are still unresolved after expansion?"*
|
|
57
|
+
|
|
58
|
+
**dotmd-parser** solves this by parsing your `.md` files into a dependency graph — automatically detecting directives, runtime references, and template placeholders. One function call gives you the full picture.
|
|
59
|
+
|
|
60
|
+
## Token savings — measured
|
|
61
|
+
|
|
62
|
+
The single biggest reason to reach for `dotmd-parser` in an agent loop is
|
|
63
|
+
that it lets Claude understand a folder **without reading every file**.
|
|
64
|
+
The numbers below are produced by `tests/test_token_savings.py` (run
|
|
65
|
+
with `DOTMD_TOKEN_REPORT=1 pytest -s`) using `tiktoken`'s `cl100k_base`
|
|
66
|
+
encoding (a close proxy for Claude's tokenizer family):
|
|
67
|
+
|
|
68
|
+
| Folder profile | Files | Naive read of every `.md` | `dotmd-index.md` | `digest` |
|
|
69
|
+
|---|---:|---:|---:|---:|
|
|
70
|
+
| Small skill (each file ~2 KB) | 4 | 1,610 tokens | **605 (0.38×)** | 174 (0.11×) |
|
|
71
|
+
| Medium docs (each file ~2 KB) | 31 | 15,855 tokens | **2,837 (0.18× → 5.6× cheaper)** | 1,285 (0.08×) |
|
|
72
|
+
| Large docs (each file ~2 KB) | 111 | 58,171 tokens | **9,535 (0.16× → 6.3× cheaper)** | 4,606 (0.08×) |
|
|
73
|
+
|
|
74
|
+
**Takeaway**: at ~30 files dotmd-parser already cuts Claude's reading
|
|
75
|
+
cost by **~5.6×**, and the savings *grow* with folder size. At 100+
|
|
76
|
+
files the same context window now fits **6× more conversation**, or
|
|
77
|
+
serves the same prompt at **1/6 the input-token spend**.
|
|
78
|
+
|
|
79
|
+
The persistent `dotmd-index.md` artifact pays a fixed frontmatter
|
|
80
|
+
overhead, so for *very small* folders (a handful of files of a few
|
|
81
|
+
hundred bytes) the naive read can still win. The `digest` output is
|
|
82
|
+
even more compact (~12× cheaper at scale) but isn't persisted on disk —
|
|
83
|
+
use `dotmd-index.md` for stable navigation, `digest` for one-shot
|
|
84
|
+
summaries.
|
|
85
|
+
|
|
86
|
+
The break-even is around **4 files × 1 KB each**: above that,
|
|
87
|
+
`dotmd-index.md` is always cheaper than reading the folder by hand.
|
|
88
|
+
|
|
89
|
+
## Comparison
|
|
90
|
+
|
|
91
|
+
| Capability | Manual / grep | dotmd-parser |
|
|
92
|
+
|---|---|---|
|
|
93
|
+
| Find `@include` / `@delegate` / `@ref` references | `grep -r "@include"` — flat list, no context | Structured graph with node types and edge metadata |
|
|
94
|
+
| Detect circular references | Hope you notice before the agent loops | Automatic detection with full cycle path in warnings |
|
|
95
|
+
| Reverse dependency ("what breaks?") | Manually trace every file | `dependents_of(graph, "shared/role.md")` — one call |
|
|
96
|
+
| Expand `@include` to final text | Copy-paste by hand | `resolve("SKILL.md", variables={...})` — recursive expansion |
|
|
97
|
+
| Find unresolved `{{variables}}` | `grep "{{" *.md` — noisy, no dedup | Deduplicated list per node and after expansion |
|
|
98
|
+
| Missing file detection | Runtime failure | Warnings at parse time with exact paths |
|
|
99
|
+
| Detect **implicit** deps (no directives yet) | Read every file, draw by hand | `analyze` subcommand asks Claude, emits `@include` / `deps.yml` |
|
|
100
|
+
| Feed Claude Code with compact context | Read 20 files × 5 KB each | `digest` outputs one ~2 KB summary; `.claude/dotmd-index.json` cache |
|
|
101
|
+
|
|
102
|
+
## Installation
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
pip install dotmd-parser
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Quick Start
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
from dotmd_parser import build_graph, resolve, dependents_of, summary
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### build_graph — Build a dependency graph
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
graph = build_graph("./my-skill/")
|
|
118
|
+
# or from a specific file
|
|
119
|
+
graph = build_graph("./my-skill/SKILL.md")
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"nodes": [
|
|
127
|
+
{"id": "/abs/path/to/SKILL.md", "type": "skill", "missing": false, "placeholders": []}
|
|
128
|
+
],
|
|
129
|
+
"edges": [
|
|
130
|
+
{"from": "...", "to": "...", "type": "include", "parallel": false}
|
|
131
|
+
],
|
|
132
|
+
"warnings": []
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Custom node type mapping:**
|
|
137
|
+
|
|
138
|
+
By default, node types are inferred from path keywords (`agent`, `shared`, `prompt`, `reference`, `asset`, `template`). You can override this with the `type_map` parameter:
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
graph = build_graph("./my-skill/", type_map=[
|
|
142
|
+
("helper", "utility"),
|
|
143
|
+
("core", "foundation"),
|
|
144
|
+
])
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**deps.yml support:**
|
|
148
|
+
|
|
149
|
+
If a `deps.yml` file exists in the root directory, its dependencies are automatically merged into the graph:
|
|
150
|
+
|
|
151
|
+
```yaml
|
|
152
|
+
- path: agents/planner.md
|
|
153
|
+
includes:
|
|
154
|
+
- shared/role.md
|
|
155
|
+
- shared/tools.md
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### resolve — Expand @include directives
|
|
159
|
+
|
|
160
|
+
Recursively expands `@include` directives into final text. `@delegate` and `@ref` lines are left as-is.
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
result = resolve("./prompts/main.md", variables={"name": "Alice"})
|
|
164
|
+
|
|
165
|
+
print(result["content"]) # Fully expanded text
|
|
166
|
+
print(result["placeholders"]) # Unresolved {{variable}} names
|
|
167
|
+
print(result["warnings"]) # Circular refs, missing files, etc.
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### dependents_of — Reverse dependency query
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
# "If I change shared/role.md, what else breaks?"
|
|
174
|
+
affected = dependents_of(graph, "/abs/path/to/shared/role.md")
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### summary — Human-readable overview
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
print(summary(graph))
|
|
181
|
+
# Nodes: 5 (agent:1, prompt:1, shared:2, skill:1)
|
|
182
|
+
# Edges: 4 (include:2, ref:1, read-ref:1)
|
|
183
|
+
# Warnings: 0
|
|
184
|
+
# Placeholders: name, role
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Supported Directives
|
|
188
|
+
|
|
189
|
+
| Directive | Edge type | Expanded by `resolve()`? | Description |
|
|
190
|
+
|---|---|---|---|
|
|
191
|
+
| `@include path/to/file.md` | `include` | Yes | Inline expansion — file content is inserted at this position |
|
|
192
|
+
| `@delegate path/to/agent.md` | `delegate` | No | Agent delegation — recorded in graph, left as-is in output |
|
|
193
|
+
| `@delegate path/to/agent.md --parallel` | `delegate` | No | Parallel delegation with `--parallel` flag |
|
|
194
|
+
| `@ref path/to/file.md` | `ref` | No | Runtime reference — recorded in graph, left as-is in output |
|
|
195
|
+
| `` Read `path/to/file.md` `` | `read-ref` | No | Legacy runtime reference (same as `@ref`, kept for backward compatibility) |
|
|
196
|
+
|
|
197
|
+
## Utility Functions
|
|
198
|
+
|
|
199
|
+
Lower-level parsing functions are also exported for custom use:
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
from dotmd_parser import parse_directives, parse_read_refs, parse_placeholders, parse_deps_yml
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
| Function | Description |
|
|
206
|
+
|---|---|
|
|
207
|
+
| `parse_directives(content)` | Extract `@include` / `@delegate` / `@ref` directives from text |
|
|
208
|
+
| `parse_read_refs(content)` | Extract legacy `Read`/`See`/list-style `.md` references (deduplicated) |
|
|
209
|
+
| `parse_placeholders(content)` | Extract `{{variable}}` placeholder names (deduplicated) |
|
|
210
|
+
| `parse_deps_yml(content)` | Parse `deps.yml` text into `{path: [includes]}` dict (no PyYAML required) |
|
|
211
|
+
|
|
212
|
+
## CLI
|
|
213
|
+
|
|
214
|
+
`dotmd-parser` ships with sub-commands tuned for Claude Code and CI use. Running `dotmd-parser <path>` with no sub-command still works and falls through to `show` for backward compatibility.
|
|
215
|
+
|
|
216
|
+
| Command | Purpose |
|
|
217
|
+
|---|---|
|
|
218
|
+
| `dotmd-parser inventory <path>` | **API-free**: extension counts, markdown/binary ratio, largest files |
|
|
219
|
+
| `dotmd-parser dotmd-index <path>` | **API-free**: generate `<path>/dotmd-index.md` (single-file folder overview) |
|
|
220
|
+
| `dotmd-parser dotmd-index <path> --aggregate` | Roll up nested `dotmd-index.md` files into the parent (Sub-Indexes section) |
|
|
221
|
+
| `dotmd-parser dotmd-index <path> --push-openrag` | After writing, ingest into OpenRAG (`pip install dotmd-parser[openrag]`) |
|
|
222
|
+
| `dotmd-parser index <path>` | Build and save `.claude/dotmd-index.json` |
|
|
223
|
+
| `dotmd-parser index <path> --scope <subdir>` | Incrementally re-index one subfolder, merge into the existing index |
|
|
224
|
+
| `dotmd-parser check <path>` | Exit non-zero on cycles / missing refs (CI-friendly) |
|
|
225
|
+
| `dotmd-parser affects <path> <file>` | Reverse dependencies of `<file>` |
|
|
226
|
+
| `dotmd-parser deps <path> <file>` | Direct dependencies of `<file>` |
|
|
227
|
+
| `dotmd-parser digest <path>` | Token-efficient text summary for LLM context |
|
|
228
|
+
| `dotmd-parser tree <path>` | ASCII dependency tree |
|
|
229
|
+
| `dotmd-parser resolve <file> [--var k=v]` | Recursively expand `@include` |
|
|
230
|
+
| `dotmd-parser analyze <path>` | AI dependency detection (requires `ANTHROPIC_API_KEY`) |
|
|
231
|
+
| `dotmd-parser analyze <path> --dry-run` | **API-free**: estimate tokens and USD cost |
|
|
232
|
+
| `dotmd-parser analyze <path> --plan` | **API-free**: emit a host-agent prompt pack for Claude Code to execute |
|
|
233
|
+
| `dotmd-parser analyze <path> --apply-from <json>` | Apply a pre-computed analysis JSON |
|
|
234
|
+
| `dotmd-parser init [--skill dotmd-index]` | Install a bundled SKILL.md into `.claude/skills/<id>/` |
|
|
235
|
+
| `dotmd-parser show <path>` | Summary + full JSON graph (legacy default) |
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
# Typical Claude Code workflow
|
|
239
|
+
dotmd-parser inventory ./my-skill/ # start here if you've never seen the folder
|
|
240
|
+
dotmd-parser dotmd-index ./my-skill/ # write ./my-skill/dotmd-index.md (Claude reads ONLY this file)
|
|
241
|
+
dotmd-parser index ./my-skill/ # one-off; cached until files change
|
|
242
|
+
dotmd-parser digest ./my-skill/ # compact summary for the LLM
|
|
243
|
+
dotmd-parser affects ./my-skill/ shared/role.md
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## `dotmd-index.md` — folder overview in a single file
|
|
247
|
+
|
|
248
|
+
`dotmd-parser dotmd-index <path>` writes `<path>/dotmd-index.md`, a
|
|
249
|
+
self-contained Markdown file that combines `inventory()` and
|
|
250
|
+
`build_index()` into one artifact Claude can read **instead of**
|
|
251
|
+
grep-scanning every file in the folder.
|
|
252
|
+
|
|
253
|
+
The file contains:
|
|
254
|
+
|
|
255
|
+
- YAML frontmatter (`schema`, `content_hash`, `stats`, RAG `chunks[]`)
|
|
256
|
+
- `## Summary` (file counts, total size, health)
|
|
257
|
+
- `## Folder Map` (depth-limited ASCII tree)
|
|
258
|
+
- `## Files` (markdown: title + desc + deps; other: kind + size)
|
|
259
|
+
- `## Dependency Tree` (`@include` / `@delegate` / `@ref` graph as ASCII)
|
|
260
|
+
- `## Placeholders` (unresolved `{{...}}` variables)
|
|
261
|
+
- `<!-- chunk:id -->` HTML markers so any RAG tool can split deterministically
|
|
262
|
+
|
|
263
|
+
Re-running on an unchanged folder writes nothing (`content_hash` matches).
|
|
264
|
+
The command refuses to overwrite a hand-written `dotmd-index.md` unless
|
|
265
|
+
`--force` is passed.
|
|
266
|
+
|
|
267
|
+
### Aggregating across nested folders
|
|
268
|
+
|
|
269
|
+
Run with `--aggregate` to roll up descendant artifacts:
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
dotmd-parser dotmd-index ./project/ --aggregate
|
|
273
|
+
# project/dotmd-index.md now references project/docs/dotmd-index.md and
|
|
274
|
+
# project/src/dotmd-index.md without duplicating their file listings.
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Each child is discovered, its frontmatter is read, and a one-line
|
|
278
|
+
summary (file count, edges, health) appears under `## Sub-Indexes`.
|
|
279
|
+
The `aggregates[]` frontmatter array records each child's `content_hash`
|
|
280
|
+
so staleness is easy to detect. User-authored `dotmd-index.md` files
|
|
281
|
+
that lack `generated_by: dotmd-parser` are silently skipped.
|
|
282
|
+
|
|
283
|
+
This is a **reference**, not a merge — Claude reads the parent to learn
|
|
284
|
+
which subfolders exist, then drills into the relevant child file. The
|
|
285
|
+
parent stays token-efficient even with deeply nested trees.
|
|
286
|
+
|
|
287
|
+
### OpenRAG integration
|
|
288
|
+
|
|
289
|
+
[OpenRAG](https://github.com/langflow-ai/openrag) is a self-hosted RAG
|
|
290
|
+
platform built on Langflow + Docling + OpenSearch. dotmd-parser can ship
|
|
291
|
+
the artifact straight into it:
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
pip install dotmd-parser[openrag] # adds openrag-sdk
|
|
295
|
+
export OPENRAG_URL=http://localhost:3000
|
|
296
|
+
export OPENRAG_API_KEY=... # if your instance requires auth
|
|
297
|
+
|
|
298
|
+
dotmd-parser dotmd-index ./docs/ --push-openrag
|
|
299
|
+
# 1. Writes ./docs/dotmd-index.md
|
|
300
|
+
# 2. Calls OpenRAGClient.documents.ingest(file_path=...)
|
|
301
|
+
# 3. Records {document_id, base_url, pushed_at} in exports.openrag
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
`dotmd-index.md` is the **map** (one-shot overview); OpenRAG is the
|
|
305
|
+
**search index** (full-content semantic retrieval). Register OpenRAG's
|
|
306
|
+
MCP server with Claude Code to use both surfaces from the same client.
|
|
307
|
+
|
|
308
|
+
## `analyze` — AI-assisted dependency detection
|
|
309
|
+
|
|
310
|
+
Use when a folder of markdown has **no explicit directives yet**. `analyze`
|
|
311
|
+
asks Claude to infer dependencies and can apply the result in one step:
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
export ANTHROPIC_API_KEY=... # or put it in ./.env
|
|
315
|
+
|
|
316
|
+
dotmd-parser analyze ./docs/ # runs the proposal (uses API)
|
|
317
|
+
dotmd-parser analyze ./docs/ --apply # inject @include, write deps.yml
|
|
318
|
+
dotmd-parser analyze ./docs/ --json # machine-readable
|
|
319
|
+
dotmd-parser analyze ./docs/ --ext md --ext pdf --ext docx
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### No-API-key workflows
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
# Estimate cost before spending any API credit
|
|
326
|
+
dotmd-parser analyze ./docs/ --dry-run
|
|
327
|
+
|
|
328
|
+
# Delegate the analysis to Claude Code itself — no API key needed
|
|
329
|
+
dotmd-parser analyze ./docs/ --plan > plan.md
|
|
330
|
+
# 1. Claude Code reads plan.md and executes the task locally
|
|
331
|
+
# 2. It writes the result to analysis.json
|
|
332
|
+
# 3. Apply it:
|
|
333
|
+
dotmd-parser analyze ./docs/ --apply-from analysis.json
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
- Text files (`.md`, `.txt`, etc.) get `@include` lines prepended.
|
|
337
|
+
- Binary sources (`.pdf`, `.docx`) are recorded in `deps.yml` — they can't
|
|
338
|
+
be edited in-place, so the parser reads them from there.
|
|
339
|
+
- PDF / DOCX support is optional: `pip install pdfplumber python-docx`.
|
|
340
|
+
- Re-run with `--apply` over time as the repo grows — existing directives
|
|
341
|
+
are preserved.
|
|
342
|
+
|
|
343
|
+
The bundled prompt lives at
|
|
344
|
+
`src/dotmd_parser/templates/prompts/analyze-dependencies.md` and is shipped
|
|
345
|
+
inside the wheel; no network access is needed except for the Claude API
|
|
346
|
+
call itself.
|
|
347
|
+
|
|
348
|
+
### Programmatic use
|
|
349
|
+
|
|
350
|
+
```python
|
|
351
|
+
from dotmd_parser import analyze_dependencies, apply_analysis
|
|
352
|
+
|
|
353
|
+
proposal = analyze_dependencies("./docs/")
|
|
354
|
+
print(proposal["edges"])
|
|
355
|
+
apply_analysis("./docs/", proposal)
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
For offline tests, pass a `caller=...` kwarg that returns a stub JSON string.
|
|
359
|
+
|
|
360
|
+
## Claude Code Skill integration
|
|
361
|
+
|
|
362
|
+
A ready-to-use Claude Code Skill is bundled with the package at
|
|
363
|
+
`src/dotmd_parser/templates/SKILL.md`. Three install paths:
|
|
364
|
+
|
|
365
|
+
```bash
|
|
366
|
+
# via pip — installs the CLI and drops SKILL.md into the current project
|
|
367
|
+
pip install dotmd-parser
|
|
368
|
+
dotmd-parser init .
|
|
369
|
+
|
|
370
|
+
# via Release archive — no pip required
|
|
371
|
+
mkdir -p .claude/skills
|
|
372
|
+
curl -L https://github.com/dotmd-projects/dotmd-parser/releases/latest/download/skill.tar.gz \
|
|
373
|
+
| tar -xz -C .claude/skills/
|
|
374
|
+
|
|
375
|
+
# manual
|
|
376
|
+
cp src/dotmd_parser/templates/SKILL.md \
|
|
377
|
+
/path/to/project/.claude/skills/dotmd-parser/
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
Once installed, Claude will consult the skill whenever it encounters
|
|
381
|
+
`SKILL.md`, `deps.yml`, a `.claude/skills/` tree, or is asked about
|
|
382
|
+
dependencies of a markdown file.
|
|
383
|
+
|
|
384
|
+
**Why this saves tokens.** Without the skill, Claude typically `grep -r`s
|
|
385
|
+
for `@include`/`@ref` and `cat`s every referenced file to trace a graph.
|
|
386
|
+
With the skill it reads `.claude/dotmd-index.json` (compact, relative paths,
|
|
387
|
+
first-paragraph descriptions) or the `digest` output once, then queries
|
|
388
|
+
`affects` / `deps` by name — never touching the raw markdown until an edit
|
|
389
|
+
is actually needed.
|
|
390
|
+
|
|
391
|
+
### Auto-refresh via Hook (optional)
|
|
392
|
+
|
|
393
|
+
Add to `~/.claude/settings.json` to keep `.claude/dotmd-index.json` fresh
|
|
394
|
+
after every markdown edit:
|
|
395
|
+
|
|
396
|
+
```json
|
|
397
|
+
{
|
|
398
|
+
"hooks": {
|
|
399
|
+
"PostToolUse": [
|
|
400
|
+
{
|
|
401
|
+
"matcher": "Edit|Write",
|
|
402
|
+
"command": "dotmd-parser index \"$CLAUDE_PROJECT_DIR\" >/dev/null 2>&1 || true"
|
|
403
|
+
}
|
|
404
|
+
]
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
The command is idempotent (SHA-256 cache) and exits fast when nothing
|
|
410
|
+
changed.
|
|
411
|
+
|
|
412
|
+
## Development
|
|
413
|
+
|
|
414
|
+
```bash
|
|
415
|
+
git clone https://github.com/dotmd-projects/dotmd-parser.git
|
|
416
|
+
cd dotmd-parser
|
|
417
|
+
pip install -e .
|
|
418
|
+
pip install pytest
|
|
419
|
+
pytest tests/ -v
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## License
|
|
423
|
+
|
|
424
|
+
MIT
|