knowledge-gateway 0.7.4__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.
- knowledge_gateway-0.7.4/.github/dependabot.yml +20 -0
- knowledge_gateway-0.7.4/.github/workflows/ci.yml +35 -0
- knowledge_gateway-0.7.4/.github/workflows/release.yml +37 -0
- knowledge_gateway-0.7.4/.gitignore +12 -0
- knowledge_gateway-0.7.4/CHANGELOG.md +163 -0
- knowledge_gateway-0.7.4/LICENSE +21 -0
- knowledge_gateway-0.7.4/PKG-INFO +296 -0
- knowledge_gateway-0.7.4/README.md +258 -0
- knowledge_gateway-0.7.4/conftest.py +2 -0
- knowledge_gateway-0.7.4/deploy/auto-update.sh +11 -0
- knowledge_gateway-0.7.4/deploy/knowledge-gateway-update.service +13 -0
- knowledge_gateway-0.7.4/deploy/knowledge-gateway-update.timer +10 -0
- knowledge_gateway-0.7.4/deploy/knowledge-gateway.service +54 -0
- knowledge_gateway-0.7.4/deploy/tailscale.md +42 -0
- knowledge_gateway-0.7.4/gateway/__init__.py +7 -0
- knowledge_gateway-0.7.4/gateway/__main__.py +3 -0
- knowledge_gateway-0.7.4/gateway/acl.py +62 -0
- knowledge_gateway-0.7.4/gateway/codegraph/__init__.py +15 -0
- knowledge_gateway-0.7.4/gateway/codegraph/build.py +89 -0
- knowledge_gateway-0.7.4/gateway/codegraph/cli.py +37 -0
- knowledge_gateway-0.7.4/gateway/codegraph/extract_ansible.py +183 -0
- knowledge_gateway-0.7.4/gateway/codegraph/extract_python.py +64 -0
- knowledge_gateway-0.7.4/gateway/codegraph/treesitter.py +84 -0
- knowledge_gateway-0.7.4/gateway/config.py +79 -0
- knowledge_gateway-0.7.4/gateway/convert.py +25 -0
- knowledge_gateway-0.7.4/gateway/detect.py +49 -0
- knowledge_gateway-0.7.4/gateway/edits.py +160 -0
- knowledge_gateway-0.7.4/gateway/gitops.py +85 -0
- knowledge_gateway-0.7.4/gateway/graph.py +150 -0
- knowledge_gateway-0.7.4/gateway/links.py +22 -0
- knowledge_gateway-0.7.4/gateway/locks.py +74 -0
- knowledge_gateway-0.7.4/gateway/search.py +94 -0
- knowledge_gateway-0.7.4/gateway/server.py +102 -0
- knowledge_gateway-0.7.4/gateway/tags.py +20 -0
- knowledge_gateway-0.7.4/gateway/tools.py +480 -0
- knowledge_gateway-0.7.4/gateway/vaults.py +147 -0
- knowledge_gateway-0.7.4/gateway/writes.py +31 -0
- knowledge_gateway-0.7.4/pyproject.toml +57 -0
- knowledge_gateway-0.7.4/server.json +19 -0
- knowledge_gateway-0.7.4/tests/conftest.py +32 -0
- knowledge_gateway-0.7.4/tests/test_acl.py +60 -0
- knowledge_gateway-0.7.4/tests/test_attachments.py +49 -0
- knowledge_gateway-0.7.4/tests/test_canvas.py +44 -0
- knowledge_gateway-0.7.4/tests/test_codegraph.py +74 -0
- knowledge_gateway-0.7.4/tests/test_config.py +104 -0
- knowledge_gateway-0.7.4/tests/test_detect.py +61 -0
- knowledge_gateway-0.7.4/tests/test_edits.py +126 -0
- knowledge_gateway-0.7.4/tests/test_gitops.py +53 -0
- knowledge_gateway-0.7.4/tests/test_graph.py +70 -0
- knowledge_gateway-0.7.4/tests/test_local.py +33 -0
- knowledge_gateway-0.7.4/tests/test_locks.py +84 -0
- knowledge_gateway-0.7.4/tests/test_masking.py +41 -0
- knowledge_gateway-0.7.4/tests/test_search.py +23 -0
- knowledge_gateway-0.7.4/tests/test_security.py +39 -0
- knowledge_gateway-0.7.4/tests/test_tools.py +82 -0
- knowledge_gateway-0.7.4/tests/test_vaults.py +112 -0
- knowledge_gateway-0.7.4/tests/test_writes.py +48 -0
- knowledge_gateway-0.7.4/tokens.example.yaml +27 -0
- knowledge_gateway-0.7.4/uv.lock +2234 -0
- knowledge_gateway-0.7.4/vaults.example.yaml +23 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
# Keep the SHA-pinned GitHub Actions and the Python/uv dependency tree current.
|
|
3
|
+
# Dependabot opens small PRs; CI (and branch protection) gate them.
|
|
4
|
+
updates:
|
|
5
|
+
- package-ecosystem: github-actions
|
|
6
|
+
directory: /
|
|
7
|
+
schedule:
|
|
8
|
+
interval: weekly
|
|
9
|
+
commit-message:
|
|
10
|
+
prefix: ci
|
|
11
|
+
groups:
|
|
12
|
+
actions:
|
|
13
|
+
patterns: ["*"]
|
|
14
|
+
|
|
15
|
+
- package-ecosystem: uv
|
|
16
|
+
directory: /
|
|
17
|
+
schedule:
|
|
18
|
+
interval: weekly
|
|
19
|
+
commit-message:
|
|
20
|
+
prefix: deps
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
|
|
3
|
+
# Test on every PR and on pushes to main (so the published default branch and
|
|
4
|
+
# every release tag are known-green). No secrets, no network beyond pip.
|
|
5
|
+
on:
|
|
6
|
+
pull_request:
|
|
7
|
+
push:
|
|
8
|
+
branches: [main]
|
|
9
|
+
tags: ['v*']
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
concurrency:
|
|
15
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
16
|
+
cancel-in-progress: true
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
test:
|
|
20
|
+
runs-on: ubuntu-24.04
|
|
21
|
+
strategy:
|
|
22
|
+
fail-fast: false
|
|
23
|
+
matrix:
|
|
24
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
27
|
+
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
|
|
28
|
+
# The committed lockfile must stay consistent with pyproject.
|
|
29
|
+
- run: uv lock --check
|
|
30
|
+
# search/backlinks/list_tags shell out to ripgrep; install it so those
|
|
31
|
+
# tools and their tests actually run in CI (not silently skipped).
|
|
32
|
+
- run: sudo apt-get update && sudo apt-get install -y ripgrep
|
|
33
|
+
- run: uv venv --python ${{ matrix.python-version }}
|
|
34
|
+
- run: uv pip install -e ".[dev]"
|
|
35
|
+
- run: uv run pytest -q --cov=gateway --cov-report=term-missing
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
# On a vX.Y.Z tag: build, publish a GitHub Release, then publish to PyPI via Trusted
|
|
4
|
+
# Publishing (OIDC, no token). CI (ci.yml) also runs on tags, so a release is only cut
|
|
5
|
+
# from a known-green tree. The GitHub Release runs before PyPI so a not-yet-configured
|
|
6
|
+
# Trusted Publisher cannot block it.
|
|
7
|
+
# One-time setup on pypi.org: add a pending publisher for project `knowledge-gateway` ->
|
|
8
|
+
# owner fszalaj, repo knowledge-gateway, workflow release.yml, environment pypi.
|
|
9
|
+
# (Renamed from `obsidian-gateway`; the old project's publisher no longer matches the dist name.)
|
|
10
|
+
on:
|
|
11
|
+
push:
|
|
12
|
+
tags: ['v*']
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
|
|
17
|
+
concurrency:
|
|
18
|
+
group: release-${{ github.ref }}
|
|
19
|
+
cancel-in-progress: false
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
release:
|
|
23
|
+
runs-on: ubuntu-24.04
|
|
24
|
+
permissions:
|
|
25
|
+
contents: write
|
|
26
|
+
id-token: write
|
|
27
|
+
environment: pypi
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
30
|
+
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
|
|
31
|
+
- run: uv build
|
|
32
|
+
- name: Publish GitHub Release
|
|
33
|
+
env:
|
|
34
|
+
GH_TOKEN: ${{ github.token }}
|
|
35
|
+
run: gh release create "${{ github.ref_name }}" dist/* --title "${{ github.ref_name }}" --generate-notes
|
|
36
|
+
- name: Publish to PyPI (Trusted Publishing)
|
|
37
|
+
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to knowledge-gateway. Consumers track the moving **`stable`** branch
|
|
4
|
+
(`uvx --refresh --from git+...@stable`); each release moves `stable` and auto-propagates on
|
|
5
|
+
next launch (no per-repo re-pin). Every release is also an immutable `vX.Y.Z` tag for
|
|
6
|
+
pinning/audit.
|
|
7
|
+
|
|
8
|
+
## v0.7.4 - 2026-06-27
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- GitHub repo renamed to **`knowledge-gateway`**; all URLs now point to
|
|
12
|
+
`github.com/fszalaj/knowledge-gateway` (the old `obsidian-gateway` URL redirects, so existing
|
|
13
|
+
`@stable` configs keep working). First release cut under the `knowledge-gateway` PyPI Trusted
|
|
14
|
+
Publisher.
|
|
15
|
+
|
|
16
|
+
## v0.7.3 - 2026-06-27
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- Swept the last `obsidian-gateway` references in `gateway/` code: the tempfile-fallback lock-dir
|
|
20
|
+
name and the fcntl-unavailable warning in `gateway/locks.py`, and the `knowledge-gateway-graph`
|
|
21
|
+
CLI docstring. `git grep obsidian-gateway -- gateway/**` is now empty (the name survives only in
|
|
22
|
+
the repo URL, the "formerly" note, and CHANGELOG history).
|
|
23
|
+
|
|
24
|
+
## v0.7.2 - 2026-06-27
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
- Three stray `obsidian-gateway` references missed in the rename (caught by review): the
|
|
28
|
+
`importlib.metadata.version("obsidian-gateway")` lookup in `gateway/__init__.py` (was silently
|
|
29
|
+
falling back to the wrong version), the `knowledge-gateway-graph` CLI `prog` name, and the git
|
|
30
|
+
lock-dir name in `gateway/locks.py`.
|
|
31
|
+
|
|
32
|
+
## v0.7.1 - 2026-06-27
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
- **Dropped the obsidian-gateway back-compat aliases** (pre-1.0 dev): removed the `obsidian-gateway`
|
|
36
|
+
console scripts and renamed the `OBSIDIAN_GATEWAY_*` env vars to `KNOWLEDGE_GATEWAY_*`. The only
|
|
37
|
+
names now are `knowledge-gateway` (the git repo URL stays `.../obsidian-gateway` until the repo is
|
|
38
|
+
renamed). Swept the README + deploy units; renamed the `deploy/*.service`/`.timer` unit files.
|
|
39
|
+
|
|
40
|
+
## v0.7.0 - 2026-06-27
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
- **Renamed `obsidian-gateway` -> `knowledge-gateway`** - it is no longer just a vault wrapper but a
|
|
44
|
+
knowledge gateway (vault + code-graph + convert). The distribution, CLI, MCP display name, and
|
|
45
|
+
`server.json` are now `knowledge-gateway`; the import package stays `gateway`, and the MCP server
|
|
46
|
+
is still keyed `wiki` in client configs.
|
|
47
|
+
- **Back-compat:** the old `obsidian-gateway` / `obsidian-gateway-graph` console scripts remain as
|
|
48
|
+
aliases, and `OBSIDIAN_GATEWAY_VAULT`/`_LOCAL` env vars are still read - existing `uvx --from
|
|
49
|
+
git+...@stable obsidian-gateway` configs keep working during the transition.
|
|
50
|
+
- README repositioned (vault + code-graph + convert), `server.py` instructions list the graph/convert tools.
|
|
51
|
+
|
|
52
|
+
### PyPI
|
|
53
|
+
- Trusted Publishing must be reconfigured for the new project name: add a pending publisher for
|
|
54
|
+
`knowledge-gateway` (owner fszalaj, repo knowledge-gateway, workflow release.yml, environment pypi).
|
|
55
|
+
|
|
56
|
+
## v0.6.0 - 2026-06-27
|
|
57
|
+
|
|
58
|
+
### Added
|
|
59
|
+
- **Code graph (optional `[graph]` / `[graph-all]`)**: a `gateway/codegraph/` package builds a
|
|
60
|
+
NetworkX graph of a source tree - Python (`ast`), Ansible (PyYAML walker: roles/tasks/handlers/
|
|
61
|
+
`include_role`/`import_tasks`/`notify` + `task -> filter plugin` edges), and an optional broad
|
|
62
|
+
tree-sitter pass (JS/TS/Go/Rust/Terraform/bash/PowerShell/...). New read-only MCP tools
|
|
63
|
+
`list_graphs`, `graph_query`, `graph_neighbors`, `god_nodes`, `graph_shortest_path`,
|
|
64
|
+
`graph_stats`; a local-only `graph_build`; and a `obsidian-gateway-graph` CLI.
|
|
65
|
+
- **Document conversion (optional `[convert]`)**: `convert_to_markdown` turns a vault file
|
|
66
|
+
(PDF/Office/image/HTML/...) into Markdown via markitdown.
|
|
67
|
+
|
|
68
|
+
### Security
|
|
69
|
+
- Graph files live in the vault's `.graph/` and are vault-contained (resolved + `is_relative_to`
|
|
70
|
+
the vault, so a symlinked `.graph` cannot escape). Malformed graphs map to `graph_invalid:`.
|
|
71
|
+
Optional deps (networkx, tree-sitter-language-pack, markitdown) are imported lazily, so the core
|
|
72
|
+
gateway requires none of them.
|
|
73
|
+
|
|
74
|
+
## v0.5.1 - 2026-06-16
|
|
75
|
+
|
|
76
|
+
### Changed
|
|
77
|
+
- **Server instructions**: point agents at `_templates/<type>.md` before creating a page
|
|
78
|
+
(the folder is already reachable via `list_notes`/`read_note` - no new tools).
|
|
79
|
+
|
|
80
|
+
### Distribution
|
|
81
|
+
- **PyPI Trusted Publishing**: `release.yml` publishes to PyPI on a `vX.Y.Z` tag via OIDC
|
|
82
|
+
(no token). First PyPI release - consumers can `uvx obsidian-gateway` (alongside `@stable`).
|
|
83
|
+
- **MCP Registry**: `server.json` manifest + a `mcp-name` marker in the README, for listing
|
|
84
|
+
in the official MCP Registry.
|
|
85
|
+
|
|
86
|
+
## v0.5.0 - 2026-06-15
|
|
87
|
+
|
|
88
|
+
### Features (MCP-FEAT)
|
|
89
|
+
- **Attachments**: `list_attachments` + `read_attachment` - read binary vault files (images
|
|
90
|
+
return as an inline `Image`; PDF/audio/video as a `File`), path-guarded, 25 MiB cap.
|
|
91
|
+
- **Obsidian Canvas**: `list_canvases` + `read_canvas` + `write_canvas` - read/write `.canvas`
|
|
92
|
+
JSON (nodes including `group` nodes, edges, `color` fields), so agents can work with groups
|
|
93
|
+
and colors.
|
|
94
|
+
|
|
95
|
+
## v0.4.2 - 2026-06-15
|
|
96
|
+
|
|
97
|
+
### Concurrency (CONC-1)
|
|
98
|
+
- **Per-repo write lock** (`fcntl.flock`): serializes read-modify-write tools
|
|
99
|
+
(`patch_note` / `patch_frontmatter`) and concurrent commits across threads and processes on
|
|
100
|
+
one host, fixing lost-update and mixed-commit races on the shared server. Taken once at the
|
|
101
|
+
tool boundary (the inner commit never re-locks); degrades to a no-op (one-time warning) where
|
|
102
|
+
fcntl/flock is unavailable, rather than failing the write.
|
|
103
|
+
- **Path-scoped commits**: each mutating op commits only its own files (`commit(paths=...)`),
|
|
104
|
+
so a `commit=True` op cannot sweep and mis-attribute a concurrent op's pending change.
|
|
105
|
+
`GIT_LITERAL_PATHSPECS=1` on every git call.
|
|
106
|
+
|
|
107
|
+
## v0.4.1 - 2026-06-15
|
|
108
|
+
|
|
109
|
+
### Docs
|
|
110
|
+
- README rewritten (enterprise style; architecture + `stable`-distribution mermaid diagrams; documents the `stable` "update once" model; AI-setup prompt fixed to `@stable` + `--local`).
|
|
111
|
+
|
|
112
|
+
### Changed
|
|
113
|
+
- The FastMCP server ships an `instructions` prompt describing the tools + Obsidian/git conventions to connecting agents.
|
|
114
|
+
- Reference deploy artifacts for the `@stable` model: `deploy/obsidian-gateway.service` (uv-tool binary) + `deploy/obsidian-gateway-update.{service,timer}` + `deploy/auto-update.sh`.
|
|
115
|
+
|
|
116
|
+
### Dependencies
|
|
117
|
+
- `ruamel.yaml` allowed up to `<0.20` (lock 0.19.1; Dependabot).
|
|
118
|
+
|
|
119
|
+
## v0.4.0 - 2026-06-15
|
|
120
|
+
|
|
121
|
+
### Security
|
|
122
|
+
- Server-mode **error masking**: the HTTP server runs `mask_error_details=True`; the
|
|
123
|
+
gateway's expected client-facing failures surface as `ToolError`, while unexpected OS/git
|
|
124
|
+
errors are hidden from the client.
|
|
125
|
+
|
|
126
|
+
### Features
|
|
127
|
+
- **`--local` vault auto-detect**: `--local` / `OBSIDIAN_GATEWAY_LOCAL` auto-detects the
|
|
128
|
+
cwd's vault (cwd-is-vault, `./wiki`, a real `*-obsidian-vault`, a child with `.obsidian/`),
|
|
129
|
+
so one global codex/antigravity MCP config works in any repo. Explicit `--vault` still
|
|
130
|
+
wins; a bare invocation still runs the HTTP server.
|
|
131
|
+
|
|
132
|
+
### Distribution
|
|
133
|
+
- Introduced the moving **`stable`** branch for "update once" rollout (see the header).
|
|
134
|
+
|
|
135
|
+
## v0.3.0 - 2026-06-15
|
|
136
|
+
|
|
137
|
+
Security, supply-chain, Obsidian-correctness and test coverage. Re-baselines the project
|
|
138
|
+
after the old `v0.2.0` tag was removed; pin this release's commit SHA (or a future PyPI
|
|
139
|
+
`==0.3.0`).
|
|
140
|
+
|
|
141
|
+
### Security & supply chain
|
|
142
|
+
- Runtime deps bounded to the current major (`fastmcp>=3,<4`, `pyyaml>=6,<7`, `ruamel.yaml>=0.18,<0.19`); `uv.lock` committed and CI-verified (`uv lock --check`).
|
|
143
|
+
- `tokens.yaml` is refused at load time if it is group/world-readable.
|
|
144
|
+
- `atomic_write` preserves an existing note's file mode (a new note is 0644, not mkstemp's 0600).
|
|
145
|
+
- systemd unit hardened with seccomp/capability/rlimit sandboxing (safe for a `--user` unit).
|
|
146
|
+
- CI: Node 24 SHA-pinned actions, Python 3.11-3.13 matrix, ripgrep installed, coverage; Dependabot for github-actions + uv.
|
|
147
|
+
|
|
148
|
+
### Features & correctness
|
|
149
|
+
- `backlinks` and `rename_note` match the flat note name **case-insensitively** (Obsidian resolves links that way) and accept a trailing `.md` and `^block`.
|
|
150
|
+
- `read_note` rejects a note over 10 MiB; `query_notes` handles a scalar frontmatter `tags:`.
|
|
151
|
+
- `__version__` is sourced from package metadata.
|
|
152
|
+
|
|
153
|
+
### Tests
|
|
154
|
+
- Coverage 54% -> 82%; added end-to-end tool tests plus rename / gitops / search / security suites.
|
|
155
|
+
|
|
156
|
+
### Planned
|
|
157
|
+
- PyPI Trusted Publishing, so consumers can `uvx obsidian-gateway==<version>` without a git fetch.
|
|
158
|
+
- Server-mode concurrency hardening (per-note locks, path-scoped commits) and error masking.
|
|
159
|
+
|
|
160
|
+
## v0.2.0 - removed
|
|
161
|
+
|
|
162
|
+
Initial release: local stdio + HTTP server, 14 git/Obsidian-aware tools, per-vault ACL,
|
|
163
|
+
path guards. This tag was deleted; use v0.3.0 or later.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Filip Szalaj
|
|
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.
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: knowledge-gateway
|
|
3
|
+
Version: 0.7.4
|
|
4
|
+
Summary: Filesystem/git-native FastMCP knowledge gateway: serve an Obsidian vault over MCP, plus optional code-graph and doc-to-markdown tools (formerly obsidian-gateway)
|
|
5
|
+
Project-URL: Homepage, https://github.com/fszalaj/knowledge-gateway
|
|
6
|
+
Project-URL: Repository, https://github.com/fszalaj/knowledge-gateway
|
|
7
|
+
Project-URL: Issues, https://github.com/fszalaj/knowledge-gateway/issues
|
|
8
|
+
Author: Filip Szalaj
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: ansible,code-graph,fastmcp,git,knowledge-base,knowledge-graph,markdown,mcp,obsidian,tree-sitter,vault
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
16
|
+
Classifier: Topic :: Text Processing :: Markup :: Markdown
|
|
17
|
+
Requires-Python: >=3.11
|
|
18
|
+
Requires-Dist: fastmcp<4,>=3
|
|
19
|
+
Requires-Dist: pyyaml<7,>=6
|
|
20
|
+
Requires-Dist: ruamel-yaml<0.20,>=0.18
|
|
21
|
+
Provides-Extra: all
|
|
22
|
+
Requires-Dist: markitdown>=0.1; extra == 'all'
|
|
23
|
+
Requires-Dist: networkx<4,>=3.4; extra == 'all'
|
|
24
|
+
Requires-Dist: tree-sitter-language-pack>=0.7; extra == 'all'
|
|
25
|
+
Provides-Extra: convert
|
|
26
|
+
Requires-Dist: markitdown>=0.1; extra == 'convert'
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: networkx<4,>=3.4; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
32
|
+
Provides-Extra: graph
|
|
33
|
+
Requires-Dist: networkx<4,>=3.4; extra == 'graph'
|
|
34
|
+
Provides-Extra: graph-all
|
|
35
|
+
Requires-Dist: networkx<4,>=3.4; extra == 'graph-all'
|
|
36
|
+
Requires-Dist: tree-sitter-language-pack>=0.7; extra == 'graph-all'
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
|
|
39
|
+
# knowledge-gateway
|
|
40
|
+
|
|
41
|
+
<!-- mcp-name: io.github.fszalaj/knowledge-gateway -->
|
|
42
|
+
|
|
43
|
+
> Formerly **obsidian-gateway**. Renamed because it is no longer just a vault wrapper - it is a
|
|
44
|
+
> filesystem- and git-native **knowledge gateway** for AI agents. The package, CLI, and MCP
|
|
45
|
+
> display name are now `knowledge-gateway`; the MCP server is still keyed `wiki` in client configs.
|
|
46
|
+
|
|
47
|
+
A single MCP server that gives agents (Claude Code, Codex, Cursor, Gemini, Copilot, Antigravity)
|
|
48
|
+
three capabilities over one connection:
|
|
49
|
+
|
|
50
|
+
- **Vault** - read, search, and **edit** a git-backed Markdown/Obsidian vault (no Obsidian GUI), git as the source of truth.
|
|
51
|
+
- **Code graph** *(optional `[graph]` / `[graph-all]`)* - build and query a code/Ansible knowledge graph of a repo (functions, calls, roles, tasks, handlers, `task -> filter` edges); AST-only, local, no LLM.
|
|
52
|
+
- **Convert** *(optional `[convert]`)* - turn PDF / Office / image / HTML files into Markdown.
|
|
53
|
+
|
|
54
|
+
The vault layer exists because the Obsidian *Local REST API* plugin serves only the one vault open
|
|
55
|
+
in a running desktop instance, writes without a lock (silent lost updates), needs a token in every
|
|
56
|
+
client, and treats git as secondary. This gateway operates on the files directly, with git as the
|
|
57
|
+
system of record - and adds the graph + convert tools the same way: one server, opt-in extras, no
|
|
58
|
+
new servers to wire.
|
|
59
|
+
|
|
60
|
+
## Architecture
|
|
61
|
+
|
|
62
|
+
```mermaid
|
|
63
|
+
flowchart LR
|
|
64
|
+
subgraph clients [Agents]
|
|
65
|
+
A1[Claude Code]
|
|
66
|
+
A2[Codex]
|
|
67
|
+
A3[Antigravity / Cursor]
|
|
68
|
+
end
|
|
69
|
+
A1 --- M(( MCP ))
|
|
70
|
+
A2 --- M
|
|
71
|
+
A3 --- M
|
|
72
|
+
M -->|stdio, per repo, no auth| L[Local gateway]
|
|
73
|
+
M -->|HTTP + bearer + ACL| S[Shared gateway]
|
|
74
|
+
L --> V[/Vault: Markdown files/]
|
|
75
|
+
S --> V
|
|
76
|
+
V <-->|atomic write + scoped commit| G[(git)]
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Both modes run the **same** tool implementation over the **same** path guards; they differ in
|
|
80
|
+
transport, authentication/ACL, vault loading, and error masking.
|
|
81
|
+
|
|
82
|
+
## Two ways to run
|
|
83
|
+
|
|
84
|
+
| | **Local mode** (per repo) | **Shared server** (team) |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| Use when | a repo wants its own vault for its agents | many people/vaults behind one always-on endpoint |
|
|
87
|
+
| Transport | stdio subprocess (launched by `.mcp.json`) | HTTP (put behind Tailscale/HTTPS) |
|
|
88
|
+
| Secrets / tokens | **none** - nothing to generate | per-user bearer tokens (admin-generated) |
|
|
89
|
+
| Trust boundary | local filesystem access you already have | tailnet + HTTPS + per-vault ACL |
|
|
90
|
+
| Obsidian needed | no | no |
|
|
91
|
+
|
|
92
|
+
Most repos want **Local mode**. The shared server is only for a central, always-on team gateway.
|
|
93
|
+
|
|
94
|
+
## Distribution - the `stable` branch ("update once")
|
|
95
|
+
|
|
96
|
+
The gateway ships from one moving branch, so a release reaches every consumer and server
|
|
97
|
+
without re-pinning anything by hand.
|
|
98
|
+
|
|
99
|
+
```mermaid
|
|
100
|
+
flowchart LR
|
|
101
|
+
PR[merge PR to main] --> TAG[tag vX.Y.Z]
|
|
102
|
+
TAG --> MV[move stable -> vX.Y.Z]
|
|
103
|
+
MV --> C["Consumers<br/>uvx --refresh @stable<br/>(updates next session)"]
|
|
104
|
+
MV --> S["Servers<br/>daily uv tool reinstall<br/>(restart if stable moved)"]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
- **Consumers** pin `@stable` with `uvx --refresh` -> the ref is re-fetched on every launch, so
|
|
108
|
+
a new release auto-propagates the next time an agent starts. No per-repo re-pin.
|
|
109
|
+
- **Servers** (long-running) run a pinned `uv tool install @stable` plus a daily job that
|
|
110
|
+
reinstalls + restarts only when `stable` actually moves.
|
|
111
|
+
- Every release is **also** an immutable `vX.Y.Z` tag - pin a tag instead of `stable` when you
|
|
112
|
+
need a frozen, auditable version.
|
|
113
|
+
|
|
114
|
+
> A moving *tag* does not work (uvx caches the resolved commit); a *branch* + `--refresh` does.
|
|
115
|
+
|
|
116
|
+
## Quickstart - local mode (zero secrets)
|
|
117
|
+
|
|
118
|
+
Add this to the repo's `.mcp.json` at the repo root:
|
|
119
|
+
|
|
120
|
+
```jsonc
|
|
121
|
+
{
|
|
122
|
+
"mcpServers": {
|
|
123
|
+
"wiki": {
|
|
124
|
+
"command": "uvx",
|
|
125
|
+
"args": ["--refresh", "--from", "git+https://github.com/fszalaj/knowledge-gateway@stable",
|
|
126
|
+
"knowledge-gateway", "--local"]
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
- `--local` auto-detects the vault in the cwd, in order: the cwd itself if it has `.obsidian/`,
|
|
133
|
+
then `./wiki`, then a single `*-obsidian-vault/`, then a single child dir with `.obsidian/`
|
|
134
|
+
(ambiguous matches error). Pass `--vault ./<dir>` to be explicit.
|
|
135
|
+
- `--refresh` re-fetches `@stable` each launch, so releases auto-apply (adds ~1-2s to start).
|
|
136
|
+
- Commits are scoped to the vault's git subdir and attributed to your own
|
|
137
|
+
`git config user.name/email`. No token: the trust boundary is local filesystem access.
|
|
138
|
+
|
|
139
|
+
Open the repo in your agent, approve the `wiki` server once, done.
|
|
140
|
+
|
|
141
|
+
## Tools
|
|
142
|
+
|
|
143
|
+
| Tool | |
|
|
144
|
+
|---|---|
|
|
145
|
+
| `list_vaults` | vaults reachable here |
|
|
146
|
+
| `list_notes` | Markdown paths in a vault |
|
|
147
|
+
| `read_note` | raw note content |
|
|
148
|
+
| `list_attachments` / `read_attachment` | list / read binary attachments (image -> inline Image, else File) |
|
|
149
|
+
| `list_canvases` / `read_canvas` / `write_canvas` | list / read / write Obsidian Canvas (nodes, groups, colors) |
|
|
150
|
+
| `search` | ripgrep literal/regex full-text |
|
|
151
|
+
| `backlinks` | notes that `[[wikilink]]` to a note |
|
|
152
|
+
| `list_tags` | inline `#tags` with counts |
|
|
153
|
+
| `query_notes` | find notes by frontmatter `type` / `tag` (headless Dataview-lite) |
|
|
154
|
+
| `write_note` | atomic write (+ optional commit) |
|
|
155
|
+
| `patch_note` | insert after a heading or at top/bottom, no full rewrite (+ commit) |
|
|
156
|
+
| `patch_frontmatter` | update YAML frontmatter keys, body intact (+ commit) |
|
|
157
|
+
| `delete_note` | delete a note (+ optional commit) |
|
|
158
|
+
| `rename_note` | rename/move + rewrite inbound flat `[[wikilinks]]` when the name changes (+ optional commit) |
|
|
159
|
+
| `git_status` / `git_commit` | pending changes / commit (subdir-scoped, attributed) |
|
|
160
|
+
| `list_graphs` / `graph_query` / `graph_neighbors` / `god_nodes` / `graph_shortest_path` / `graph_stats` | query a built code graph (optional `[graph]`) |
|
|
161
|
+
| `graph_build` | build a code/Ansible graph from a source tree into `.graph/<name>.json` (local mode only) |
|
|
162
|
+
| `convert_to_markdown` | convert a file (PDF/Office/image/HTML/...) in the vault to Markdown (optional `[convert]`) |
|
|
163
|
+
|
|
164
|
+
Edits are atomic (temp file + `rename`). Every path goes through `safe_note_path`, which blocks
|
|
165
|
+
traversal, symlink escape, hidden/dotfiles, non-`.md` targets, and `.git`/`.obsidian` - a caller
|
|
166
|
+
can never read or write outside the vault's notes.
|
|
167
|
+
|
|
168
|
+
## Code graph and conversion (optional)
|
|
169
|
+
|
|
170
|
+
Two opt-in capabilities, gated behind extras so the core install stays dependency-free:
|
|
171
|
+
|
|
172
|
+
| Extra | Adds |
|
|
173
|
+
|---|---|
|
|
174
|
+
| `[graph]` | Python (`ast`) + Ansible (PyYAML) code graph + the query tools |
|
|
175
|
+
| `[graph-all]` | the above plus a broad tree-sitter pass (JS/TS/Go/Rust/Terraform/bash/PowerShell/...) |
|
|
176
|
+
| `[convert]` | attachment -> Markdown via markitdown |
|
|
177
|
+
|
|
178
|
+
**Build a graph** (AST-only - local, no network, no LLM) where the code lives:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
knowledge-gateway-graph /path/to/code-repo -o /path/to/vault/.graph/myrepo.json
|
|
182
|
+
# in a local-mode session the graph_build tool does the same, writing .graph/<name>.json
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Query it** over MCP with `graph_query` / `graph_neighbors` / `god_nodes` /
|
|
186
|
+
`graph_shortest_path` / `graph_stats`. The graph captures functions/classes/imports/calls and -
|
|
187
|
+
uniquely for Ansible - roles, tasks, handlers, `include_role`/`import_tasks`/`notify`, and
|
|
188
|
+
`task -> filter plugin` edges. Graph files live in the vault's `.graph/`, are vault-contained
|
|
189
|
+
(resolved + checked to stay inside the vault), and are read-only to the gateway - the vault tools
|
|
190
|
+
never depend on them.
|
|
191
|
+
|
|
192
|
+
## Shared server mode
|
|
193
|
+
|
|
194
|
+
Run this only for a central, always-on gateway reachable over the network.
|
|
195
|
+
|
|
196
|
+
**1. Map vaults** - `cp vaults.example.yaml vaults.yaml`, then set `name -> path / repo_root /
|
|
197
|
+
subdir`. `repo_root` + `subdir` pathspec-scope commits to a vault that lives inside a larger repo.
|
|
198
|
+
|
|
199
|
+
**2. Mint a token per user** (the admin does this):
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
cp tokens.example.yaml tokens.yaml
|
|
203
|
+
openssl rand -hex 32 # once PER user -> the key
|
|
204
|
+
chmod 0600 tokens.yaml # refused at load if group/world-readable
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
```yaml
|
|
208
|
+
tokens:
|
|
209
|
+
"8f3c…hex…":
|
|
210
|
+
sub: alice # identity recorded on that user's commits
|
|
211
|
+
vaults: [teamwiki] # the ONLY vaults this token may see/touch
|
|
212
|
+
write: true # false = read-only
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
A token sees only the vaults in its `vaults` list; anything else returns an opaque
|
|
216
|
+
`vault_forbidden`. `vaults.yaml` + `tokens.yaml` are gitignored.
|
|
217
|
+
|
|
218
|
+
**3. Run** - `uv run knowledge-gateway` (127.0.0.1:8765, path `/mcp/`). For a team box, run it as
|
|
219
|
+
a service behind Tailscale Serve - see `deploy/` and *Operate* below.
|
|
220
|
+
|
|
221
|
+
**4. Connect** - the admin shares the token over a password manager (not chat):
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
claude mcp add --transport http --scope project teamwiki \
|
|
225
|
+
https://YOUR-HOST.<tailnet>.ts.net/mcp/ --header "Authorization: Bearer $GW_TOKEN"
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Security model
|
|
229
|
+
|
|
230
|
+
- **No secrets in the repo.** `vaults.yaml` / `tokens.yaml` are gitignored; only
|
|
231
|
+
`*.example.yaml` ship. `tokens.yaml` is refused at load if group/world-readable.
|
|
232
|
+
- **Local mode has no credential surface** - a local stdio subprocess; the trust boundary is
|
|
233
|
+
filesystem access the user already has.
|
|
234
|
+
- **Server mode is defense in depth, not a public endpoint** - tailnet ACL + HTTPS + per-user
|
|
235
|
+
`StaticTokenVerifier` bearer token + per-vault ACL. The bearer layer is a shared secret for
|
|
236
|
+
use **behind a trusted tailnet**; do not expose the server publicly.
|
|
237
|
+
- **Path guards on all note I/O** via `safe_note_path` (traversal, symlink, hidden/dotfiles
|
|
238
|
+
incl. `.env`, non-`.md`, `.git`/`.obsidian`). Search/backlinks/tags are bounded to `*.md`.
|
|
239
|
+
- **Server-mode error masking** - the HTTP server runs `mask_error_details=True`: only the
|
|
240
|
+
gateway's own expected failures surface as `ToolError`; unexpected OS/git errors are hidden.
|
|
241
|
+
Local mode keeps details visible.
|
|
242
|
+
- **Commits are attributed** to the requesting user (server) or the local git identity (local),
|
|
243
|
+
and pathspec-scoped to the vault subdir.
|
|
244
|
+
|
|
245
|
+
## Set it up with an AI
|
|
246
|
+
|
|
247
|
+
Paste this into an agent at a repo's root to wire in local mode:
|
|
248
|
+
|
|
249
|
+
```
|
|
250
|
+
Add the knowledge-gateway to this repo so agents can read/edit our vault over MCP with zero
|
|
251
|
+
tokens:
|
|
252
|
+
1. Create or merge `.mcp.json` at the repo root with an mcpServers."wiki" entry that runs:
|
|
253
|
+
uvx --refresh --from git+https://github.com/fszalaj/knowledge-gateway@stable knowledge-gateway --local
|
|
254
|
+
(`--local` auto-detects the vault: ./wiki, a *-obsidian-vault dir, or a dir with .obsidian/.
|
|
255
|
+
If detection is ambiguous, use `--vault ./<vault dir>` instead of `--local`.)
|
|
256
|
+
2. Verify: `uvx --refresh --from git+https://github.com/fszalaj/knowledge-gateway@stable \
|
|
257
|
+
knowledge-gateway --help` resolves; then in the agent, call list_vaults and read one note.
|
|
258
|
+
Branch + PR, no direct push, no AI attribution.
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
For the shared server, ask your gateway admin for a token, then run the `claude mcp add …` from
|
|
262
|
+
*Connect* above.
|
|
263
|
+
|
|
264
|
+
## Operate (servers)
|
|
265
|
+
|
|
266
|
+
A server runs the `@stable` release as a `uv tool`, with a daily job that reinstalls and
|
|
267
|
+
restarts only when `stable` moved. Reference units are in `deploy/`:
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
uv tool install --from git+https://github.com/fszalaj/knowledge-gateway@stable knowledge-gateway
|
|
271
|
+
# the binary lives in the uv cache, so point config at the live files via env:
|
|
272
|
+
# KNOWLEDGE_GATEWAY_VAULTS=<dir>/vaults.yaml KNOWLEDGE_GATEWAY_TOKENS=<dir>/tokens.yaml
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
- `deploy/knowledge-gateway.service` - the service (systemd `--user`).
|
|
276
|
+
- `deploy/knowledge-gateway-update.{service,timer}` + `deploy/auto-update.sh` - the daily auto-update.
|
|
277
|
+
|
|
278
|
+
Update now instead of waiting for the timer: `uv tool install --reinstall --from
|
|
279
|
+
git+https://github.com/fszalaj/knowledge-gateway@stable knowledge-gateway`, then restart the
|
|
280
|
+
service. Health: `curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8765/mcp/` -> `401`.
|
|
281
|
+
|
|
282
|
+
## Release (maintainers)
|
|
283
|
+
|
|
284
|
+
1. PR -> merge to `main` (CI: `uv lock --check`, pytest matrix).
|
|
285
|
+
2. Bump `pyproject.toml` version + `CHANGELOG.md`.
|
|
286
|
+
3. Tag `vX.Y.Z` and push the tag (the release workflow builds it).
|
|
287
|
+
4. Move `stable`: `git branch -f stable vX.Y.Z && git push --force-with-lease origin stable`.
|
|
288
|
+
|
|
289
|
+
Consumers pick it up next session; servers within a day (or restart now).
|
|
290
|
+
|
|
291
|
+
## Develop
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
uv venv && uv pip install -e ".[dev]"
|
|
295
|
+
uv run pytest # ACL + path guards + edit/frontmatter + detect + masking
|
|
296
|
+
```
|