synto 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. synto-0.1.0/.github/FUNDING.yml +6 -0
  2. synto-0.1.0/.github/workflows/benchmark.yml +41 -0
  3. synto-0.1.0/.github/workflows/ci.yml +38 -0
  4. synto-0.1.0/.github/workflows/release.yml +72 -0
  5. synto-0.1.0/.gitignore +32 -0
  6. synto-0.1.0/CLAUDE.md +83 -0
  7. synto-0.1.0/LICENSE +21 -0
  8. synto-0.1.0/PKG-INFO +190 -0
  9. synto-0.1.0/README.md +155 -0
  10. synto-0.1.0/RELEASE.md +38 -0
  11. synto-0.1.0/docs/img/setup.png +0 -0
  12. synto-0.1.0/docs/web-clipper-setup.md +76 -0
  13. synto-0.1.0/install.py +238 -0
  14. synto-0.1.0/pyproject.toml +71 -0
  15. synto-0.1.0/scripts/benchmark.sh +127 -0
  16. synto-0.1.0/scripts/compare_smoke.sh +356 -0
  17. synto-0.1.0/scripts/release.sh +44 -0
  18. synto-0.1.0/scripts/smoke_test.sh +1397 -0
  19. synto-0.1.0/src/synto/__init__.py +1 -0
  20. synto-0.1.0/src/synto/cli.py +2859 -0
  21. synto-0.1.0/src/synto/client_factory.py +70 -0
  22. synto-0.1.0/src/synto/compare/__init__.py +25 -0
  23. synto-0.1.0/src/synto/compare/metrics.py +215 -0
  24. synto-0.1.0/src/synto/compare/models.py +92 -0
  25. synto-0.1.0/src/synto/compare/report.py +180 -0
  26. synto-0.1.0/src/synto/compare/runner.py +510 -0
  27. synto-0.1.0/src/synto/config.py +301 -0
  28. synto-0.1.0/src/synto/engines.py +151 -0
  29. synto-0.1.0/src/synto/git_ops.py +115 -0
  30. synto-0.1.0/src/synto/global_config.py +86 -0
  31. synto-0.1.0/src/synto/indexer.py +272 -0
  32. synto-0.1.0/src/synto/markdown_math.py +110 -0
  33. synto-0.1.0/src/synto/metrics.py +193 -0
  34. synto-0.1.0/src/synto/models.py +409 -0
  35. synto-0.1.0/src/synto/ollama_client.py +179 -0
  36. synto-0.1.0/src/synto/openai_compat_client.py +482 -0
  37. synto-0.1.0/src/synto/pack_export.py +706 -0
  38. synto-0.1.0/src/synto/paths.py +61 -0
  39. synto-0.1.0/src/synto/pipeline/__init__.py +0 -0
  40. synto-0.1.0/src/synto/pipeline/compile.py +1526 -0
  41. synto-0.1.0/src/synto/pipeline/eval.py +241 -0
  42. synto-0.1.0/src/synto/pipeline/ingest.py +1172 -0
  43. synto-0.1.0/src/synto/pipeline/items.py +228 -0
  44. synto-0.1.0/src/synto/pipeline/lint.py +930 -0
  45. synto-0.1.0/src/synto/pipeline/lock.py +177 -0
  46. synto-0.1.0/src/synto/pipeline/maintain.py +359 -0
  47. synto-0.1.0/src/synto/pipeline/orchestrator.py +325 -0
  48. synto-0.1.0/src/synto/pipeline/query.py +786 -0
  49. synto-0.1.0/src/synto/pipeline/review.py +136 -0
  50. synto-0.1.0/src/synto/pricing.py +41 -0
  51. synto-0.1.0/src/synto/protocols.py +43 -0
  52. synto-0.1.0/src/synto/providers.py +79 -0
  53. synto-0.1.0/src/synto/readers.py +668 -0
  54. synto-0.1.0/src/synto/sanitize.py +45 -0
  55. synto-0.1.0/src/synto/schemas/index-v1.json +132 -0
  56. synto-0.1.0/src/synto/serve.py +231 -0
  57. synto-0.1.0/src/synto/state.py +2221 -0
  58. synto-0.1.0/src/synto/stats.py +293 -0
  59. synto-0.1.0/src/synto/structured_output.py +315 -0
  60. synto-0.1.0/src/synto/vault.py +332 -0
  61. synto-0.1.0/src/synto/watcher.py +131 -0
  62. synto-0.1.0/tests/compare_corpus/corpus.toml +100 -0
  63. synto-0.1.0/tests/compare_corpus/notes/ambiguous_entity.md +29 -0
  64. synto-0.1.0/tests/compare_corpus/notes/cross_reference.md +26 -0
  65. synto-0.1.0/tests/compare_corpus/notes/data_heavy_table.md +56 -0
  66. synto-0.1.0/tests/compare_corpus/notes/edge_empty_list.md +17 -0
  67. synto-0.1.0/tests/compare_corpus/notes/long_dense_technical.md +71 -0
  68. synto-0.1.0/tests/compare_corpus/notes/moderate_overlap.md +38 -0
  69. synto-0.1.0/tests/compare_corpus/notes/multi_concept_overlap.md +29 -0
  70. synto-0.1.0/tests/compare_corpus/notes/narrative_essay.md +19 -0
  71. synto-0.1.0/tests/compare_corpus/notes/noisy_low_quality.md +27 -0
  72. synto-0.1.0/tests/compare_corpus/notes/short_factual.md +11 -0
  73. synto-0.1.0/tests/compare_corpus/queries.toml +68 -0
  74. synto-0.1.0/tests/conftest.py +45 -0
  75. synto-0.1.0/tests/eval/__init__.py +1 -0
  76. synto-0.1.0/tests/eval/queries_default.toml +29 -0
  77. synto-0.1.0/tests/fixtures/analysis_valid.json +11 -0
  78. synto-0.1.0/tests/fixtures/compile_plan_valid.json +12 -0
  79. synto-0.1.0/tests/fixtures/single_article_valid.json +5 -0
  80. synto-0.1.0/tests/test_benchmarks.py +209 -0
  81. synto-0.1.0/tests/test_cli_compile.py +101 -0
  82. synto-0.1.0/tests/test_cli_messaging.py +99 -0
  83. synto-0.1.0/tests/test_cli_migrate_olw.py +328 -0
  84. synto-0.1.0/tests/test_cli_model_flags.py +47 -0
  85. synto-0.1.0/tests/test_cli_query.py +200 -0
  86. synto-0.1.0/tests/test_cli_reject.py +157 -0
  87. synto-0.1.0/tests/test_cli_status.py +56 -0
  88. synto-0.1.0/tests/test_cli_support.py +26 -0
  89. synto-0.1.0/tests/test_compare_cli.py +214 -0
  90. synto-0.1.0/tests/test_compare_metrics.py +167 -0
  91. synto-0.1.0/tests/test_compare_report.py +120 -0
  92. synto-0.1.0/tests/test_compare_runner.py +276 -0
  93. synto-0.1.0/tests/test_compare_safety.py +144 -0
  94. synto-0.1.0/tests/test_compile.py +573 -0
  95. synto-0.1.0/tests/test_compile_v2.py +1204 -0
  96. synto-0.1.0/tests/test_config.py +276 -0
  97. synto-0.1.0/tests/test_git_ops.py +105 -0
  98. synto-0.1.0/tests/test_indexer.py +94 -0
  99. synto-0.1.0/tests/test_ingest.py +1357 -0
  100. synto-0.1.0/tests/test_items.py +176 -0
  101. synto-0.1.0/tests/test_lint.py +926 -0
  102. synto-0.1.0/tests/test_lock.py +206 -0
  103. synto-0.1.0/tests/test_maintain.py +340 -0
  104. synto-0.1.0/tests/test_metrics.py +296 -0
  105. synto-0.1.0/tests/test_ollama_client.py +118 -0
  106. synto-0.1.0/tests/test_openai_compat_client.py +335 -0
  107. synto-0.1.0/tests/test_orchestrator.py +479 -0
  108. synto-0.1.0/tests/test_phase0_engines.py +62 -0
  109. synto-0.1.0/tests/test_phase0_migration_v8.py +307 -0
  110. synto-0.1.0/tests/test_phase0_readers.py +110 -0
  111. synto-0.1.0/tests/test_phase0_schemas.py +207 -0
  112. synto-0.1.0/tests/test_phase1a_capability_gating.py +158 -0
  113. synto-0.1.0/tests/test_phase1a_eval.py +254 -0
  114. synto-0.1.0/tests/test_phase1a_index_json.py +127 -0
  115. synto-0.1.0/tests/test_phase1a_metrics_cli.py +101 -0
  116. synto-0.1.0/tests/test_phase1a_metrics_persistence.py +142 -0
  117. synto-0.1.0/tests/test_phase1a_migration_v9.py +600 -0
  118. synto-0.1.0/tests/test_phase1a_pack_export.py +644 -0
  119. synto-0.1.0/tests/test_phase1a_pack_reader.py +207 -0
  120. synto-0.1.0/tests/test_phase1a_query_engine.py +130 -0
  121. synto-0.1.0/tests/test_phase1a_serve.py +232 -0
  122. synto-0.1.0/tests/test_phase1a_state.py +33 -0
  123. synto-0.1.0/tests/test_phase1a_stats.py +264 -0
  124. synto-0.1.0/tests/test_phase1a_vault_reader.py +431 -0
  125. synto-0.1.0/tests/test_pipeline_language.py +103 -0
  126. synto-0.1.0/tests/test_pipeline_reject_all.py +123 -0
  127. synto-0.1.0/tests/test_providers.py +756 -0
  128. synto-0.1.0/tests/test_query.py +317 -0
  129. synto-0.1.0/tests/test_query_git_behavior.py +79 -0
  130. synto-0.1.0/tests/test_query_synthesize.py +568 -0
  131. synto-0.1.0/tests/test_review.py +255 -0
  132. synto-0.1.0/tests/test_sanitize.py +117 -0
  133. synto-0.1.0/tests/test_setup.py +695 -0
  134. synto-0.1.0/tests/test_state.py +682 -0
  135. synto-0.1.0/tests/test_structured_output.py +300 -0
  136. synto-0.1.0/tests/test_vault.py +453 -0
  137. synto-0.1.0/tests/test_watcher.py +154 -0
  138. synto-0.1.0/uv.lock +1133 -0
@@ -0,0 +1,6 @@
1
+ # These are supported funding model platforms
2
+
3
+ github: kytmanov
4
+ liberapay: kytmanov
5
+ buy_me_a_coffee: kytmanov
6
+ custom: ["https://tip.md/kytmanov"]
@@ -0,0 +1,41 @@
1
+ name: Benchmarks
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ branches: [master]
8
+
9
+ jobs:
10
+ benchmark:
11
+ name: Offline micro-benchmarks
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - name: Install uv
18
+ uses: astral-sh/setup-uv@v4
19
+ with:
20
+ version: "latest"
21
+
22
+ - name: Set up Python
23
+ run: uv python install 3.12
24
+
25
+ - name: Install dependencies
26
+ run: uv sync --group dev
27
+
28
+ - name: Run benchmarks
29
+ run: |
30
+ uv run pytest tests/test_benchmarks.py \
31
+ --benchmark-only \
32
+ --benchmark-json=benchmark-results.json \
33
+ -v
34
+
35
+ - name: Upload benchmark results
36
+ uses: actions/upload-artifact@v4
37
+ with:
38
+ name: benchmark-results
39
+ path: benchmark-results.json
40
+ retention-days: 90
41
+
@@ -0,0 +1,38 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master, main]
6
+ pull_request:
7
+ branches: [master, main]
8
+
9
+ jobs:
10
+ test:
11
+ name: pytest + ruff
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ matrix:
15
+ python-version: ["3.11", "3.12"]
16
+
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Install uv
21
+ uses: astral-sh/setup-uv@v4
22
+ with:
23
+ version: "latest"
24
+
25
+ - name: Set up Python ${{ matrix.python-version }}
26
+ run: uv python install ${{ matrix.python-version }}
27
+
28
+ - name: Install dependencies
29
+ run: uv sync --group dev
30
+
31
+ - name: Lint (ruff)
32
+ run: uv run ruff check src/ tests/
33
+
34
+ - name: Format check (ruff)
35
+ run: uv run ruff format --check src/ tests/
36
+
37
+ - name: Run tests
38
+ run: uv run pytest --tb=short -q
@@ -0,0 +1,72 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ test:
10
+ name: Tests must pass
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+
15
+ - name: Install uv
16
+ uses: astral-sh/setup-uv@v4
17
+ with:
18
+ version: "latest"
19
+
20
+ - name: Set up Python
21
+ run: uv python install 3.11
22
+
23
+ - name: Install dependencies
24
+ run: uv sync --group dev
25
+
26
+ - name: Lint
27
+ run: uv run ruff check src/ tests/
28
+
29
+ - name: Tests
30
+ run: uv run pytest --tb=short -q
31
+
32
+ release:
33
+ name: Create GitHub Release
34
+ needs: test
35
+ runs-on: ubuntu-latest
36
+ permissions:
37
+ contents: write
38
+
39
+ steps:
40
+ - uses: actions/checkout@v4
41
+ with:
42
+ fetch-depth: 0
43
+
44
+ - name: Create release
45
+ uses: softprops/action-gh-release@v2
46
+ with:
47
+ generate_release_notes: true
48
+ make_latest: true
49
+
50
+ publish:
51
+ name: Publish to PyPI
52
+ needs: test
53
+ runs-on: ubuntu-latest
54
+ environment: pypi
55
+ permissions:
56
+ id-token: write # OIDC trusted publishing — no API token needed
57
+
58
+ steps:
59
+ - uses: actions/checkout@v4
60
+
61
+ - name: Install uv
62
+ uses: astral-sh/setup-uv@v4
63
+ with:
64
+ version: "latest"
65
+
66
+ - name: Build package
67
+ run: uv build
68
+
69
+ - name: Publish to PyPI
70
+ uses: pypa/gh-action-pypi-publish@release/v1
71
+ with:
72
+ skip-existing: true
synto-0.1.0/.gitignore ADDED
@@ -0,0 +1,32 @@
1
+ .DS_Store
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .venv/
8
+ .env
9
+ *.log
10
+
11
+ # Vault artifacts (not part of the tool itself)
12
+ .chroma/
13
+ *.db
14
+ .olw-compare/
15
+
16
+ # Test artifacts
17
+ .coverage
18
+ htmlcov/
19
+ .pytest_cache/
20
+
21
+ # Claude Code local settings (user-specific, never commit)
22
+ .claude/
23
+
24
+ # Ruff cache
25
+ .ruff_cache/
26
+
27
+ # Local planning/review artifacts
28
+ CONTEXT.md
29
+ REQUIREMENTS.md
30
+ IMPLEMENTATION_PLAN.md
31
+ IMPLEMENTAION_PLAN.md
32
+ REVIEW.md
synto-0.1.0/CLAUDE.md ADDED
@@ -0,0 +1,83 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Commands
6
+
7
+ ```bash
8
+ # Install (editable, auto-detects uv/pip)
9
+ python install.py
10
+
11
+ # Dependencies
12
+ uv sync --group dev
13
+
14
+ # Tests (all offline, no Ollama required)
15
+ uv run pytest
16
+ uv run pytest tests/test_ingest.py::test_function_name -v # single test
17
+ uv run pytest --cov=src/synto # with coverage
18
+
19
+ # Lint & format
20
+ uv run ruff check src/ tests/
21
+ uv run ruff format --check src/ tests/
22
+ uv run ruff format src/ tests/ # auto-fix
23
+
24
+ # Smoke tests (user preference: run against LM Studio with gemma4:e4b)
25
+ # Requires LM Studio server at http://localhost:1234/v1 with gemma4:e4b loaded.
26
+ PROVIDER=lm_studio FAST_MODEL=gemma4:e4b HEAVY_MODEL=gemma4:e4b bash scripts/smoke_test.sh
27
+ PROVIDER=lm_studio FAST_MODEL=gemma4:e4b HEAVY_MODEL=gemma4:e4b bash scripts/compare_smoke.sh
28
+ # If LM Studio rejects the alias, use the exact loaded id it reports, e.g.
29
+ # PROVIDER=lm_studio FAST_MODEL=google/gemma-4-e4b HEAVY_MODEL=google/gemma-4-e4b bash scripts/smoke_test.sh
30
+ # The main smoke can take 15+ minutes with gemma4:e4b; use a long command timeout.
31
+ ```
32
+
33
+ ## Architecture
34
+
35
+ Three-stage local LLM pipeline turning Obsidian raw notes into a synthesized wiki via Ollama.
36
+
37
+ **Data flow:** `raw/*.md` → **ingest** (fast model → AnalysisResult) → **compile** (heavy model → SingleArticle drafts) → **approve** (publish to `wiki/`)
38
+
39
+ **Vault structure:** `raw/` (immutable user notes), `wiki/` (published articles), `wiki/.drafts/`, `wiki/sources/`, `wiki/queries/`, `wiki/synthesis/`, `.synto/state.db`
40
+
41
+ ### Query synthesis
42
+
43
+ - `synto query --save` writes dated Q&A notes to `wiki/queries/`
44
+ - `synto query --synthesize` writes published synthesis articles to `wiki/synthesis/`
45
+ - synthesis rows are tracked in `wiki_articles` with `kind="synthesis"`, `question_hash`, `synthesis_sources`, and `synthesis_source_hashes`
46
+ - duplicate syntheses are keyed by normalized question hash
47
+ - `update_in_place` must respect manual-edit protection by comparing the on-disk body hash with the DB `content_hash`
48
+ - compare runs must not create or mutate active `wiki/synthesis/` content
49
+
50
+ ### Key modules (`src/synto/`)
51
+
52
+ - `cli.py` — Click-based CLI entry point, all commands registered here
53
+ - `config.py` / `global_config.py` — Two-tier config: per-vault `synto.toml` + user-level `~/.config/synto/config.toml`
54
+ - `models.py` — Pydantic v2 schemas for LLM I/O (AnalysisResult, SingleArticle, PageSelection, QueryAnswer) and internal state (RawNoteRecord, WikiArticleRecord)
55
+ - `state.py` — SQLite state DB tracking note lifecycle (new → ingested → compiled → published/failed), concepts, and articles
56
+ - `ollama_client.py` — Thin httpx wrapper around Ollama HTTP API (no langchain)
57
+ - `structured_output.py` — 3-tier JSON extraction fallback: native `format=json` → regex extraction → retry with error feedback
58
+ - `vault.py` — Frontmatter parsing (python-frontmatter), wikilink extraction, atomic writes
59
+ - `indexer.py` — Generates `wiki/index.md` and append-only operation log
60
+ - `git_ops.py` — Auto-commit with `[synto]` prefix, safe undo via `git revert`
61
+ - `watcher.py` — Debounced file watcher (watchdog + threading.Timer)
62
+
63
+ ### Pipeline stages (`pipeline/`)
64
+
65
+ - `ingest.py` — Fast model analyzes raw notes, extracts concepts, creates source summary pages
66
+ - `compile.py` — Default: concept-driven (one article per concept, incremental). Legacy: two-step LLM planning (`--legacy`). Manual-edit protection via content_hash comparison
67
+ - `query.py` — Index-based page routing (no embeddings), fast model selects pages, heavy model answers
68
+ - `lint.py` — Static health checks (orphans, broken links, stale articles, missing frontmatter)
69
+
70
+ ## Conventions
71
+
72
+ - **Two LLM tiers:** fast model (gemma4:e4b, 8K ctx) for analysis/routing, heavy model (qwen2.5:14b, 16K ctx) for writing. For manual/smoke testing, use gemma4:e4b for both fast and heavy
73
+ - **Pydantic models for LLM output:** Keep schemas small and flat (no nested lists of objects) for 4B model reliability. JSON schema is injected into system prompts
74
+ - **Atomic writes:** `vault.atomic_write()` uses temp file + rename for crash safety
75
+ - **Content hashing:** SHA256 on note body (excluding frontmatter) for dedup and manual-edit detection
76
+ - **Concept normalization:** Case-insensitive matching against existing canonical names during ingest
77
+ - **Config loading order:** `--vault` flag → `SYNTO_VAULT` env var → global config default vault → error
78
+ - **Git safety:** All auto-operations use `[synto]`-prefixed commits; undo uses `git revert` (never destructive)
79
+ - **Error handling:** LLM failures log + mark note as "failed" + continue (no crash). Config loading returns None on failure (fail open)
80
+ - **Code comments:** Add comments only when the reason or invariant is non-obvious from the code itself. Prefer tests and commit messages for routine explanation; use comments for safeguards, provider quirks, heuristics, and tradeoffs that future agents or humans could otherwise misread.
81
+ - **Testing:** All 200 tests mock OllamaClient via MagicMock, use tmp_path vaults and in-memory SQLite. Fixtures in `tests/fixtures/`. Integration tests marked with `@pytest.mark.integration`
82
+ - **Python 3.11+:** Uses `tomllib` (stdlib), `from __future__ import annotations`, full type hints
83
+ - **Ruff config:** rules E, F, I, UP; line-length 100
synto-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 kytmanov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
synto-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,190 @@
1
+ Metadata-Version: 2.4
2
+ Name: synto
3
+ Version: 0.1.0
4
+ Summary: Turn private notes into local knowledge packs and synthesized wikis
5
+ Project-URL: Homepage, https://github.com/kytmanov/synto
6
+ Project-URL: Repository, https://github.com/kytmanov/synto
7
+ Project-URL: Issues, https://github.com/kytmanov/synto/issues
8
+ Author: kytmanov
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: knowledge-management,llm,local-ai,obsidian,ollama,wiki
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: End Users/Desktop
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Text Processing :: Markup :: Markdown
21
+ Classifier: Topic :: Utilities
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: click>=8.1
24
+ Requires-Dist: httpx>=0.27
25
+ Requires-Dist: jsonschema>=4.0
26
+ Requires-Dist: pydantic>=2.0
27
+ Requires-Dist: python-frontmatter>=1.1
28
+ Requires-Dist: python-ulid>=2.0
29
+ Requires-Dist: pyyaml>=6.0
30
+ Requires-Dist: rich>=13.0
31
+ Requires-Dist: watchdog>=4.0
32
+ Provides-Extra: mcp
33
+ Requires-Dist: mcp<2.0,>=1.0; extra == 'mcp'
34
+ Description-Content-Type: text/markdown
35
+
36
+ # Synto
37
+
38
+ <p align="center">
39
+ <a href="https://github.com/kytmanov/synto/commits/master"><img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/kytmanov/obsidian-llm-wiki-local?style=flat"></a>
40
+ <a href="https://github.com/kytmanov/synto/actions/workflows/ci.yml"><img alt="CI status" src="https://img.shields.io/github/actions/workflow/status/kytmanov/synto/ci.yml?style=flat&amp;label=CI"></a>
41
+ <a href="https://pypi.org/project/synto/"><img alt="PyPI version" src="https://img.shields.io/pypi/v/synto?style=flat"></a>
42
+ </p>
43
+
44
+ **Turn your raw notes into a self-improving, interlinked wiki — powered by a local LLM.**
45
+
46
+ Synto is a knowledge compiler. Point it at any source of expertise and it produces a portable wiki pack any AI agent can install and query.
47
+
48
+
49
+ **Local-first, provider-flexible.** Runs 100% locally with Ollama or LM Studio. Switch to a cloud provider — Groq, OpenRouter, Mistral — when you need more power. Your notes and source material never leave your machine unless you choose.
50
+
51
+ Synto succeeds [obsidian-llm-wiki-local](https://github.com/kytmanov/obsidian-llm-wiki-local) (608 ★, 9k+ downloads) — same proven local pipeline, redesigned for distributable knowledge packs.
52
+
53
+ <p align=center>
54
+ <img width="341" height="463" alt="image" src="https://github.com/user-attachments/assets/b3e13203-bb4a-42a4-a16d-0d4d93404f71" />
55
+ </p>
56
+
57
+ ---
58
+
59
+ ## Why it exists
60
+
61
+ AI agents are only as good as the context you give them. A folder of notes or a raw PDF is not context — it's noise. Synto processes your source material through a local LLM pipeline, extracts concepts, writes cross-linked articles, and exports a structured directory: articles, an index, a concept graph, and agent-readable metadata. The pack installs like a package. Any agent gets a domain expert layer, not a file dump.
62
+
63
+ ---
64
+
65
+ ## Use cases
66
+
67
+ **Architectural reference from a textbook**
68
+
69
+ [Dobryakov took Tanenbaum's *Distributed Systems*](https://www.facebook.com/dobryakov/posts/pfbid021pwPPJZ77KsyWMs3zTdMQEbgpmxgeE9wzoX1SDFE12y5vC3HtdFZV5i5HnS2dUAul), compiled it into a cross-linked wiki, and installed it into Claude/Cursor. Instead of generic suggestions, the AI started reasoning from established distributed systems principles — recommending consistent hashing and two-phase commit instead of "use a shared database." Any technical book, spec, or documentation set becomes a live context layer for your AI.
70
+
71
+ **Karpathy's LLM Wiki**
72
+
73
+ [Andrej Karpathy's](https://karpathy.ai) neural-network series is 20 hours of dense, high-quality material. Compile the transcripts and blog posts into a Synto pack and the content becomes queryable: any agent in your project can explain backpropagation, walk through the attention mechanism, or cite a specific lecture — from the source, not from model weights.
74
+
75
+ **Your own research notes**
76
+
77
+ Works today with Markdown. Drop notes in `raw/`, run `synto run`, and get a cross-linked wiki exported as an agent-ready pack. Expose it via `synto serve` as a local MCP server, or ship the pack directory for any file-aware agent to use.
78
+
79
+ ---
80
+
81
+ ## How it works
82
+
83
+ Three stages, two LLM tiers:
84
+
85
+ 1. **Ingest** — fast model reads each source, extracts concepts and summaries
86
+ 2. **Compile** — heavy model writes one cross-linked article per concept
87
+ 3. **Export** — `synto pack export` produces an agent-ready directory
88
+
89
+ The fast model handles analysis (4B parameters is enough). The heavy model handles writing (14B+ recommended locally, or any cloud model). Both tiers are configurable independently.
90
+
91
+ ---
92
+
93
+ ## Install
94
+
95
+ ```bash
96
+ pip install synto
97
+ # or
98
+ uv tool install synto
99
+ ```
100
+
101
+ For MCP server support:
102
+
103
+ ```bash
104
+ pip install "synto[mcp]"
105
+ ```
106
+
107
+ ---
108
+
109
+ ## Quick start
110
+
111
+ ```bash
112
+ synto setup # configure LLM provider
113
+ synto init ~/my-vault # create vault
114
+
115
+ # add Markdown notes to ~/my-vault/raw/
116
+ synto run --vault ~/my-vault # ingest + compile into wiki/.drafts/
117
+ synto review --vault ~/my-vault # inspect drafts interactively
118
+ # or: synto approve --all --vault ~/my-vault
119
+
120
+ synto pack export --target agents --vault ~/my-vault
121
+ synto serve --vault ~/my-vault # expose as MCP server (requires [mcp])
122
+ ```
123
+
124
+ If you want a one-command flow, use `synto run --auto-approve --vault ~/my-vault`.
125
+ That skips draft review and publishes directly into `wiki/`.
126
+
127
+ ---
128
+
129
+ ## What's in a pack
130
+
131
+ ```
132
+ pack/
133
+ articles/ one Markdown file per concept
134
+ index/INDEX.json machine-readable index with stable article IDs
135
+ agent/
136
+ manifest.json capabilities, pack metadata
137
+ concepts.json concept registry
138
+ sources.json source provenance
139
+ AGENTS.md agent-readable entrypoint
140
+ CLAUDE.md Claude Code context file
141
+ ```
142
+
143
+ Any file-aware agent can read the articles directly. `INDEX.json` enables fast concept lookup without a database. `synto serve` exposes `list_articles`, `read_article`, and `find_concept` as MCP tools.
144
+
145
+ ---
146
+
147
+ ## What ships now
148
+
149
+ - Full ingest → compile → approve pipeline; currently supports Markdown notes and Obsidian vaults
150
+ - `synto pack export --target agents` — portable knowledge pack with INDEX.json and agent metadata
151
+ - `synto serve` — read-only MCP server (`list_articles`, `read_article`, `find_concept`)
152
+ - `synto query` — index-routed Q&A with optional synthesis to `wiki/synthesis/`
153
+ - `synto review` — interactive draft review: approve, reject, edit, or diff before publishing
154
+ - `synto watch` — file watcher: auto-ingest and compile on every save
155
+ - `synto maintain` — wiki health check, stub creation, orphan cleanup
156
+ - `synto eval` — offline structural evaluation (coverage, citation support, link resolution)
157
+ - `synto compare` — A/B model comparison without touching your vault
158
+ - Multi-language: notes are ingested and compiled in their source language
159
+ - 20+ LLM providers supported via OpenAI-compatible API
160
+
161
+ ---
162
+
163
+ ## Data & Privacy
164
+
165
+ - **Local by default.** Ollama and LM Studio process all content on your machine — notes never leave it.
166
+ - **Cloud providers.** If you configure an OpenAI-compatible cloud provider, note content and wiki text are sent to that service. Review their privacy policy before use.
167
+ - **No remote analytics.** Synto does not send usage analytics anywhere. Local runtime and cost metrics stay in your vault database.
168
+ - **Pack exports.** Exported packs include raw notes, sources, wiki articles, queries, and synthesis by default. Review your vault before sharing a pack.
169
+ - **API keys.** Stored in `~/.config/synto/config.toml` (user-owned, not inside the vault). Never commit that file.
170
+
171
+ ---
172
+
173
+ ## Requirements
174
+
175
+ - Python 3.11+
176
+ - An LLM provider: Ollama (local), LM Studio, or any OpenAI-compatible endpoint
177
+
178
+ Recommended local setup: a 4B model for ingest (e.g. Gemma 4), a 14B+ model for compilation (e.g. Qwen 2.5 14B). Works entirely offline.
179
+
180
+ ---
181
+
182
+ ## Migrate from obsidian-llm-wiki-local
183
+
184
+ **Existing obsidian-llm-wiki-local vaults must be migrated first.** Run `migrate-olw` to copy `wiki.toml` and `.olw/` into the current Synto layout before using normal commands.
185
+
186
+ ```bash
187
+ synto migrate-olw --vault ~/my-old-vault
188
+ ```
189
+
190
+ Copies `wiki.toml` → `synto.toml` and `.olw/` → `.synto/`. Notes and articles are untouched. Old files are preserved — delete them once you've verified everything works.
synto-0.1.0/README.md ADDED
@@ -0,0 +1,155 @@
1
+ # Synto
2
+
3
+ <p align="center">
4
+ <a href="https://github.com/kytmanov/synto/commits/master"><img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/kytmanov/obsidian-llm-wiki-local?style=flat"></a>
5
+ <a href="https://github.com/kytmanov/synto/actions/workflows/ci.yml"><img alt="CI status" src="https://img.shields.io/github/actions/workflow/status/kytmanov/synto/ci.yml?style=flat&amp;label=CI"></a>
6
+ <a href="https://pypi.org/project/synto/"><img alt="PyPI version" src="https://img.shields.io/pypi/v/synto?style=flat"></a>
7
+ </p>
8
+
9
+ **Turn your raw notes into a self-improving, interlinked wiki — powered by a local LLM.**
10
+
11
+ Synto is a knowledge compiler. Point it at any source of expertise and it produces a portable wiki pack any AI agent can install and query.
12
+
13
+
14
+ **Local-first, provider-flexible.** Runs 100% locally with Ollama or LM Studio. Switch to a cloud provider — Groq, OpenRouter, Mistral — when you need more power. Your notes and source material never leave your machine unless you choose.
15
+
16
+ Synto succeeds [obsidian-llm-wiki-local](https://github.com/kytmanov/obsidian-llm-wiki-local) (608 ★, 9k+ downloads) — same proven local pipeline, redesigned for distributable knowledge packs.
17
+
18
+ <p align=center>
19
+ <img width="341" height="463" alt="image" src="https://github.com/user-attachments/assets/b3e13203-bb4a-42a4-a16d-0d4d93404f71" />
20
+ </p>
21
+
22
+ ---
23
+
24
+ ## Why it exists
25
+
26
+ AI agents are only as good as the context you give them. A folder of notes or a raw PDF is not context — it's noise. Synto processes your source material through a local LLM pipeline, extracts concepts, writes cross-linked articles, and exports a structured directory: articles, an index, a concept graph, and agent-readable metadata. The pack installs like a package. Any agent gets a domain expert layer, not a file dump.
27
+
28
+ ---
29
+
30
+ ## Use cases
31
+
32
+ **Architectural reference from a textbook**
33
+
34
+ [Dobryakov took Tanenbaum's *Distributed Systems*](https://www.facebook.com/dobryakov/posts/pfbid021pwPPJZ77KsyWMs3zTdMQEbgpmxgeE9wzoX1SDFE12y5vC3HtdFZV5i5HnS2dUAul), compiled it into a cross-linked wiki, and installed it into Claude/Cursor. Instead of generic suggestions, the AI started reasoning from established distributed systems principles — recommending consistent hashing and two-phase commit instead of "use a shared database." Any technical book, spec, or documentation set becomes a live context layer for your AI.
35
+
36
+ **Karpathy's LLM Wiki**
37
+
38
+ [Andrej Karpathy's](https://karpathy.ai) neural-network series is 20 hours of dense, high-quality material. Compile the transcripts and blog posts into a Synto pack and the content becomes queryable: any agent in your project can explain backpropagation, walk through the attention mechanism, or cite a specific lecture — from the source, not from model weights.
39
+
40
+ **Your own research notes**
41
+
42
+ Works today with Markdown. Drop notes in `raw/`, run `synto run`, and get a cross-linked wiki exported as an agent-ready pack. Expose it via `synto serve` as a local MCP server, or ship the pack directory for any file-aware agent to use.
43
+
44
+ ---
45
+
46
+ ## How it works
47
+
48
+ Three stages, two LLM tiers:
49
+
50
+ 1. **Ingest** — fast model reads each source, extracts concepts and summaries
51
+ 2. **Compile** — heavy model writes one cross-linked article per concept
52
+ 3. **Export** — `synto pack export` produces an agent-ready directory
53
+
54
+ The fast model handles analysis (4B parameters is enough). The heavy model handles writing (14B+ recommended locally, or any cloud model). Both tiers are configurable independently.
55
+
56
+ ---
57
+
58
+ ## Install
59
+
60
+ ```bash
61
+ pip install synto
62
+ # or
63
+ uv tool install synto
64
+ ```
65
+
66
+ For MCP server support:
67
+
68
+ ```bash
69
+ pip install "synto[mcp]"
70
+ ```
71
+
72
+ ---
73
+
74
+ ## Quick start
75
+
76
+ ```bash
77
+ synto setup # configure LLM provider
78
+ synto init ~/my-vault # create vault
79
+
80
+ # add Markdown notes to ~/my-vault/raw/
81
+ synto run --vault ~/my-vault # ingest + compile into wiki/.drafts/
82
+ synto review --vault ~/my-vault # inspect drafts interactively
83
+ # or: synto approve --all --vault ~/my-vault
84
+
85
+ synto pack export --target agents --vault ~/my-vault
86
+ synto serve --vault ~/my-vault # expose as MCP server (requires [mcp])
87
+ ```
88
+
89
+ If you want a one-command flow, use `synto run --auto-approve --vault ~/my-vault`.
90
+ That skips draft review and publishes directly into `wiki/`.
91
+
92
+ ---
93
+
94
+ ## What's in a pack
95
+
96
+ ```
97
+ pack/
98
+ articles/ one Markdown file per concept
99
+ index/INDEX.json machine-readable index with stable article IDs
100
+ agent/
101
+ manifest.json capabilities, pack metadata
102
+ concepts.json concept registry
103
+ sources.json source provenance
104
+ AGENTS.md agent-readable entrypoint
105
+ CLAUDE.md Claude Code context file
106
+ ```
107
+
108
+ Any file-aware agent can read the articles directly. `INDEX.json` enables fast concept lookup without a database. `synto serve` exposes `list_articles`, `read_article`, and `find_concept` as MCP tools.
109
+
110
+ ---
111
+
112
+ ## What ships now
113
+
114
+ - Full ingest → compile → approve pipeline; currently supports Markdown notes and Obsidian vaults
115
+ - `synto pack export --target agents` — portable knowledge pack with INDEX.json and agent metadata
116
+ - `synto serve` — read-only MCP server (`list_articles`, `read_article`, `find_concept`)
117
+ - `synto query` — index-routed Q&A with optional synthesis to `wiki/synthesis/`
118
+ - `synto review` — interactive draft review: approve, reject, edit, or diff before publishing
119
+ - `synto watch` — file watcher: auto-ingest and compile on every save
120
+ - `synto maintain` — wiki health check, stub creation, orphan cleanup
121
+ - `synto eval` — offline structural evaluation (coverage, citation support, link resolution)
122
+ - `synto compare` — A/B model comparison without touching your vault
123
+ - Multi-language: notes are ingested and compiled in their source language
124
+ - 20+ LLM providers supported via OpenAI-compatible API
125
+
126
+ ---
127
+
128
+ ## Data & Privacy
129
+
130
+ - **Local by default.** Ollama and LM Studio process all content on your machine — notes never leave it.
131
+ - **Cloud providers.** If you configure an OpenAI-compatible cloud provider, note content and wiki text are sent to that service. Review their privacy policy before use.
132
+ - **No remote analytics.** Synto does not send usage analytics anywhere. Local runtime and cost metrics stay in your vault database.
133
+ - **Pack exports.** Exported packs include raw notes, sources, wiki articles, queries, and synthesis by default. Review your vault before sharing a pack.
134
+ - **API keys.** Stored in `~/.config/synto/config.toml` (user-owned, not inside the vault). Never commit that file.
135
+
136
+ ---
137
+
138
+ ## Requirements
139
+
140
+ - Python 3.11+
141
+ - An LLM provider: Ollama (local), LM Studio, or any OpenAI-compatible endpoint
142
+
143
+ Recommended local setup: a 4B model for ingest (e.g. Gemma 4), a 14B+ model for compilation (e.g. Qwen 2.5 14B). Works entirely offline.
144
+
145
+ ---
146
+
147
+ ## Migrate from obsidian-llm-wiki-local
148
+
149
+ **Existing obsidian-llm-wiki-local vaults must be migrated first.** Run `migrate-olw` to copy `wiki.toml` and `.olw/` into the current Synto layout before using normal commands.
150
+
151
+ ```bash
152
+ synto migrate-olw --vault ~/my-old-vault
153
+ ```
154
+
155
+ Copies `wiki.toml` → `synto.toml` and `.olw/` → `.synto/`. Notes and articles are untouched. Old files are preserved — delete them once you've verified everything works.