Commit Graph

17 Commits

Author SHA1 Message Date
Arnav 52c9f2bae2 feat(server): run a vault as a Dockerized HTTP + MCP memory service (#185)
Everything else here is local: skills on your machine, a vault on your disk.
This puts a vault behind a URL so an agent elsewhere can search and write it.

One container, one vault, one API key. The vault stays plain markdown on a
mounted volume, so Obsidian still opens it. The container does no LLM work --
search and packing delegate to the existing graphrag/context_pack modules, and
the caller's agent does the thinking.

- obsidian_wiki/server.py: four vault functions, five REST routes and four MCP
  tools as transport over them. Auth is one bearer key; the process refuses to
  start without WIKI_API_KEY unless WIKI_ALLOW_ANONYMOUS=1. Every path is
  resolved inside the vault or refused.
- Dockerfile, docker-compose.yml, .dockerignore, and a ghcr push on v* tags.
- New [server] extra; the core wheel stays dependency-free.
- docs/deployment.md, plus the WIKI_* vars in configuration.md and .env.example.

Requires mcp>=2.0: 2.0 renamed FastMCP to MCPServer, and session_manager only
exists once streamable_http_app() has been called -- a mounted sub-app's own
lifespan is ignored, so it is wired into the FastAPI lifespan by hand.
2026-08-21 14:37:37 -07:00
Arnav ea1633a8d4 fix(tests): isolate CLI subprocess tests, and actually run the suite in CI (#174)
* fix(tests): isolate CLI subprocess tests, and run the suite in CI

12 tests failed on a clean checkout. Neither was a product bug — both were
test-harness isolation gaps, and CI never caught them because the suite was
never run there.

1. Wrong package under test. The 18 test files that spawn
   `python -m obsidian_wiki.cli` each build their own env from
   os.environ.copy() and never set PYTHONPATH, so sys.path[0] was the
   subprocess cwd. Any test running from a temp dir imported whatever
   obsidian_wiki happened to be pip-installed instead of the working tree —
   here a stale build predating `code-understand`, so all 8
   test_code_understand_cli tests died at argparse with "invalid choice",
   plus 4 in test_context_pack_cli. One autouse session fixture in
   conftest.py now pins PYTHONPATH for every helper at once.

2. Developer .env leaking in. test_lint's `_run` and test_context_pack's
   `run_cli` inherited pytest's cwd (the repo), so config resolution walked
   up and found a developer's own untracked .env, pointing the run at their
   real vault instead of the fixture. Both now run from the fake HOME.

Verified the fix isn't masking anything: sabotaging the config resolver makes
the relevant tests fail, and the suite passes in a venv with no obsidian_wiki
installed at all — so PYTHONPATH is genuinely doing the work.

Adds .github/workflows/tests.yml to run pytest on PRs and main. The workflows
only ran setup.sh, wheel publish, and the README-sync checker, so nothing
executed tests/ — the real reason this drifted.

Also drops the stale "RED by design / command does not exist yet" docstring
in test_code_understand_cli.py; the wiring landed in fd30720.

566 passed, 1 skipped (was 554 passed / 12 failed).

* fix(tests): make three test modules importable on Python 3.9

test_batch, test_graph_analysis and test_graphrag annotate helpers with
`int | None` / `list[str] | None` but lack `from __future__ import
annotations`, so 3.9 evaluates the union at import time and collection dies
with "unsupported operand type(s) for |". Every module under obsidian_wiki/
already has the future import; only these three tests were missing it.

Surfaced by the new pytest CI job — the 3.9 leg (the requires-python floor)
failed at collection while 3.12 passed.
2026-08-16 21:14:55 -07:00
Arnav 77d74e0261 feat(config): XDG-style config location, with legacy fallback (#172) (#173)
* feat(config): resolve global config from an XDG-style location (#172)

The global config lived at ~/.obsidian-wiki, which isn't XDG-compliant.
It now resolves to $XDG_CONFIG_HOME/obsidian-wiki (default
~/.config/obsidian-wiki).

Existing installs are unaffected: if ~/.obsidian-wiki is present and the
XDG path is not, the legacy directory is used as-is. No migration is
required, and nothing moves on upgrade. Once the XDG path exists it wins,
so `mv ~/.obsidian-wiki ~/.config/obsidian-wiki` is all a migration takes.

Resolution is implemented identically in Python (cli.py), bash (setup.sh,
scripts/daily-update.sh, scripts/wiki-notify.sh), and the Config
Resolution Protocol that every skill defers to, so vault-scoped state and
named `config.<name>` profiles stay in one place.

* fix(config): stop setup from wiping user-added config keys

`write_config` rewrote the global config with only the three setup-managed
keys, so every `obsidian-wiki setup` — including the one a pip upgrade
prompts for — silently destroyed anything else in the file:
OBSIDIAN_LINK_FORMAT, QMD_WIKI_COLLECTION, WIKI_SKIP_PROJECTS, sync
settings, and comments.

Setup now owns only OBSIDIAN_VAULT_PATH, OBSIDIAN_WIKI_REPO and
OBSIDIAN_WIKI_VERSION, updating those in place and carrying every other
line over untouched. Duplicate definitions of a managed key collapse to
one.

Predates the XDG change (same behavior on main) but is fixed here because
this branch already touches config writing, and the XDG work makes
re-running setup more likely.

Also pins PYTHONPATH in both new test files so they exercise this
checkout rather than whatever obsidian_wiki happens to be installed.
2026-08-16 20:40:09 -07:00
Mike Tsai b7c7b747a3 fix: sync wiki-history-ingest router targets; translate trust ledger for zh-TW (#165)
* docs: design git project manifest identity

* docs: narrow git project identity to safe MVP

* docs: add Git project identity MVP implementation plan

* docs: sync README translations and fix history router references

- README_TW.md: add missing trust-check/trust-record commands and wiki-narrate row
- README.md/README_TW.md: document all 37 skills (table + project structure tree),
  add README_TW.md and package/extension entries to the tree
- wiki-history-ingest: update router targets from 4 to 6 agents (add copilot,
  openclaw) in README.md, README_TW.md, AGENTS.md, SETUP.md,
  copilot-instructions.md, and windsurf rules
2026-08-11 10:35:57 -07:00
Mike Tsai 3288eb648b feat: add vault-backed agent context (#149) 2026-07-26 23:15:52 -07:00
Mike Tsai e8172201fc refactor(ci): make README translation sync advisory, not a merge gate
The readme-sync workflow no longer fails when README.md and
README_TW.md don't change together. Instead, check_readme_sync.py
reports drift: it lists commits that touched README.md after the
last README_TW.md update, plus the pending English diff to translate
and backfill. CI surfaces drift as a warning annotation only.

Claude-Session: https://claude.ai/code/session_01PG9Pz6tcUfgpTHLjq3BT5Q
2026-07-18 10:35:45 +08:00
Mike Tsai dafc90aa4d fix(ci): compare README changes from PR merge base 2026-07-16 01:48:00 +08:00
Mike Tsai d07e8f950e ci: require README translations to change together 2026-07-16 00:48:58 +08:00
Arnav d6dee95ede Add inline vault targeting docs
Document @name named-vault routing across shared skills, bootstrap docs, and README; add regression tests for config-resolution consistency.
2026-06-29 16:24:47 -07:00
Arnav 4b1cd29dc8 refactor(skills): merge data-ingest into wiki-ingest (#84)
data-ingest was effectively wiki-ingest plus a format-detection
preamble — its own process step said "Follow the wiki-ingest skill's
process for creating/updating pages". The split forced users and the
skill router to disambiguate two overlapping ingest skills (a .md
ChatGPT export fit either one).

Fold it in to keep the skill surface small:
- wiki-ingest now handles structured docs AND raw/unstructured text
  (chat exports, Slack/Discord JSON, CSV/JSON, transcripts, logs).
- Added an "Unstructured & conversational sources" section to Step 1
  with format detection, chat-export shapes, and "distill substance,
  not dialogue" guidance carried over from data-ingest.
- Expanded the description to absorb data-ingest's triggers.
- Removed .skills/data-ingest/ and repointed every reference
  (CLAUDE.md/AGENTS.md, README, SETUP, llm-wiki, wiki-status,
  wiki-rebuild, wiki-quick-chat-capture, and the mirror rule files
  for cursor/windsurf/agent/kiro/copilot).
2026-06-11 11:45:36 +05:30
ar9av ab9cd84f63 ci: create GitHub Release on version tag push
Adds contents:write permission and a gh release create step to the
publish job so that each v* tag push produces a GitHub Release with
the built wheel and sdist attached, alongside the existing PyPI publish.
2026-06-08 21:03:58 +05:30
Arnav 46e699b91f Package as a pip-installable PyPI distribution (#72)
* feat(pypi): package obsidian-wiki as a pip-installable distribution (#71)

Add a PyPI package so users can install without cloning the repo.

- pyproject.toml (hatchling, no runtime deps); force-include .skills/ and
  bootstrap files into the wheel under obsidian_wiki/_data/ — repo root stays
  the single source of truth. Force-include .skills/ into the sdist too, or
  hatchling's VCS walker drops it (the committed agent symlink mirrors shadow
  the real .skills/<name> files).
- obsidian_wiki CLI: Python port of setup.sh. `obsidian-wiki setup` writes
  ~/.obsidian-wiki/config and symlinks all skills into every supported agent
  (--copy / --project / --project-only); plus `list` and `info`.
- .github/workflows/publish.yml: build + twine check + skill-bundle assertion,
  publish to PyPI on v* tags via Trusted Publishing (OIDC).
- README + SETUP: pip install instructions; gitignore build artifacts.

* build(pypi): derive version from git tag via hatch-vcs; skip-existing on publish

Align the package version with the repo's CalVer release tags (v2026.05.2 ->
2026.5.2) so tagging a release is the version bump and future release tags
auto-publish the matching version.
2026-05-27 21:21:39 +05:30
Tarek Rached 5304b75979 fix(setup): use relative symlinks for in-repo skill mirrors (#52)
* fix(setup): use relative symlinks for in-repo skill mirrors

setup.sh has been writing absolute symlinks (e.g. /Users/<name>/obsidian-wiki/.skills/...)
into the in-repo skill mirror directories (.agents/, .claude/, .cursor/, .kiro/,
.windsurf/), even though those mirrors are tracked in git as relative symlinks
(../../.skills/<name>). The result: every fresh clone is left with ~160 modified
files immediately after running setup.sh.

This is the same class of bug that 476ac88 ("complete relative symlink migration
across all mirrors and skills") fixed in the committed tree — the migration
updated the symlinks themselves but missed the installer that recreates them.
A contributor running `git add -A` after setup would silently re-commit their
home directory into the public repo, undoing 476ac88.

Add an optional third `mode` argument to install_skills(). When "relative" is
passed, the link target is hardcoded to ../../.skills/<name> (correct for every
in-repo mirror, all of which live at $REPO/<agent-dir>/skills). The global
target dirs under $HOME continue to use absolute paths, which is what they need.

Also corrects the post-install log line — it previously said "Installed global
skills" even for in-repo dirs.

Tested: on a clean checkout, `bash setup.sh && git status` now reports a clean
tree. In-repo links read ../../.skills/<name>; global links under ~/.codex,
~/.gemini, etc. remain absolute.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* setup: harden install_skills + add CI guard

Addresses review feedback on the in-repo symlink fix:

1. Compute the relative-path prefix from target_dir's depth under
   $SCRIPT_DIR instead of hardcoding ../../. The old comment claimed
   "in-repo mirrors are always two levels deep" — true today, silently
   wrong the moment anyone adds a deeper target. Now correct for any
   depth.

2. Validate the mode arg. A typo at the call site (e.g. "rleative")
   previously fell through to absolute and reintroduced the original
   bug. case-statement now exits with a clear message.

3. Guard against relative mode on out-of-repo targets. Bails rather
   than emitting a wrong link.

4. Assert each new symlink resolves to a SKILL.md. Catches future
   path-math mistakes at install time instead of when an agent later
   fails to discover skills.

5. Fold the inline ~/.claude/skills loop into install_skills via a new
   optional subset argument. Removes 17 lines of duplicated
   delete-and-create logic; continues the consolidation that 9377be4
   started.

6. Compress install_skills docstring from 8 lines to 4.

7. Add .github/workflows/setup.yml: runs setup.sh on every PR and
   fails if it modifies a tracked file. Re-runs to verify idempotency.
   This is the missing guard that let the absolute-symlink regression
   reach main in the first place.

Tested locally:
- bad mode → exits 1 with clear error
- relative + /tmp target → exits 1 with clear error
- subset filter installs exactly the named skills
- 4-deep test target (_test_deep/a/b/skills) gets ../../../../.skills/...
- git status clean after install; re-run is idempotent
- ~/.claude/skills contains only wiki-update + wiki-query (absolute)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Tarek Rached <tarek@kisotechnology.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 15:19:45 +05:30
medenor bcff8f24bb feat(history): add unified history ingest router for Claude and Codex 2026-04-12 18:54:43 +02:00
ar9av 700dae4e5b refactor: rename obsidian-* skill references to wiki-* and remove redundant agent-specific skill configuration files 2026-04-06 18:02:43 +05:30
ar9av 1d5053276f feat: add cross-linker and tag-taxonomy skills, update documentation, and refine claude-history-ingest workflow. 2026-04-06 17:05:31 +05:30
ar9av b9cbf01e6d feat: add agent-specific configuration and documentation for the Obsidian wiki skill-based framework 2026-04-06 14:29:57 +05:30