logseq-matryca-parser 1.2.2__tar.gz → 1.3.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 (93) hide show
  1. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/CHANGELOG.md +14 -0
  2. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/CONTRIBUTING.md +1 -1
  3. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/PKG-INFO +46 -9
  4. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/README.md +45 -8
  5. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/SECURITY.md +1 -1
  6. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/ARCHITECTURE.md +16 -8
  7. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/CODEQL.md +1 -1
  8. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/logseq_ast_primer.md +1 -1
  9. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_INCREMENTAL_WATCHER.md +2 -0
  10. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_UUID_AND_GRAPH_SUPERPOWERS.md +2 -0
  11. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/examples/run_demo.py +3 -2
  12. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/legacy/local_digestor.py +6 -9
  13. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/pyproject.toml +22 -1
  14. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/__init__.py +26 -5
  15. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/forge.py +1 -4
  16. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/graph.py +100 -18
  17. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/kinetic.py +104 -57
  18. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/lens.py +9 -6
  19. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/logos_core.py +5 -5
  20. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/logos_parser.py +37 -8
  21. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/logseq_paths.py +17 -0
  22. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/synapse.py +134 -45
  23. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_agent_writer.py +5 -1
  24. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_graph.py +65 -1
  25. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_kinetic.py +27 -0
  26. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_lens.py +9 -1
  27. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_logos_parser.py +34 -9
  28. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_logseq_paths.py +2 -2
  29. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_package_version.py +17 -0
  30. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_synapse.py +70 -6
  31. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/uv.lock +96 -80
  32. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.cursorignore +0 -0
  33. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/CODEOWNERS +0 -0
  34. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/FUNDING.yml +0 -0
  35. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  36. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  37. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  38. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  39. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/dependabot.yml +0 -0
  40. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/workflows/ci.yml +0 -0
  41. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/workflows/daily-metrics.yml +0 -0
  42. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/workflows/github_release.yml +0 -0
  43. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.github/workflows/pypi_publish.yml +0 -0
  44. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.gitignore +0 -0
  45. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.pre-commit-config.yaml +0 -0
  46. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/.repomixignore +0 -0
  47. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/CODE_OF_CONDUCT.md +0 -0
  48. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/LICENSE +0 -0
  49. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/Makefile +0 -0
  50. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/NOTICE +0 -0
  51. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/claude-skill-logseq-read/SKILL.md +0 -0
  52. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/claude-skill-logseq-read/scripts/parse_logseq.py +0 -0
  53. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/RELEASE_PROCESS.md +0 -0
  54. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/design-docs/ARCHITECTURE_BLUEPRINT.md +0 -0
  55. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/design-docs/CODE_SCAFFOLD.md +0 -0
  56. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/design-docs/LOGSEQ_ASSET_RESOLUTION_SPEC.md +0 -0
  57. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/design-docs/LOGSEQ_DATASCRIPT_MAPPING.md +0 -0
  58. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/design-docs/LOGSEQ_TEMPORAL_ONTOLOGY.md +0 -0
  59. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/design-docs/OFFICIAL_MLDOC_SPECS.md +0 -0
  60. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/design-docs/REFERENCE_SPEC.md +0 -0
  61. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/error_log.md +0 -0
  62. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_AGENT_NATIVE_XRAY.md +0 -0
  63. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_CLI_HYDRATION_AND_ENRICHMENT.md +0 -0
  64. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_CONTEXT_SYNTHESIS_AND_SCOPING.md +0 -0
  65. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_EMBED_EXPANSION_AND_FLUENT_QUERIES.md +0 -0
  66. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_GRAPH_RAG_SEMANTICS.md +0 -0
  67. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_HEADLESS_WRITER.md +0 -0
  68. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_INLINE_SHIELD_AND_NAMESPACES.md +0 -0
  69. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_OBSIDIAN_ADAPTER.md +0 -0
  70. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_ROBUSTNESS_AND_SOFT_BREAKS.md +0 -0
  71. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/docs/roadmaps/ROADMAP_TOML_FIX_AND_PYPI_DISTRIBUTION.md +0 -0
  72. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/examples/demo_logseq_journal.md +0 -0
  73. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/lib/bindings/utils.js +0 -0
  74. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/lib/tom-select/tom-select.complete.min.js +0 -0
  75. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/lib/tom-select/tom-select.css +0 -0
  76. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/lib/vis-9.1.2/vis-network.css +0 -0
  77. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/lib/vis-9.1.2/vis-network.min.js +0 -0
  78. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/metrics/history.json +0 -0
  79. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/repomix-output-parser.xml +0 -0
  80. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/scripts/debug_pre_release.py +0 -0
  81. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/scripts/extract_changelog.py +0 -0
  82. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/.gitignore +0 -0
  83. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/NOTICE +0 -0
  84. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/__main__.py +0 -0
  85. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/agent_press.py +0 -0
  86. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/agent_writer.py +0 -0
  87. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/exceptions.py +0 -0
  88. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/logseq_markdown.py +0 -0
  89. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/src/logseq_matryca_parser/pyproject.toml +0 -0
  90. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_agent_press.py +0 -0
  91. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_forge.py +0 -0
  92. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_logseq_markdown.py +0 -0
  93. {logseq_matryca_parser-1.2.2 → logseq_matryca_parser-1.3.0}/tests/test_pre_release_roundtrip.py +0 -0
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.3.0] - 2026-06-19
11
+
12
+ ### Changed
13
+
14
+ - **Sprint 1 architectural quick wins** — **`discover_graph_files`** moved from `kinetic.py` to `logseq_paths.py` (decouples CLI from `LogseqGraph`); KINETIC optional-dependency errors now recommend **`uv sync --extra ai|viz`**; **`lens.py`** lazy-imports NetworkX/PyVis; **SYNAPSE** exports vector-store-safe metadata via **`SynapseMetadata`** / **`build_synapse_metadata`** (`task_priority`, temporal epochs, `source_uuid`, joined `path`/`refs`); explicit **`[tool.ruff]`** config in `pyproject.toml`.
15
+ - **Sprint 2 runtime robustness** — **`LogseqGraphWatcher`** debounces filesystem events (~500ms) and ignores editor temp/swap files; **`StackMachineParser(strict_refs=True)`** raises **`BlockReferenceError`** for unresolved same-page `((uuid))` refs (default off); **KINETIC** adds **`@app.callback()`** with **`--verbose`** / **`--graph`**, **`rich_markup_mode="rich"`**, and shared graph-path resolution.
16
+ - **Sprint 3 architecture** — **`LogseqGraph`** uses **`validate_assignment=True`** (no frozen/`object.__setattr__` hack); **SYNAPSE** **`LlamaIndexVisitor`** adds **`SOURCE`**, **`NEXT`**, and **`PREVIOUS`** relationships; package root **`__init__.py`** exports **`SynapseAdapter`**, **`SessionAliasRegistry`**, **`GraphVisualizer`**, and core LOGOS symbols via explicit **`__all__`**.
17
+ - **Optional AI stack** — `llama-index-core` bumped to `0.14.22` via lock refresh.
18
+ - **Documentation** — README, ARCHITECTURE, CONTRIBUTING, SECURITY, CODEQL, AST primer, and roadmaps updated for **1.3.0** (public API, watcher debounce, `strict_refs`, LlamaIndex spatial edges, `uv` install).
19
+
20
+ ### Security
21
+
22
+ - **Transitive dependency hardening** — `uv` constraints pin `aiohttp>=3.14.1` (11 Dependabot alerts); `nltk` overridden to `v3.10.0-rc1` from upstream Git until NLTK 3.10.0 ships on PyPI (GHSA-p4gq-832x-fm9v). Affects optional `[ai]` / `[all]` extras only; core install unchanged.
23
+
10
24
  ## [1.2.2] - 2026-06-18
11
25
 
12
26
  ### Fixed
@@ -15,7 +15,7 @@ User-facing behavior is documented in:
15
15
  - [`README.md`](README.md) — overview, quickstart, and feature matrix
16
16
  - [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) — LOGOS, SYNAPSE, `LogseqGraph`, agents, and data flow
17
17
  - [`docs/logseq_ast_primer.md`](docs/logseq_ast_primer.md) — Logseq Spatial Markdown domain rules
18
- - [`CHANGELOG.md`](CHANGELOG.md) — shipped releases (current: **1.2.2**) and **Unreleased** changes (Keep a Changelog)
18
+ - [`CHANGELOG.md`](CHANGELOG.md) — shipped releases (current: **1.3.0**) and **Unreleased** changes (Keep a Changelog)
19
19
  - [`docs/RELEASE_PROCESS.md`](docs/RELEASE_PROCESS.md) — version bump, tag, and PyPI publish checklist
20
20
  - [`docs/CODEQL.md`](docs/CODEQL.md) — CodeQL default setup (no custom `codeql.yml`)
21
21
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: logseq-matryca-parser
3
- Version: 1.2.2
3
+ Version: 1.3.0
4
4
  Summary: The Logos Protocol: Deterministic Logseq AST parsing for Matryca.ai.
5
5
  Project-URL: Homepage, https://github.com/MarcoPorcellato/logseq-matryca-parser
6
6
  Project-URL: Repository, https://github.com/MarcoPorcellato/logseq-matryca-parser
@@ -53,7 +53,7 @@ Description-Content-Type: text/markdown
53
53
  [![Status: Stable](https://img.shields.io/badge/Status-Stable-22c55e.svg?style=flat-square)](#)
54
54
  ![Origin: Matryca.ai](https://img.shields.io/badge/Origin-Matryca.ai-gold?style=for-the-badge)
55
55
 
56
- **v1.2.2** — CodeQL CI fix & docs (see [CHANGELOG](CHANGELOG.md)) — **234 tests**, no parser API changes; SAST via GitHub CodeQL **default setup** ([`docs/CODEQL.md`](docs/CODEQL.md)).
56
+ **v1.3.0** — Architecture & runtime hardening (see [CHANGELOG](CHANGELOG.md)) — **244 tests**, public API exports, watcher debounce, `strict_refs`, LlamaIndex spatial edges; SAST via GitHub CodeQL **default setup** ([`docs/CODEQL.md`](docs/CODEQL.md)).
57
57
 
58
58
  > *Turning a forest of local plain-text files into a unified semantic powerhouse.*
59
59
 
@@ -147,6 +147,23 @@ Logseq Matryca Parser is a deterministic **Stack-Machine engine** that acts as t
147
147
 
148
148
  ---
149
149
 
150
+ ## ⚡ Release highlights (v1.3.0)
151
+
152
+ Minor release — architectural quick wins, runtime robustness, and expanded public API. No breaking changes to default parser behavior.
153
+
154
+ | Area | Change |
155
+ | :--- | :--- |
156
+ | **Public API** | Root **`logseq_matryca_parser`** exports **`SynapseAdapter`**, **`SessionAliasRegistry`**, **`GraphVisualizer`**, **`discover_graph_files`**, and core LOGOS symbols via explicit **`__all__`**. |
157
+ | **Graph model** | **`LogseqGraph`** uses **`validate_assignment=True`** instead of frozen/`object.__setattr__` for incremental reloads. |
158
+ | **Live watcher** | **`start_watching()`** debounces filesystem events (~500ms) and ignores editor temp/swap files (`.swp`, `~`, `.tmp`, `.DS_Store`). |
159
+ | **Strict refs** | **`StackMachineParser(strict_refs=True)`** raises **`BlockReferenceError`** for unresolved same-page `((uuid))` refs (default off). |
160
+ | **SYNAPSE** | **`SynapseMetadata`** / **`build_synapse_metadata`** for vector-store-safe fields; **LlamaIndex** adds **`SOURCE`**, **`NEXT`**, **`PREVIOUS`** relationships. |
161
+ | **KINETIC CLI** | Global **`--verbose`** / **`--graph`** via **`@app.callback()`**; optional-dependency hints recommend **`uv sync --extra ai\|viz`**. |
162
+ | **LENS** | Lazy-imports NetworkX/PyVis so core installs stay lightweight. |
163
+ | **Security** | Transitive **`aiohttp`** / **`nltk`** constraints for optional **`[ai]`** extras. |
164
+
165
+ ---
166
+
150
167
  ## ⚡ Release highlights (v1.2.2)
151
168
 
152
169
  Patch release — fixes a failing CodeQL GitHub Actions workflow; **no parser or public API changes**.
@@ -236,7 +253,7 @@ matryca-parse export /path/to/logseq/graph /path/to/obsidian/vault --format obsi
236
253
  > **Note:** Wikilinks currently use the **Logseq page title** (e.g. `[[Target#^…]]`). Vault files may live under namespace folders (`Projects/AI/Demo.md`). Obsidian usually resolves unique titles; aligning link text to folder paths is a possible future refinement.
237
254
 
238
255
  ### Live incremental watcher
239
- `LogseqGraph` supports **surgical file invalidation** (optional dependency: `pip install 'logseq-matryca-parser[watch]'`). `start_watching()` runs a recursive **watchdog** observer: on `created` / `modified` under `pages/` or `journals/`, only that file is re-parsed; stale synthetic UUIDs are purged from `_node_registry` and scrubbed from `_backlink_registry`—no full-graph cold reload.
256
+ `LogseqGraph` supports **surgical file invalidation** (optional dependency: `uv sync --extra watch`). `start_watching()` runs a recursive **watchdog** observer with **~500ms debounce** and ignores editor temp/swap files: on `created` / `modified` under `pages/` or `journals/`, only that file is re-parsed; stale synthetic UUIDs are purged from `_node_registry` and scrubbed from `_backlink_registry`—no full-graph cold reload.
240
257
 
241
258
  ### Fluent topological queries
242
259
  Filter the global node registry with a **chainable** API (tags, task state, ancestry under a parent UUID):
@@ -315,12 +332,17 @@ Marker syntax (`[#A]`, `SCHEDULED: <...>`, `DEADLINE: <...>`) is stripped from `
315
332
  ## 🛠️ Quickstart
316
333
 
317
334
  ```bash
318
- # Install from PyPI (latest: v1.2.2)
319
- pip install logseq-matryca-parser
335
+ # Install from PyPI (latest: v1.3.0)
336
+ uv pip install logseq-matryca-parser
320
337
 
321
338
  # Optional: filesystem watcher for live incremental graph updates
322
- pip install 'logseq-matryca-parser[watch]'
339
+ uv pip install 'logseq-matryca-parser[watch]'
340
+
341
+ # Or clone and sync all extras locally
342
+ uv sync --all-extras
343
+ ```
323
344
 
345
+ ```bash
324
346
  # 1. Visualize your local graph (LENS)
325
347
  matryca-parse visualize /path/to/logseq/graph my-map.html
326
348
 
@@ -332,13 +354,23 @@ matryca-parse export /path/to/logseq/graph output --format langchain-enriched
332
354
 
333
355
  # 4. Obsidian vault (YAML frontmatter + ^ block ids)
334
356
  matryca-parse export /path/to/logseq/graph output --format obsidian
357
+
358
+ # Global options (all subcommands): --verbose, --graph /path/to/vault
359
+ matryca-parse --graph /path/to/logseq/graph --verbose export output --format json
335
360
  ```
336
361
 
337
362
  ### Python API
363
+
364
+ Prefer the package root for stable imports (see **`__all__`** in **`logseq_matryca_parser`**):
365
+
338
366
  ```python
339
- from logseq_matryca_parser.graph import LogseqGraph
340
- from logseq_matryca_parser.logos_parser import LogosParser
341
- from logseq_matryca_parser.synapse import SynapseAdapter
367
+ from logseq_matryca_parser import (
368
+ LogseqGraph,
369
+ LogosParser,
370
+ SynapseAdapter,
371
+ SessionAliasRegistry,
372
+ discover_graph_files,
373
+ )
342
374
 
343
375
  # Parse a single page to AST (YAML or native frontmatter; utf-8-sig BOM-safe)
344
376
  page = LogosParser().parse_page_file("page.md")
@@ -352,6 +384,11 @@ effective = graph.get_effective_properties(page_obj.root_nodes[0].uuid)
352
384
 
353
385
  # Export to LangChain with lineage metadata
354
386
  docs = SynapseAdapter.to_langchain_documents(page.root_nodes, source_name=page.title)
387
+
388
+ # Optional strict same-page block-ref validation at parse time
389
+ from logseq_matryca_parser import StackMachineParser
390
+
391
+ strict_page = StackMachineParser(strict_refs=True).parse_page_file("page.md")
355
392
  ```
356
393
 
357
394
  ### 🤖 Agentic Write Access (Append-Only)
@@ -12,7 +12,7 @@
12
12
  [![Status: Stable](https://img.shields.io/badge/Status-Stable-22c55e.svg?style=flat-square)](#)
13
13
  ![Origin: Matryca.ai](https://img.shields.io/badge/Origin-Matryca.ai-gold?style=for-the-badge)
14
14
 
15
- **v1.2.2** — CodeQL CI fix & docs (see [CHANGELOG](CHANGELOG.md)) — **234 tests**, no parser API changes; SAST via GitHub CodeQL **default setup** ([`docs/CODEQL.md`](docs/CODEQL.md)).
15
+ **v1.3.0** — Architecture & runtime hardening (see [CHANGELOG](CHANGELOG.md)) — **244 tests**, public API exports, watcher debounce, `strict_refs`, LlamaIndex spatial edges; SAST via GitHub CodeQL **default setup** ([`docs/CODEQL.md`](docs/CODEQL.md)).
16
16
 
17
17
  > *Turning a forest of local plain-text files into a unified semantic powerhouse.*
18
18
 
@@ -106,6 +106,23 @@ Logseq Matryca Parser is a deterministic **Stack-Machine engine** that acts as t
106
106
 
107
107
  ---
108
108
 
109
+ ## ⚡ Release highlights (v1.3.0)
110
+
111
+ Minor release — architectural quick wins, runtime robustness, and expanded public API. No breaking changes to default parser behavior.
112
+
113
+ | Area | Change |
114
+ | :--- | :--- |
115
+ | **Public API** | Root **`logseq_matryca_parser`** exports **`SynapseAdapter`**, **`SessionAliasRegistry`**, **`GraphVisualizer`**, **`discover_graph_files`**, and core LOGOS symbols via explicit **`__all__`**. |
116
+ | **Graph model** | **`LogseqGraph`** uses **`validate_assignment=True`** instead of frozen/`object.__setattr__` for incremental reloads. |
117
+ | **Live watcher** | **`start_watching()`** debounces filesystem events (~500ms) and ignores editor temp/swap files (`.swp`, `~`, `.tmp`, `.DS_Store`). |
118
+ | **Strict refs** | **`StackMachineParser(strict_refs=True)`** raises **`BlockReferenceError`** for unresolved same-page `((uuid))` refs (default off). |
119
+ | **SYNAPSE** | **`SynapseMetadata`** / **`build_synapse_metadata`** for vector-store-safe fields; **LlamaIndex** adds **`SOURCE`**, **`NEXT`**, **`PREVIOUS`** relationships. |
120
+ | **KINETIC CLI** | Global **`--verbose`** / **`--graph`** via **`@app.callback()`**; optional-dependency hints recommend **`uv sync --extra ai\|viz`**. |
121
+ | **LENS** | Lazy-imports NetworkX/PyVis so core installs stay lightweight. |
122
+ | **Security** | Transitive **`aiohttp`** / **`nltk`** constraints for optional **`[ai]`** extras. |
123
+
124
+ ---
125
+
109
126
  ## ⚡ Release highlights (v1.2.2)
110
127
 
111
128
  Patch release — fixes a failing CodeQL GitHub Actions workflow; **no parser or public API changes**.
@@ -195,7 +212,7 @@ matryca-parse export /path/to/logseq/graph /path/to/obsidian/vault --format obsi
195
212
  > **Note:** Wikilinks currently use the **Logseq page title** (e.g. `[[Target#^…]]`). Vault files may live under namespace folders (`Projects/AI/Demo.md`). Obsidian usually resolves unique titles; aligning link text to folder paths is a possible future refinement.
196
213
 
197
214
  ### Live incremental watcher
198
- `LogseqGraph` supports **surgical file invalidation** (optional dependency: `pip install 'logseq-matryca-parser[watch]'`). `start_watching()` runs a recursive **watchdog** observer: on `created` / `modified` under `pages/` or `journals/`, only that file is re-parsed; stale synthetic UUIDs are purged from `_node_registry` and scrubbed from `_backlink_registry`—no full-graph cold reload.
215
+ `LogseqGraph` supports **surgical file invalidation** (optional dependency: `uv sync --extra watch`). `start_watching()` runs a recursive **watchdog** observer with **~500ms debounce** and ignores editor temp/swap files: on `created` / `modified` under `pages/` or `journals/`, only that file is re-parsed; stale synthetic UUIDs are purged from `_node_registry` and scrubbed from `_backlink_registry`—no full-graph cold reload.
199
216
 
200
217
  ### Fluent topological queries
201
218
  Filter the global node registry with a **chainable** API (tags, task state, ancestry under a parent UUID):
@@ -274,12 +291,17 @@ Marker syntax (`[#A]`, `SCHEDULED: <...>`, `DEADLINE: <...>`) is stripped from `
274
291
  ## 🛠️ Quickstart
275
292
 
276
293
  ```bash
277
- # Install from PyPI (latest: v1.2.2)
278
- pip install logseq-matryca-parser
294
+ # Install from PyPI (latest: v1.3.0)
295
+ uv pip install logseq-matryca-parser
279
296
 
280
297
  # Optional: filesystem watcher for live incremental graph updates
281
- pip install 'logseq-matryca-parser[watch]'
298
+ uv pip install 'logseq-matryca-parser[watch]'
299
+
300
+ # Or clone and sync all extras locally
301
+ uv sync --all-extras
302
+ ```
282
303
 
304
+ ```bash
283
305
  # 1. Visualize your local graph (LENS)
284
306
  matryca-parse visualize /path/to/logseq/graph my-map.html
285
307
 
@@ -291,13 +313,23 @@ matryca-parse export /path/to/logseq/graph output --format langchain-enriched
291
313
 
292
314
  # 4. Obsidian vault (YAML frontmatter + ^ block ids)
293
315
  matryca-parse export /path/to/logseq/graph output --format obsidian
316
+
317
+ # Global options (all subcommands): --verbose, --graph /path/to/vault
318
+ matryca-parse --graph /path/to/logseq/graph --verbose export output --format json
294
319
  ```
295
320
 
296
321
  ### Python API
322
+
323
+ Prefer the package root for stable imports (see **`__all__`** in **`logseq_matryca_parser`**):
324
+
297
325
  ```python
298
- from logseq_matryca_parser.graph import LogseqGraph
299
- from logseq_matryca_parser.logos_parser import LogosParser
300
- from logseq_matryca_parser.synapse import SynapseAdapter
326
+ from logseq_matryca_parser import (
327
+ LogseqGraph,
328
+ LogosParser,
329
+ SynapseAdapter,
330
+ SessionAliasRegistry,
331
+ discover_graph_files,
332
+ )
301
333
 
302
334
  # Parse a single page to AST (YAML or native frontmatter; utf-8-sig BOM-safe)
303
335
  page = LogosParser().parse_page_file("page.md")
@@ -311,6 +343,11 @@ effective = graph.get_effective_properties(page_obj.root_nodes[0].uuid)
311
343
 
312
344
  # Export to LangChain with lineage metadata
313
345
  docs = SynapseAdapter.to_langchain_documents(page.root_nodes, source_name=page.title)
346
+
347
+ # Optional strict same-page block-ref validation at parse time
348
+ from logseq_matryca_parser import StackMachineParser
349
+
350
+ strict_page = StackMachineParser(strict_refs=True).parse_page_file("page.md")
314
351
  ```
315
352
 
316
353
  ### 🤖 Agentic Write Access (Append-Only)
@@ -6,7 +6,7 @@ Security fixes are provided **only for the latest released version** on [PyPI](h
6
6
 
7
7
  | Version | Supported |
8
8
  | ------- | --------- |
9
- | **1.2.2** (latest) | Yes |
9
+ | **1.3.0** (latest) | Yes |
10
10
  | Older releases | No |
11
11
 
12
12
  We recommend always running the current release and upgrading promptly when a security advisory is published.
@@ -82,7 +82,7 @@ title Logseq Matryca Parser — C4 Level 2 (Containers)
82
82
  Person(knowledgeWorker, "Knowledge Worker", "Local operator of a sovereign Logseq graph.")
83
83
 
84
84
  System_Boundary(matrycaEcosystem, "Matryca.ai Ecosystem") {
85
- Container(kinetic, "KINETIC", "Typer / Rich CLI", "CLI — export (json, markdown, langchain, langchain-enriched, obsidian), visualize, demo, graph scans, `agent-read` / `agent-write` (X-Ray + headless splice), weekly append (`append`).")
85
+ Container(kinetic, "KINETIC", "Typer / Rich CLI", "CLI — global `--verbose` / `--graph` callback; export (json, markdown, langchain, langchain-enriched, obsidian), visualize, demo, graph scans, `agent-read` / `agent-write` (X-Ray + headless splice), weekly append (`append`).")
86
86
  Container(logos, "LOGOS", "Python / Pydantic", "Stack-Machine AST engine — LogseqPage and LogseqNode models.")
87
87
  Container(synapse, "SYNAPSE", "LangChain / LlamaIndex", "Framework-native exporters with parent-child metadata.")
88
88
  Container(lens, "LENS", "NetworkX / PyVis", "Reference-topology visualization to interactive HTML.")
@@ -258,7 +258,9 @@ classDiagram
258
258
 
259
259
  - **LangChain.** [`LangChainVisitor`](../src/logseq_matryca_parser/synapse.py) emits one **`Document`** per node with `page_content=node.clean_text` and metadata unioning **`node.properties`** with lineage fields (`uuid`, `parent_id`, `indent_level`, `source`, **`path`** — the UUID ancestry chain — `left_id`, `refs`, `task_status`, repeater, `created_at`). The underlying **`LogseqNode`** additionally carries **`task_priority`**, **`scheduled_at`**, and **`deadline_at`** (§3.1); adapters or custom visitors can project those into metadata when feeding **downstream graph databases** or **GraphRAG** filters. This preserves **parent context** explicitly in retrieval filters and re-ranking.
260
260
 
261
- - **LlamaIndex.** [`LlamaIndexVisitor`](../src/logseq_matryca_parser/synapse.py) constructs **`TextNode`** instances keyed by **`id_=node.uuid`**. It wires **`NodeRelationship.PARENT`** and **`CHILD`** via **`RelatedNodeInfo`**, back-linking when the parent appears earlier in preorder traversal — encoding **topology as first-class edges** beyond flat metadata dictionaries.
261
+ - **LlamaIndex.** [`LlamaIndexVisitor`](../src/logseq_matryca_parser/synapse.py) constructs **`TextNode`** instances keyed by **`id_=node.uuid`**. It wires **`NodeRelationship.PARENT`** and **`CHILD`** via **`RelatedNodeInfo`**, back-linking when the parent appears earlier in preorder traversal — encoding **topology as first-class edges** beyond flat metadata dictionaries. From **v1.3.0**, it also emits **`SOURCE`** (page-level anchor via **`page_source_node_id`**), **`NEXT`**, and **`PREVIOUS`** sibling edges for spatial traversal in vector stores.
262
+
263
+ - **Vector-store metadata.** **`SynapseMetadata`** and **`build_synapse_metadata`** project **`task_priority`**, temporal epoch fields, **`source_uuid`**, and joined **`path`** / **`refs`** strings into LangChain/LlamaIndex metadata without leaking raw Python list reprs.
262
264
 
263
265
  Together, adapters guarantee that **embedding units align with intentional block boundaries**, not splitter accidents.
264
266
 
@@ -276,7 +278,7 @@ The KINETIC **`export --format langchain-enriched`** path serializes these docum
276
278
 
277
279
  ### 3.3 LENS — NetworkX topology + PyVis interactive visualization
278
280
 
279
- **LENS** (`logseq_matryca_parser.lens.GraphVisualizer`) builds a **`networkx.Graph`** over **page ⇄ wiki/tag reference** projections using `NetworkXVisitor` during AST preorder walks. Nodes receive **degree-based sizing** (“sun” hotspots) and subgroup classification (`page`, `tag`, `journal`, etc.).
281
+ **LENS** (`logseq_matryca_parser.lens.GraphVisualizer`) builds a **`networkx.Graph`** over **page ⇄ wiki/tag reference** projections using `NetworkXVisitor` during AST preorder walks. Nodes receive **degree-based sizing** (“sun” hotspots) and subgroup classification (`page`, `tag`, `journal`, etc.). **NetworkX** and **PyVis** are **lazy-imported** (optional **`[viz]`** extra) so core installs avoid pulling visualization dependencies until `GraphVisualizer` is used.
280
282
 
281
283
  Visualization export uses **`pyvis`** with **`force_atlas_2based`** physics, fullscreen canvas, HUD filters, glassmorphism control chrome, and stabilized layout configuration suitable for **large graphs at interactive frame rates** in the browser (product positioning targets fluid exploration of graphs on the order of **10⁴ nodes**).
282
284
 
@@ -296,14 +298,14 @@ Both paths keep **existing topology intact** relative to their contract: append-
296
298
 
297
299
  ### 3.6 `LogseqGraph` — namespace scoping, O(1) invalidation, live watch
298
300
 
299
- The **in-memory graph** ([`graph.py`](../src/logseq_matryca_parser/graph.py)) is the runtime **RAM image** of the sovereign vault: `pages: dict[str, LogseqPage]`, a private **`_node_registry`** keyed by synthetic block UUID, and a **`_backlink_registry`** mapping normalized link targets to source node UUIDs.
301
+ The **in-memory graph** ([`graph.py`](../src/logseq_matryca_parser/graph.py)) is the runtime **RAM image** of the sovereign vault: `pages: dict[str, LogseqPage]`, a private **`_node_registry`** keyed by synthetic block UUID, and a **`_backlink_registry`** mapping normalized link targets to source node UUIDs. **`LogseqGraph`** uses **`ConfigDict(strict=True, validate_assignment=True)`** (not frozen) so **`invalidate_and_reload_page`** can mutate registries and page maps without `object.__setattr__` workarounds.
300
302
 
301
303
  #### Page title overrides and alias indexing (`_enrich_pages_index`)
302
304
 
303
305
  After every bulk or incremental parse, the graph applies a **post-parse enrichment pass** before backlink construction:
304
306
 
305
307
  1. **Filename → canonical title.** Each markdown file is first keyed by **`derive_page_title_from_source_path`** (see §3.9).
306
- 2. **`title::` override.** If page frontmatter contains a non-empty string **`title`**, the frozen `LogseqPage` is updated via **`model_copy(update={"title": custom})`**, the old filename key is removed from **`pages`**, and the page is re-inserted under the custom title (collision with another file’s title is skipped with a debug log).
308
+ 2. **`title::` override.** If page frontmatter contains a non-empty string **`title`**, the `LogseqPage` is updated via **`model_copy(update={"title": custom})`**, the old filename key is removed from **`pages`**, and the page is re-inserted under the custom title (collision with another file’s title is skipped with a debug log).
307
309
  3. **Alias injection.** For each canonical dict entry where **`dict_key == page.title`**, values from **`alias::`** and **`aliases::`** are normalized (comma-separated strings or Python lists; `[[Page]]` / `#tag` adornments stripped using the same rules as [`logseq_markdown.py`](../src/logseq_matryca_parser/logseq_markdown.py)) and registered as **additional keys** pointing at the **same `LogseqPage` instance** — e.g. `pages["Dev"]` and `pages["Development"]` share identity.
308
310
  4. **Backlinks.** **`_build_backlink_registry`** walks **unique pages** (`id(page)` deduplication) so alias keys do not double-count outgoing links. Incoming wikilinks such as **`[[Dev]]`** normalize to lowercase registry keys and resolve through **`get_backlinks("Dev")`** like any other page title.
309
311
 
@@ -341,7 +343,11 @@ This keeps **global indexes consistent** without rebuilding the entire graph —
341
343
 
342
344
  #### Live filesystem watcher (`start_watching`)
343
345
 
344
- **`LogseqGraph.start_watching(callback=None)`** (optional **`watchdog`** install) returns a **`LogseqGraphWatcher`** that schedules a recursive **`Observer`** on the graph root. **`on_modified` / `on_created`** events for tracked Markdown call **`invalidate_and_reload_page`**, then optionally invoke **`callback(path)`** — the intended hook for **vector store patch**, **re-embedding**, or UI refresh. Event routing ignores directories and non-tracked extensions so the hot path stays tight.
346
+ **`LogseqGraph.start_watching(callback=None, debounce_seconds=0.5)`** (optional **`watchdog`** install) returns a **`LogseqGraphWatcher`** that schedules a recursive **`Observer`** on the graph root. **`on_modified` / `on_created`** events for tracked Markdown call **`invalidate_and_reload_page`**, then optionally invoke **`callback(path)`** — the intended hook for **vector store patch**, **re-embedding**, or UI refresh. **`_DebouncedGraphEventRouter`** coalesces rapid save bursts (~500ms default) and ignores editor temp/swap artifacts (`.swp`, `~`, `.tmp`, `.DS_Store`). Event routing ignores directories and non-tracked extensions so the hot path stays tight.
347
+
348
+ #### Parse-time reference validation (`strict_refs`)
349
+
350
+ **`StackMachineParser(..., strict_refs=False)`** (default) resolves same-page `((uuid))` block refs leniently. When **`strict_refs=True`**, unresolved refs raise **`BlockReferenceError`** at parse time — complementary to **`LogseqGraph.get_broken_references()`**, which scans the loaded graph post-hoc.
345
351
 
346
352
  #### Fluent topological queries (`GraphQuery`)
347
353
 
@@ -404,6 +410,8 @@ The compound CLI commands **`agent_read`** and **`agent_write`** in [`kinetic.py
404
410
 
405
411
  Rich styling injects **ANSI escape sequences** that waste tokens and can cause models to **hallucinate markup** as content. `agent-read` is **stdout-pure** so shell pipelines, MCP tools, and headless agents receive **unescaped plain text** only. Human-oriented commands (`scan`, `export`, `visualize`) keep Rich; the **machine-native read/write paths** opt out where token fidelity matters.
406
412
 
413
+ **Global CLI options (v1.3.0).** [`kinetic.py`](../src/logseq_matryca_parser/kinetic.py) registers **`@app.callback()`** with **`--verbose`** and **`--graph`** so every subcommand shares graph-path resolution and debug logging. Optional extras (`[ai]`, `[viz]`) print **`uv sync --extra …`** hints on import failure.
414
+
407
415
  This complements §3.4 **AGENT WRITER** (weekly append + headless splice) and §3.2 **SYNAPSE** (human/RAG chunking): one stack, multiple projections — **enriched chunks for vectors**, **X-Ray + alias state for agent context**, **append / splice for durable writes**.
408
416
 
409
417
  ### 3.8 Bidirectional I/O and Logseq Layouts
@@ -459,7 +467,7 @@ Logseq namespaces use **`/`** in titles (e.g. `Projects/AI`). On disk, each segm
459
467
 
460
468
  #### Graph discovery filters
461
469
 
462
- When scanning a vault root, **`is_excluded_graph_path`** drops noise directories — notably **`.recycle`**, **`.git`**, and the internal **`logseq`** config tree — so incremental watchers and bulk loaders never ingest backup blobs or VCS metadata as pages. This keeps **`LogseqGraph.load_directory`** and **`invalidate_and_reload_page`** focused on sovereign content under `pages/` and `journals/`.
470
+ When scanning a vault root, **`discover_graph_files`** (in [`logseq_paths.py`](../src/logseq_matryca_parser/logseq_paths.py), shared by **`LogseqGraph.load_directory`** and **KINETIC**) enumerates `pages/` and `journals/` markdown. **`is_excluded_graph_path`** drops noise directories — notably **`.recycle`**, **`.git`**, and the internal **`logseq`** config tree — so incremental watchers and bulk loaders never ingest backup blobs or VCS metadata as pages. This keeps **`LogseqGraph.load_directory`** and **`invalidate_and_reload_page`** focused on sovereign content under `pages/` and `journals/`.
463
471
 
464
472
  ---
465
473
 
@@ -528,4 +536,4 @@ Recursive and character-budget chunkers assume **approximately flat prose**. Log
528
536
 
529
537
  ---
530
538
 
531
- *This document reflects the implementations in `src/logseq_matryca_parser/logos_parser.py`, `synapse.py`, `graph.py`, `forge.py`, `lens.py`, `logos_core.py`, `agent_writer.py`, `agent_press.py`, `logseq_markdown.py`, and `logseq_paths.py`, and complements narrative primers such as [`logseq_ast_primer.md`](logseq_ast_primer.md).*
539
+ *This document reflects the implementations in `src/logseq_matryca_parser/logos_parser.py`, `synapse.py`, `graph.py`, `forge.py`, `lens.py`, `logos_core.py`, `agent_writer.py`, `agent_press.py`, `logseq_markdown.py`, `logseq_paths.py`, `kinetic.py`, and the public exports in `__init__.py`, and complements narrative primers such as [`logseq_ast_primer.md`](logseq_ast_primer.md).*
@@ -1,6 +1,6 @@
1
1
  # CodeQL code scanning
2
2
 
3
- **Logseq Matryca Parser** (v1.2.2+) uses **GitHub CodeQL default setup** for static analysis (SAST) on Python.
3
+ **Logseq Matryca Parser** (v1.3.0+) uses **GitHub CodeQL default setup** for static analysis (SAST) on Python.
4
4
 
5
5
  ## Why there is no `codeql.yml` workflow
6
6
 
@@ -214,4 +214,4 @@ If you feed Logseq Markdown into `RecursiveCharacterTextSplitter` (LangChain) or
214
214
 
215
215
  The **Logos Protocol** solves this by walking the AST deterministically, isolating properties, shielding dead-zone literals, and using the `SYNAPSE` adapter to export native LangChain `Document` or LlamaIndex `TextNode` objects. Every generated object retains its exact hierarchical lineage in the metadata, feeding your local LLM perfectly structured data.
216
216
 
217
- For vault-wide navigation (aliases, backlinks, namespace shadowing, assets), load the graph with **`LogseqGraph`** — see the [README](../README.md) and [CHANGELOG](../CHANGELOG.md) (graph parity from **v1.2.0**; **v1.2.1** adds CI/OSS hardening; **v1.2.2** fixes CodeQL CI and documents default setup).
217
+ For vault-wide navigation (aliases, backlinks, namespace shadowing, assets), load the graph with **`LogseqGraph`** — see the [README](../README.md) and [CHANGELOG](../CHANGELOG.md) (graph parity from **v1.2.0**; **v1.3.0** adds watcher debounce, `strict_refs`, public API exports, and LlamaIndex spatial relationships).
@@ -1,5 +1,7 @@
1
1
  # 📜 Architectural Contract: Live Incremental Invalidation & File Watcher
2
2
  **Contract Status:** Wave 7 — Implemented (incremental invalidation + lazy watchdog watcher)
3
+
4
+ > **Implementation note (v1.3.0):** `LogseqGraph` now uses `validate_assignment=True` (not `frozen=True`); the watcher debounces events (~500ms) and ignores editor temp files. Historical spec text below describes the original contract.
3
5
  **Target Stack:** Python 3.12+ | Pydantic V2 | Watchdog (Optional/Lazy Dependency)
4
6
  **Inspiration Architectures:**
5
7
  - `Microsoft/language-server-protocol` (Incremental text document synchronization and dependency invalidation)
@@ -1,5 +1,7 @@
1
1
  # 📜 Architectural Contract: Synthetic UUID Hardening & Graph Orchestration Module
2
2
  **Contract Status:** Completed (Autonomous Execution)
3
+
4
+ > **Implementation note (v1.3.0):** `discover_graph_files` lives in `logseq_paths.py` (not `kinetic.py`); `LogseqGraph` uses `validate_assignment=True` instead of `frozen=True`. Historical spec text below describes the original contract.
3
5
  **Target Stack:** Python 3.12+ | Pydantic V2 (Strict/Frozen Models) | Local-First No-DB
4
6
 
5
7
  **Execution checklist**
@@ -11,10 +11,11 @@ root_dir = Path(__file__).parent.parent
11
11
  sys.path.append(str(root_dir / "src"))
12
12
 
13
13
  try:
14
- from logseq_matryca_parser.logos_parser import LogosParser
15
- from logseq_matryca_parser.forge import ForgeExporter
16
14
  from rich.console import Console
17
15
  from rich.panel import Panel
16
+
17
+ from logseq_matryca_parser.forge import ForgeExporter
18
+ from logseq_matryca_parser.logos_parser import LogosParser
18
19
  except ImportError as e:
19
20
  print(f"Errore: Assicurati di aver installato le dipendenze (pip install rich typer pydantic). {e}")
20
21
  sys.exit(1)
@@ -5,10 +5,9 @@ import re
5
5
  import shutil
6
6
  import urllib.request
7
7
  from datetime import datetime
8
- from typing import Any, Dict, Literal, TypeVar
8
+ from typing import Any, Literal, TypeVar
9
9
 
10
10
  from pydantic import BaseModel, ValidationError
11
-
12
11
  from smart_router.core.ingestion_engine import IngestionEngine
13
12
  from smart_router.core.librarian_models import (
14
13
  EntityNodeSchema,
@@ -31,7 +30,7 @@ async def emit_note_package(
31
30
  slug: str,
32
31
  content: str,
33
32
  ontology_class: NodeType,
34
- metadata: Dict[str, str],
33
+ metadata: dict[str, str],
35
34
  indentation_level: int,
36
35
  ) -> None:
37
36
  package = SovereignNotePackage(
@@ -90,9 +89,7 @@ class LogseqASTParser:
90
89
  trees.append("\n".join(current_tree))
91
90
  current_tree = [line]
92
91
  else:
93
- if current_tree:
94
- current_tree.append(line)
95
- elif line.strip():
92
+ if current_tree or line.strip():
96
93
  current_tree.append(line)
97
94
  if current_tree:
98
95
  trees.append("\n".join(current_tree))
@@ -122,7 +119,7 @@ T = TypeVar("T", bound=BaseModel)
122
119
  def call_local_llm(
123
120
  system_prompt: str, user_content: str, response_model: type[T]
124
121
  ) -> T | None:
125
- payload: Dict[str, Any] = {
122
+ payload: dict[str, Any] = {
126
123
  "model": "local-model",
127
124
  "messages": [
128
125
  {"role": "system", "content": system_prompt},
@@ -204,7 +201,7 @@ async def main() -> None:
204
201
  if filename.startswith("."):
205
202
  continue
206
203
  filepath = os.path.join(INBOX_DIR, filename)
207
- with open(filepath, "r", encoding="utf-8") as f:
204
+ with open(filepath, encoding="utf-8") as f:
208
205
  global_skeleton = f.read()
209
206
  macro_buckets = LogseqASTParser.chunk_into_buckets(
210
207
  global_skeleton, max_chars=15000
@@ -247,7 +244,7 @@ async def main() -> None:
247
244
  if not note_filename.endswith(".md"):
248
245
  note_filename += ".md"
249
246
  try:
250
- metadata: Dict[str, str] = {
247
+ metadata: dict[str, str] = {
251
248
  "source_filename": filename,
252
249
  "confidence": str(extracted_base.confidence),
253
250
  "extracted_at": datetime.now().isoformat(),
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "logseq-matryca-parser"
7
- version = "1.2.2"
7
+ version = "1.3.0"
8
8
  description = "The Logos Protocol: Deterministic Logseq AST parsing for Matryca.ai."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -76,6 +76,14 @@ dev = [
76
76
  "ruff>=0.15.12",
77
77
  ]
78
78
 
79
+ [tool.uv]
80
+ constraint-dependencies = [
81
+ "aiohttp>=3.14.1",
82
+ ]
83
+ override-dependencies = [
84
+ "nltk @ git+https://github.com/nltk/nltk@v3.10.0-rc1",
85
+ ]
86
+
79
87
  [tool.pytest.ini_options]
80
88
  testpaths = ["tests"]
81
89
 
@@ -95,3 +103,16 @@ module = [
95
103
  "watchdog.*",
96
104
  ]
97
105
  ignore_missing_imports = true
106
+
107
+ [tool.ruff]
108
+ target-version = "py312"
109
+ line-length = 100
110
+ exclude = ["legacy", "examples", "scripts"]
111
+
112
+ [tool.ruff.lint]
113
+ select = ["E", "F", "I", "UP", "B", "SIM"]
114
+ ignore = ["E501"]
115
+
116
+ [tool.ruff.lint.per-file-ignores]
117
+ "src/logseq_matryca_parser/kinetic.py" = ["B008"]
118
+ "tests/**" = ["SIM117"]
@@ -4,8 +4,9 @@ from __future__ import annotations
4
4
 
5
5
  import sys
6
6
 
7
- __version__ = "1.2.2"
7
+ __version__ = "1.3.0"
8
8
 
9
+ from .agent_press import SessionAliasRegistry
9
10
  from .agent_writer import LogseqConfigReader, logseq_agent_write
10
11
  from .exceptions import BlockReferenceError, LogseqIndentationError, LogseqParserError
11
12
  from .forge import (
@@ -16,7 +17,15 @@ from .forge import (
16
17
  ObsidianForgeVisitor,
17
18
  )
18
19
  from .graph import LogseqGraph
19
- from .logos_core import ASTVisitor, LogseqNode, LogseqPage, LogosNode, SovereignNotePackage
20
+ from .logos_core import ASTVisitor, LogosNode, LogseqNode, LogseqPage, SovereignNotePackage
21
+ from .logos_parser import (
22
+ LOGSEQ_PATTERNS,
23
+ LogosParser,
24
+ PageRegistry,
25
+ StackMachineParser,
26
+ clean_node_content,
27
+ is_system_block,
28
+ )
20
29
  from .logseq_markdown import (
21
30
  format_logseq_block_property_lines,
22
31
  format_logseq_page_properties,
@@ -26,12 +35,19 @@ from .logseq_markdown import (
26
35
  from .logseq_paths import (
27
36
  decode_page_title_segment,
28
37
  derive_page_title_from_source_path,
38
+ discover_graph_files,
29
39
  encode_page_title_segment,
30
40
  filename_to_page_title,
31
41
  is_excluded_graph_path,
32
42
  page_title_to_filename,
33
43
  page_title_to_relative_path,
34
44
  )
45
+ from .synapse import SynapseAdapter, page_source_node_id
46
+
47
+ try:
48
+ from .lens import GraphVisualizer
49
+ except ImportError: # optional [viz] extra (networkx / pyvis)
50
+ GraphVisualizer = None # type: ignore[misc, assignment]
35
51
 
36
52
 
37
53
  def ensure_aot_compatibility() -> None:
@@ -46,6 +62,7 @@ __all__ = [
46
62
  "BlockReferenceError",
47
63
  "FlatListForgeVisitor",
48
64
  "ForgeExporter",
65
+ "GraphVisualizer",
49
66
  "JSONForgeVisitor",
50
67
  "LOGSEQ_PATTERNS",
51
68
  "LogosNode",
@@ -56,22 +73,26 @@ __all__ = [
56
73
  "LogseqNode",
57
74
  "LogseqPage",
58
75
  "LogseqParserError",
76
+ "MarkdownForgeVisitor",
77
+ "ObsidianForgeVisitor",
59
78
  "PageRegistry",
79
+ "SessionAliasRegistry",
60
80
  "SovereignNotePackage",
61
81
  "StackMachineParser",
82
+ "SynapseAdapter",
62
83
  "clean_node_content",
63
- "ensure_aot_compatibility",
64
84
  "decode_page_title_segment",
65
85
  "derive_page_title_from_source_path",
86
+ "discover_graph_files",
66
87
  "encode_page_title_segment",
88
+ "ensure_aot_compatibility",
67
89
  "filename_to_page_title",
68
90
  "format_logseq_block_property_lines",
69
91
  "format_logseq_page_properties",
70
92
  "is_excluded_graph_path",
71
93
  "is_system_block",
72
94
  "logseq_agent_write",
73
- "MarkdownForgeVisitor",
74
- "ObsidianForgeVisitor",
95
+ "page_source_node_id",
75
96
  "page_title_to_filename",
76
97
  "page_title_to_relative_path",
77
98
  "serialize_logseq_page",
@@ -179,10 +179,7 @@ def _replace_block_refs_in_text(
179
179
 
180
180
  def _obsidian_line_source(node: LogseqNode) -> str:
181
181
  """Prefer the first line of ``content`` so ``((uuid))`` survives when stripped from ``clean_text``."""
182
- if node.content:
183
- first = node.content.split("\n", 1)[0]
184
- else:
185
- first = node.clean_text
182
+ first = node.content.split("\n", 1)[0] if node.content else node.clean_text
186
183
  stripped = LOGSEQ_PATTERNS["inline_uuid_prop"].sub("", first)
187
184
  return stripped.replace("\n", " ").strip()
188
185