mdbind 0.1.1__tar.gz → 0.1.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.
Files changed (34) hide show
  1. mdbind-0.1.2/PKG-INFO +227 -0
  2. {mdbind-0.1.1 → mdbind-0.1.2}/pyproject.toml +8 -1
  3. {mdbind-0.1.1 → mdbind-0.1.2}/src/mdbind/cli.py +37 -37
  4. mdbind-0.1.2/src/mdbind.egg-info/PKG-INFO +227 -0
  5. mdbind-0.1.1/PKG-INFO +0 -9
  6. mdbind-0.1.1/src/mdbind.egg-info/PKG-INFO +0 -9
  7. {mdbind-0.1.1 → mdbind-0.1.2}/README.md +0 -0
  8. {mdbind-0.1.1 → mdbind-0.1.2}/setup.cfg +0 -0
  9. {mdbind-0.1.1 → mdbind-0.1.2}/src/mdbind/__init__.py +0 -0
  10. {mdbind-0.1.1 → mdbind-0.1.2}/src/mdbind/cache.py +0 -0
  11. {mdbind-0.1.1 → mdbind-0.1.2}/src/mdbind/composer.py +0 -0
  12. {mdbind-0.1.1 → mdbind-0.1.2}/src/mdbind/cycle.py +0 -0
  13. {mdbind-0.1.1 → mdbind-0.1.2}/src/mdbind/directives.py +0 -0
  14. {mdbind-0.1.1 → mdbind-0.1.2}/src/mdbind/index.py +0 -0
  15. {mdbind-0.1.1 → mdbind-0.1.2}/src/mdbind/models.py +0 -0
  16. {mdbind-0.1.1 → mdbind-0.1.2}/src/mdbind/parser.py +0 -0
  17. {mdbind-0.1.1 → mdbind-0.1.2}/src/mdbind.egg-info/SOURCES.txt +0 -0
  18. {mdbind-0.1.1 → mdbind-0.1.2}/src/mdbind.egg-info/dependency_links.txt +0 -0
  19. {mdbind-0.1.1 → mdbind-0.1.2}/src/mdbind.egg-info/entry_points.txt +0 -0
  20. {mdbind-0.1.1 → mdbind-0.1.2}/src/mdbind.egg-info/requires.txt +0 -0
  21. {mdbind-0.1.1 → mdbind-0.1.2}/src/mdbind.egg-info/top_level.txt +0 -0
  22. {mdbind-0.1.1 → mdbind-0.1.2}/tests/test_cache.py +0 -0
  23. {mdbind-0.1.1 → mdbind-0.1.2}/tests/test_cli_compose.py +0 -0
  24. {mdbind-0.1.1 → mdbind-0.1.2}/tests/test_cli_get.py +0 -0
  25. {mdbind-0.1.1 → mdbind-0.1.2}/tests/test_cli_ia_v1.py +0 -0
  26. {mdbind-0.1.1 → mdbind-0.1.2}/tests/test_cli_ia_v2.py +0 -0
  27. {mdbind-0.1.1 → mdbind-0.1.2}/tests/test_cli_tree.py +0 -0
  28. {mdbind-0.1.1 → mdbind-0.1.2}/tests/test_cli_validate.py +0 -0
  29. {mdbind-0.1.1 → mdbind-0.1.2}/tests/test_cycle_detection.py +0 -0
  30. {mdbind-0.1.1 → mdbind-0.1.2}/tests/test_directives.py +0 -0
  31. {mdbind-0.1.1 → mdbind-0.1.2}/tests/test_examples.py +0 -0
  32. {mdbind-0.1.1 → mdbind-0.1.2}/tests/test_index.py +0 -0
  33. {mdbind-0.1.1 → mdbind-0.1.2}/tests/test_models.py +0 -0
  34. {mdbind-0.1.1 → mdbind-0.1.2}/tests/test_parser.py +0 -0
mdbind-0.1.2/PKG-INFO ADDED
@@ -0,0 +1,227 @@
1
+ Metadata-Version: 2.4
2
+ Name: mdbind
3
+ Version: 0.1.2
4
+ Summary: MdBind — Structured memory in plain Markdown
5
+ Project-URL: Homepage, https://github.com/seu-usuario/mdbind
6
+ Project-URL: Repository, https://github.com/seu-usuario/mdbind
7
+ Project-URL: Bug Tracker, https://github.com/seu-usuario/mdbind/issues
8
+ Project-URL: Documentation, https://github.com/seu-usuario/mdbind#readme
9
+ Requires-Python: >=3.11
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: pydantic>=2.0
12
+ Requires-Dist: markdown-it-py>=3.0
13
+ Requires-Dist: typer>=0.12
14
+ Requires-Dist: pyyaml>=6.0
15
+
16
+ <div align="center">
17
+
18
+ # MdBind
19
+
20
+ **Structured memory in plain Markdown.**
21
+
22
+ Transform your Markdown files into a navigable knowledge graph —
23
+ without databases, embeddings, or proprietary formats.
24
+
25
+ [![Python](https://img.shields.io/badge/python-3.11%2B-blue?logo=python&logoColor=white)](https://www.python.org/)
26
+ [![Tests](https://img.shields.io/badge/tests-209%20passing-brightgreen?logo=pytest&logoColor=white)](#development)
27
+ [![Version](https://img.shields.io/badge/version-0.1.0-informational)](#installation)
28
+ [![License](https://img.shields.io/badge/license-MIT-lightgrey)](#license)
29
+
30
+ </div>
31
+
32
+ ---
33
+
34
+ ## What is MdBind?
35
+
36
+ MdBind turns Markdown files into a **directed knowledge graph** where every section is an addressable node with stable identity, metadata, and explicit relationships.
37
+
38
+ Your files stay **plain text, Git-friendly, and human-readable** — but gain:
39
+
40
+ - Graph traversal and dependency resolution
41
+ - Stable URIs that survive reorganization
42
+ - Structured metadata queries
43
+ - AI-oriented context retrieval with bounded token consumption
44
+
45
+ ---
46
+
47
+ ## Why not embeddings?
48
+
49
+ | Approach | Inspectable | Versionable | Deterministic | Human-readable |
50
+ |---|:---:|:---:|:---:|:---:|
51
+ | Vector databases | ✗ | ✗ | ✗ | ✗ |
52
+ | Proprietary stores | ✗ | partial | partial | ✗ |
53
+ | **MdBind** | ✓ | ✓ | ✓ | ✓ |
54
+
55
+ Every node, every edge, every relationship is visible in the source file. What an agent reads, a human can audit.
56
+
57
+ ---
58
+
59
+ ## Quick start
60
+
61
+ ```bash
62
+ # 1. Clone and install
63
+ git clone <repo-url> && cd mdbind
64
+ python3 -m venv .venv && source .venv/bin/activate
65
+ pip install -e .
66
+
67
+ # 2. Point it at your docs
68
+ mdb validate --root docs/
69
+
70
+ # 3. Query the graph
71
+ mdb get docs/auth.md#auth --json
72
+ ```
73
+
74
+ ---
75
+
76
+ ## See it in action
77
+
78
+ ```bash
79
+ # Navigate the dependency tree
80
+ $ mdb tree docs/auth.md#auth --root docs/
81
+
82
+ auth [docs/auth.md]
83
+ ├── jwt [include] docs/security.md#jwt
84
+ └── permissions [ref] docs/users.md#permissions
85
+
86
+ # Compose a unified document by expanding all @include directives
87
+ $ mdb compose docs/auth.md#auth --root docs/ --depth 2
88
+
89
+ # Find everything that depends on a node (reverse BFS)
90
+ $ mdb impact docs/auth.md#auth --root docs/ --json
91
+
92
+ # Boolean metadata query
93
+ $ mdb query "tag:api AND NOT status=obsolete" --root docs/ --json
94
+
95
+ # Bounded context for LLM consumption
96
+ $ mdb context-compose docs/auth.md#auth --root docs/ --depth 2 --token-limit 2000 --json
97
+ ```
98
+
99
+ ---
100
+
101
+ ## Syntax
102
+
103
+ ### Declaring a section
104
+
105
+ A section is a Markdown heading followed immediately by a YAML block with a `section:` field:
106
+
107
+ ````markdown
108
+ ## Authentication
109
+
110
+ ```yaml
111
+ section: auth
112
+ title: Authentication
113
+ type: domain
114
+ owner: security-team
115
+ tags: [auth, core]
116
+ ```
117
+
118
+ Authentication is responsible for user identity.
119
+
120
+ [@include: JWT handling](security.md#jwt)
121
+
122
+ See also: [@ref: permissions model](users.md#permissions)
123
+ ````
124
+
125
+ - The YAML block must be the **first element** after the heading
126
+ - `section:` is mandatory and must be **unique per repository**
127
+ - Any additional fields are preserved as queryable metadata
128
+
129
+ ### Directives (graph edges)
130
+
131
+ ```markdown
132
+ [@include: label](path/to/file.md#section-id) <!-- expands inline during compose -->
133
+ [@ref: label](path/to/file.md#section-id) <!-- records dependency, no expansion -->
134
+ ```
135
+
136
+ Directives are standard Markdown links — they render correctly in any Markdown viewer.
137
+
138
+ ```
139
+ auth
140
+ ├── jwt [include]
141
+ └── permissions [ref]
142
+ ```
143
+
144
+ ---
145
+
146
+ ## Commands
147
+
148
+ ### Quick reference
149
+
150
+ | Command | Description |
151
+ |---|---|
152
+ | `mdb get <URI>` | Extract a section with full documentary fidelity |
153
+ | `mdb tree <URI>` | Visual dependency hierarchy |
154
+ | `mdb compose <URI>` | Materialize a unified document (expands `@include`) |
155
+ | `mdb validate` | Check integrity: broken refs, cycles, duplicate IDs |
156
+ | `mdb context <URI>` | Metadata + immediate 1-hop neighborhood |
157
+ | `mdb backlinks <URI>` | All sections that reference this URI |
158
+ | `mdb search <predicate>` | Search sections by metadata |
159
+ | `mdb impact <URI>` | All nodes that depend on this URI (reverse BFS) |
160
+ | `mdb neighbors <URI>` | All nodes reachable within N hops |
161
+ | `mdb explain <URI_A> <URI_B>` | All directed paths between two nodes |
162
+ | `mdb diff` | Structural graph diff against a git reference |
163
+ | `mdb query <expression>` | Boolean metadata query (`AND`, `OR`, `NOT`) |
164
+ | `mdb context-compose <URI>` | Bounded materialization for LLM consumption |
165
+
166
+ All commands accept `--json` for machine-readable output.
167
+ All outputs are deterministic and JSON-serializable. All URIs are stable across sessions.
168
+
169
+ ### Selected examples
170
+
171
+ ```bash
172
+ # Validate an entire repository
173
+ mdb validate --root docs/ --json
174
+
175
+ # 1-hop neighborhood of a node
176
+ mdb context docs/auth.md#auth --root docs/ --json
177
+
178
+ # Find all sections tagged api that are not obsolete
179
+ mdb query "tag:api AND NOT status=obsolete" --root docs/ --json
180
+
181
+ # Bounded context for LLM — depth 2, max 2000 tokens
182
+ mdb context-compose docs/auth.md#auth --root docs/ --depth 2 --token-limit 2000 --json
183
+
184
+ # What changed structurally since the last commit?
185
+ mdb diff --root docs/ --since HEAD~1 --json
186
+ ```
187
+
188
+ ---
189
+
190
+ ## Philosophy
191
+
192
+ Five principles behind every design decision:
193
+
194
+ 1. **Markdown is the source of truth** — no proprietary formats, no hidden state
195
+ 2. **Knowledge should be inspectable** — every node, every edge, every relationship is visible in the source
196
+ 3. **Relationships should be explicit** — `@include` and `@ref` are first-class graph primitives
197
+ 4. **Stable identifiers are better than headings** — `file.md#id` survives reorganization
198
+ 5. **AI memory should remain human-readable** — what an agent reads, a human can audit
199
+
200
+ ---
201
+
202
+ ## Examples
203
+
204
+ See the [examples/](examples/) directory for a complete working knowledge base demonstrating sections, directives, composition, and graph traversal.
205
+
206
+ ---
207
+
208
+ ## Development
209
+
210
+ ```bash
211
+ # Install in editable mode
212
+ pip install -e .
213
+
214
+ # Run the full test suite
215
+ python -m pytest
216
+
217
+ # Run a specific module
218
+ python -m pytest tests/test_cli_validate.py -v
219
+ ```
220
+
221
+ > 209 tests, 0 failures.
222
+
223
+ ---
224
+
225
+ ## License
226
+
227
+ MIT
@@ -4,8 +4,9 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "mdbind"
7
- version = "0.1.1"
7
+ version = "0.1.2"
8
8
  description = "MdBind — Structured memory in plain Markdown"
9
+ readme = "README.md"
9
10
  requires-python = ">=3.11"
10
11
  dependencies = [
11
12
  "pydantic>=2.0",
@@ -22,3 +23,9 @@ where = ["src"]
22
23
 
23
24
  [tool.pytest.ini_options]
24
25
  testpaths = ["tests"]
26
+
27
+ [project.urls]
28
+ Homepage = "https://github.com/seu-usuario/mdbind"
29
+ Repository = "https://github.com/seu-usuario/mdbind"
30
+ "Bug Tracker" = "https://github.com/seu-usuario/mdbind/issues"
31
+ Documentation = "https://github.com/seu-usuario/mdbind#readme"
@@ -1,10 +1,10 @@
1
1
  """
2
- CLI do mdgraph — entrypoint principal.
2
+ CLI for mdbindmain entrypoint.
3
3
 
4
- Comandos:
5
- get <URI> Extrai uma secao com fidelidade documental (linhas brutas)
6
- tree <URI> Exibe hierarquia visual de dependencias
7
- compose <URI> Materializa documento unificado (B-007)
4
+ Commands:
5
+ get <URI> Extract a section with documentary fidelity (raw lines)
6
+ tree <URI> Display visual hierarchy of dependencies
7
+ compose <URI> Materialize unified document (B-007)
8
8
  """
9
9
  from __future__ import annotations
10
10
 
@@ -43,23 +43,23 @@ def _split_uri(uri: str) -> tuple[str, str]:
43
43
 
44
44
  @app.command()
45
45
  def get(
46
- uri: str = typer.Argument(..., help="URI da secao no formato arquivo.md#id"),
46
+ uri: str = typer.Argument(..., help="URI of the section in the format file.md#id"),
47
47
  json_output: bool = typer.Option(False, "--json", help="Output as JSON."),
48
48
  ) -> None:
49
49
  """
50
- Extrai uma secao com 100%% de fidelidade documental (linhas brutas do arquivo fonte).
50
+ Extract a section with 100%% documentary fidelity (raw lines from the source file).
51
51
  """
52
52
  file_path_str, section_id = _split_uri(uri)
53
53
  file_path = Path(file_path_str).resolve()
54
54
 
55
55
  if not file_path.exists():
56
- typer.echo(f"Erro: arquivo nao encontrado: '{file_path}'", err=True)
56
+ typer.echo(f"Error: file not found: '{file_path}'", err=True)
57
57
  raise typer.Exit(code=1)
58
58
 
59
59
  try:
60
60
  sections = parse_file(file_path)
61
61
  except ParseError as exc:
62
- typer.echo(f"Erro de parsing: {exc}", err=True)
62
+ typer.echo(f"Parse error: {exc}", err=True)
63
63
  raise typer.Exit(code=1)
64
64
 
65
65
  matched = next(
@@ -69,15 +69,15 @@ def get(
69
69
 
70
70
  if matched is None:
71
71
  typer.echo(
72
- f"Erro: secao '{section_id}' nao encontrada em '{file_path}'",
72
+ f"Error: section '{section_id}' not found in '{file_path}'",
73
73
  err=True,
74
74
  )
75
75
  raise typer.Exit(code=1)
76
76
 
77
- # Fatiamento documental: preserva o texto exato do arquivo fonte
77
+ # Documentary slicing: preserves the exact text from the source file
78
78
  lines = file_path.read_text(encoding="utf-8").splitlines(keepends=True)
79
79
  start = matched.raw.source_start_line - 1 # base-0
80
- end = matched.raw.source_end_line # slice exclusivo = ultima linha inclusiva
80
+ end = matched.raw.source_end_line # exclusive slice = last line inclusive
81
81
 
82
82
  output = "".join(lines[start:end])
83
83
  # Garantir newline final sem adicionar extra
@@ -103,23 +103,23 @@ def get(
103
103
 
104
104
  @app.command()
105
105
  def tree(
106
- uri: str = typer.Argument(..., help="URI da secao no formato arquivo.md#id"),
106
+ uri: str = typer.Argument(..., help="URI of the section in the format file.md#id"),
107
107
  root: Optional[Path] = typer.Option(
108
108
  None, "--root", "-r",
109
- help="Diretorio raiz do repositorio (padrao: diretorio do arquivo).",
109
+ help="Root directory of the repository (default: directory of the file).",
110
110
  ),
111
111
  refs: bool = typer.Option(
112
112
  False, "--refs",
113
- help="Exibir backlinks (quem depende desta secao).",
113
+ help="Display backlinks (who depends on this section).",
114
114
  ),
115
115
  depth: Optional[int] = typer.Option(
116
116
  None, "--depth", "-d",
117
- help="Profundidade maxima da arvore (padrao: ilimitada).",
117
+ help="Maximum depth of the tree (default: unlimited).",
118
118
  ),
119
119
  json_output: bool = typer.Option(False, "--json", help="Output as JSON."),
120
120
  ) -> None:
121
121
  """
122
- Exibe a hierarquia visual de dependencias de uma secao.
122
+ Display the visual hierarchy of dependencies of a section.
123
123
  """
124
124
  from mdbind.index import index_repository
125
125
 
@@ -131,14 +131,14 @@ def tree(
131
131
  try:
132
132
  graph = index_repository(repo_root)
133
133
  except ParseError as exc:
134
- typer.echo(f"Erro de parsing: {exc}", err=True)
134
+ typer.echo(f"Parse error: {exc}", err=True)
135
135
  raise typer.Exit(code=1)
136
136
 
137
- # Montar URI absoluta para lookup
137
+ # Build absolute URI for lookup
138
138
  abs_uri = str(file_path) + "#" + section_id
139
139
 
140
140
  if abs_uri not in graph.index.sections:
141
- typer.echo(f"Erro: URI '{abs_uri}' nao encontrada no indice.", err=True)
141
+ typer.echo(f"Error: URI '{abs_uri}' not found in the index.", err=True)
142
142
  raise typer.Exit(code=1)
143
143
 
144
144
  if json_output:
@@ -160,7 +160,7 @@ def _label(uri: str, graph) -> str:
160
160
 
161
161
 
162
162
  def _print_tree_outgoing(uri: str, graph, prefix: str, visited: set, depth: Optional[int] = None) -> None:
163
- marker = "(ciclo)" if uri in visited else ""
163
+ marker = "(cycle)" if uri in visited else ""
164
164
  typer.echo(f"{prefix}{_label(uri, graph)} {marker}".rstrip())
165
165
  if uri in visited:
166
166
  return
@@ -175,7 +175,7 @@ def _print_tree_outgoing(uri: str, graph, prefix: str, visited: set, depth: Opti
175
175
 
176
176
 
177
177
  def _print_tree_incoming(uri: str, graph, prefix: str, visited: set, depth: Optional[int] = None) -> None:
178
- marker = "(ciclo)" if uri in visited else ""
178
+ marker = "(cycle)" if uri in visited else ""
179
179
  typer.echo(f"{prefix}{_label(uri, graph)} {marker}".rstrip())
180
180
  if uri in visited:
181
181
  return
@@ -233,21 +233,21 @@ def _build_tree_incoming(uri: str, graph, visited: set, depth: Optional[int] = N
233
233
 
234
234
  @app.command()
235
235
  def compose(
236
- uri: str = typer.Argument(..., help="URI da secao raiz no formato arquivo.md#id"),
236
+ uri: str = typer.Argument(..., help="URI of the root section in the format file.md#id"),
237
237
  root: Optional[Path] = typer.Option(
238
238
  None, "--root", "-r",
239
- help="Diretorio raiz do repositorio (padrao: diretorio do arquivo).",
239
+ help="Root directory of the repository (default: directory of the file).",
240
240
  ),
241
- strict: bool = typer.Option(False, "--strict", help="Abortar em URI nao resolvida."),
242
- deduplicate: bool = typer.Option(False, "--deduplicate", help="Deduplicar nos repetidos."),
243
- json_output: bool = typer.Option(False, "--json", help="Exportar como JSON estruturado."),
241
+ strict: bool = typer.Option(False, "--strict", help="Abort on unresolved URI."),
242
+ deduplicate: bool = typer.Option(False, "--deduplicate", help="Deduplicate repeated nodes."),
243
+ json_output: bool = typer.Option(False, "--json", help="Export as structured JSON."),
244
244
  depth: Optional[int] = typer.Option(
245
245
  None, "--depth", "-d",
246
- help="Profundidade maxima de expansao de @include (padrao: ilimitada).",
246
+ help="Maximum depth of @include expansion (default: unlimited).",
247
247
  ),
248
248
  ) -> None:
249
249
  """
250
- Materializa um documento Markdown unificado expandindo @include recursivamente.
250
+ Materializes a unified Markdown document by recursively expanding @include.
251
251
  """
252
252
  import json as json_mod
253
253
  from mdbind.composer import compose as do_compose
@@ -257,7 +257,7 @@ def compose(
257
257
  file_path = Path(file_path_str).resolve()
258
258
 
259
259
  if not file_path.exists():
260
- typer.echo(f"Erro: arquivo nao encontrado: '{file_path}'", err=True)
260
+ typer.echo(f"Error: file not found: '{file_path}'", err=True)
261
261
  raise typer.Exit(code=1)
262
262
 
263
263
  repo_root = root.resolve() if root else file_path.parent
@@ -265,13 +265,13 @@ def compose(
265
265
  try:
266
266
  graph = index_repository(repo_root)
267
267
  except ParseError as exc:
268
- typer.echo(f"Erro de parsing: {exc}", err=True)
268
+ typer.echo(f"Parse error: {exc}", err=True)
269
269
  raise typer.Exit(code=1)
270
270
 
271
271
  abs_uri = str(file_path) + "#" + section_id
272
272
 
273
273
  if abs_uri not in graph.index.sections:
274
- typer.echo(f"Erro: URI '{abs_uri}' nao encontrada no indice.", err=True)
274
+ typer.echo(f"Error: URI '{abs_uri}' not found in the index.", err=True)
275
275
  raise typer.Exit(code=1)
276
276
 
277
277
  collected_warnings: list[str] = []
@@ -285,11 +285,11 @@ def compose(
285
285
  depth=depth,
286
286
  )
287
287
  except ValueError as exc:
288
- typer.echo(f"Erro: {exc}", err=True)
288
+ typer.echo(f"Error: {exc}", err=True)
289
289
  raise typer.Exit(code=1)
290
290
 
291
291
  for w in collected_warnings:
292
- typer.echo(f"Aviso: {w}", err=True)
292
+ typer.echo(f"Warning: {w}", err=True)
293
293
 
294
294
  if json_output:
295
295
  typer.echo(json_mod.dumps({"uri": abs_uri, "content": result}, ensure_ascii=False))
@@ -305,12 +305,12 @@ def compose(
305
305
  def validate(
306
306
  root: Optional[Path] = typer.Option(
307
307
  None, "--root", "-r",
308
- help="Diretorio raiz do repositorio (padrao: diretorio atual).",
308
+ help="Root directory of the repository (default: current directory).",
309
309
  ),
310
- json_output: bool = typer.Option(False, "--json", help="Exportar resultado como JSON."),
310
+ json_output: bool = typer.Option(False, "--json", help="Export result as JSON."),
311
311
  ) -> None:
312
312
  """
313
- Verifica a integridade estrutural do repositorio de grafos Markdown.
313
+ Verifies the structural integrity of the Markdown graph repository.
314
314
 
315
315
  Checks: broken refs/includes, duplicate section IDs, include cycles,
316
316
  sections without required payload.
@@ -0,0 +1,227 @@
1
+ Metadata-Version: 2.4
2
+ Name: mdbind
3
+ Version: 0.1.2
4
+ Summary: MdBind — Structured memory in plain Markdown
5
+ Project-URL: Homepage, https://github.com/seu-usuario/mdbind
6
+ Project-URL: Repository, https://github.com/seu-usuario/mdbind
7
+ Project-URL: Bug Tracker, https://github.com/seu-usuario/mdbind/issues
8
+ Project-URL: Documentation, https://github.com/seu-usuario/mdbind#readme
9
+ Requires-Python: >=3.11
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: pydantic>=2.0
12
+ Requires-Dist: markdown-it-py>=3.0
13
+ Requires-Dist: typer>=0.12
14
+ Requires-Dist: pyyaml>=6.0
15
+
16
+ <div align="center">
17
+
18
+ # MdBind
19
+
20
+ **Structured memory in plain Markdown.**
21
+
22
+ Transform your Markdown files into a navigable knowledge graph —
23
+ without databases, embeddings, or proprietary formats.
24
+
25
+ [![Python](https://img.shields.io/badge/python-3.11%2B-blue?logo=python&logoColor=white)](https://www.python.org/)
26
+ [![Tests](https://img.shields.io/badge/tests-209%20passing-brightgreen?logo=pytest&logoColor=white)](#development)
27
+ [![Version](https://img.shields.io/badge/version-0.1.0-informational)](#installation)
28
+ [![License](https://img.shields.io/badge/license-MIT-lightgrey)](#license)
29
+
30
+ </div>
31
+
32
+ ---
33
+
34
+ ## What is MdBind?
35
+
36
+ MdBind turns Markdown files into a **directed knowledge graph** where every section is an addressable node with stable identity, metadata, and explicit relationships.
37
+
38
+ Your files stay **plain text, Git-friendly, and human-readable** — but gain:
39
+
40
+ - Graph traversal and dependency resolution
41
+ - Stable URIs that survive reorganization
42
+ - Structured metadata queries
43
+ - AI-oriented context retrieval with bounded token consumption
44
+
45
+ ---
46
+
47
+ ## Why not embeddings?
48
+
49
+ | Approach | Inspectable | Versionable | Deterministic | Human-readable |
50
+ |---|:---:|:---:|:---:|:---:|
51
+ | Vector databases | ✗ | ✗ | ✗ | ✗ |
52
+ | Proprietary stores | ✗ | partial | partial | ✗ |
53
+ | **MdBind** | ✓ | ✓ | ✓ | ✓ |
54
+
55
+ Every node, every edge, every relationship is visible in the source file. What an agent reads, a human can audit.
56
+
57
+ ---
58
+
59
+ ## Quick start
60
+
61
+ ```bash
62
+ # 1. Clone and install
63
+ git clone <repo-url> && cd mdbind
64
+ python3 -m venv .venv && source .venv/bin/activate
65
+ pip install -e .
66
+
67
+ # 2. Point it at your docs
68
+ mdb validate --root docs/
69
+
70
+ # 3. Query the graph
71
+ mdb get docs/auth.md#auth --json
72
+ ```
73
+
74
+ ---
75
+
76
+ ## See it in action
77
+
78
+ ```bash
79
+ # Navigate the dependency tree
80
+ $ mdb tree docs/auth.md#auth --root docs/
81
+
82
+ auth [docs/auth.md]
83
+ ├── jwt [include] docs/security.md#jwt
84
+ └── permissions [ref] docs/users.md#permissions
85
+
86
+ # Compose a unified document by expanding all @include directives
87
+ $ mdb compose docs/auth.md#auth --root docs/ --depth 2
88
+
89
+ # Find everything that depends on a node (reverse BFS)
90
+ $ mdb impact docs/auth.md#auth --root docs/ --json
91
+
92
+ # Boolean metadata query
93
+ $ mdb query "tag:api AND NOT status=obsolete" --root docs/ --json
94
+
95
+ # Bounded context for LLM consumption
96
+ $ mdb context-compose docs/auth.md#auth --root docs/ --depth 2 --token-limit 2000 --json
97
+ ```
98
+
99
+ ---
100
+
101
+ ## Syntax
102
+
103
+ ### Declaring a section
104
+
105
+ A section is a Markdown heading followed immediately by a YAML block with a `section:` field:
106
+
107
+ ````markdown
108
+ ## Authentication
109
+
110
+ ```yaml
111
+ section: auth
112
+ title: Authentication
113
+ type: domain
114
+ owner: security-team
115
+ tags: [auth, core]
116
+ ```
117
+
118
+ Authentication is responsible for user identity.
119
+
120
+ [@include: JWT handling](security.md#jwt)
121
+
122
+ See also: [@ref: permissions model](users.md#permissions)
123
+ ````
124
+
125
+ - The YAML block must be the **first element** after the heading
126
+ - `section:` is mandatory and must be **unique per repository**
127
+ - Any additional fields are preserved as queryable metadata
128
+
129
+ ### Directives (graph edges)
130
+
131
+ ```markdown
132
+ [@include: label](path/to/file.md#section-id) <!-- expands inline during compose -->
133
+ [@ref: label](path/to/file.md#section-id) <!-- records dependency, no expansion -->
134
+ ```
135
+
136
+ Directives are standard Markdown links — they render correctly in any Markdown viewer.
137
+
138
+ ```
139
+ auth
140
+ ├── jwt [include]
141
+ └── permissions [ref]
142
+ ```
143
+
144
+ ---
145
+
146
+ ## Commands
147
+
148
+ ### Quick reference
149
+
150
+ | Command | Description |
151
+ |---|---|
152
+ | `mdb get <URI>` | Extract a section with full documentary fidelity |
153
+ | `mdb tree <URI>` | Visual dependency hierarchy |
154
+ | `mdb compose <URI>` | Materialize a unified document (expands `@include`) |
155
+ | `mdb validate` | Check integrity: broken refs, cycles, duplicate IDs |
156
+ | `mdb context <URI>` | Metadata + immediate 1-hop neighborhood |
157
+ | `mdb backlinks <URI>` | All sections that reference this URI |
158
+ | `mdb search <predicate>` | Search sections by metadata |
159
+ | `mdb impact <URI>` | All nodes that depend on this URI (reverse BFS) |
160
+ | `mdb neighbors <URI>` | All nodes reachable within N hops |
161
+ | `mdb explain <URI_A> <URI_B>` | All directed paths between two nodes |
162
+ | `mdb diff` | Structural graph diff against a git reference |
163
+ | `mdb query <expression>` | Boolean metadata query (`AND`, `OR`, `NOT`) |
164
+ | `mdb context-compose <URI>` | Bounded materialization for LLM consumption |
165
+
166
+ All commands accept `--json` for machine-readable output.
167
+ All outputs are deterministic and JSON-serializable. All URIs are stable across sessions.
168
+
169
+ ### Selected examples
170
+
171
+ ```bash
172
+ # Validate an entire repository
173
+ mdb validate --root docs/ --json
174
+
175
+ # 1-hop neighborhood of a node
176
+ mdb context docs/auth.md#auth --root docs/ --json
177
+
178
+ # Find all sections tagged api that are not obsolete
179
+ mdb query "tag:api AND NOT status=obsolete" --root docs/ --json
180
+
181
+ # Bounded context for LLM — depth 2, max 2000 tokens
182
+ mdb context-compose docs/auth.md#auth --root docs/ --depth 2 --token-limit 2000 --json
183
+
184
+ # What changed structurally since the last commit?
185
+ mdb diff --root docs/ --since HEAD~1 --json
186
+ ```
187
+
188
+ ---
189
+
190
+ ## Philosophy
191
+
192
+ Five principles behind every design decision:
193
+
194
+ 1. **Markdown is the source of truth** — no proprietary formats, no hidden state
195
+ 2. **Knowledge should be inspectable** — every node, every edge, every relationship is visible in the source
196
+ 3. **Relationships should be explicit** — `@include` and `@ref` are first-class graph primitives
197
+ 4. **Stable identifiers are better than headings** — `file.md#id` survives reorganization
198
+ 5. **AI memory should remain human-readable** — what an agent reads, a human can audit
199
+
200
+ ---
201
+
202
+ ## Examples
203
+
204
+ See the [examples/](examples/) directory for a complete working knowledge base demonstrating sections, directives, composition, and graph traversal.
205
+
206
+ ---
207
+
208
+ ## Development
209
+
210
+ ```bash
211
+ # Install in editable mode
212
+ pip install -e .
213
+
214
+ # Run the full test suite
215
+ python -m pytest
216
+
217
+ # Run a specific module
218
+ python -m pytest tests/test_cli_validate.py -v
219
+ ```
220
+
221
+ > 209 tests, 0 failures.
222
+
223
+ ---
224
+
225
+ ## License
226
+
227
+ MIT
mdbind-0.1.1/PKG-INFO DELETED
@@ -1,9 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: mdbind
3
- Version: 0.1.1
4
- Summary: MdBind — Structured memory in plain Markdown
5
- Requires-Python: >=3.11
6
- Requires-Dist: pydantic>=2.0
7
- Requires-Dist: markdown-it-py>=3.0
8
- Requires-Dist: typer>=0.12
9
- Requires-Dist: pyyaml>=6.0
@@ -1,9 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: mdbind
3
- Version: 0.1.1
4
- Summary: MdBind — Structured memory in plain Markdown
5
- Requires-Python: >=3.11
6
- Requires-Dist: pydantic>=2.0
7
- Requires-Dist: markdown-it-py>=3.0
8
- Requires-Dist: typer>=0.12
9
- Requires-Dist: pyyaml>=6.0
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes