Make upload-ticket auth the default remote-agent path by returning complete upload URLs and updating service output/docs. Add validate_upload and preview_upload_metadata for lightweight file checks and exact sha256 duplicate warnings before ingest. Expose version, capability schema, file-index freshness, queue state, and known limitations through get_mcp_capabilities. Validation: python3 -m unittest discover -v; python3 -m compileall obsidian_wiki tests scripts; git diff --check.
15 KiB
Obsidian Wiki — Agent Context
A skill-based framework for building and maintaining an Obsidian knowledge base. No scripts or dependencies — everything is markdown instructions that you execute directly.
Configuration
Resolve config using the Config Resolution Protocol in llm-wiki/SKILL.md:
- Walk up from CWD — look for a
.envfile in the current directory, then each parent, up to$HOME. Stop at the first.envthat containsOBSIDIAN_VAULT_PATH. - Global config — if no local
.envis found, read~/.obsidian-wiki/config. - Prompt setup — if neither exists, tell the user to run
wiki-setup.
The resolved config sets OBSIDIAN_VAULT_PATH (where the wiki lives). It may also set OBSIDIAN_WIKI_REPO (where this repo is cloned) and other optional variables.
After reading config, always read $OBSIDIAN_VAULT_PATH/AGENTS.md if it exists. It contains owner-specific conventions (domain vocabulary, ingest preferences, writing style, project scoping) that override framework defaults for all skills. Apply it for the duration of the session.
Vault Structure
$OBSIDIAN_VAULT_PATH/
├── index.md # Master index — every page listed, always kept current
├── log.md # Chronological activity log (ingests, updates, lints)
├── hot.md # Session hot cache — ~500-word semantic snapshot of recent activity
├── .manifest.json # Tracks every ingested source: path, timestamps, pages produced
├── _meta/
│ ├── taxonomy.md # Controlled tag vocabulary
│ └── *.base # Obsidian Bases dashboard definitions (wiki-dashboard skill)
├── _insights.md # Graph analysis output (hubs, bridges, dead ends)
├── _raw/ # Staging area — drop rough notes here, next ingest promotes them
├── concepts/ # Abstract ideas, patterns, mental models
├── entities/ # Concrete things — people, tools, libraries, companies
├── skills/ # How-to knowledge, techniques, procedures
├── references/ # Factual lookups — specs, APIs, configs
├── synthesis/ # Cross-cutting analysis connecting multiple concepts
├── journal/ # Time-bound entries — daily logs, session notes
└── projects/
└── <project-name>.md # One page per project synced via wiki-update
Every wiki page has required frontmatter: title, category, tags, sources, created, updated. Pages connect via internal links — [[wikilinks]] by default, or standard Markdown links when OBSIDIAN_LINK_FORMAT=markdown is set in config.
Skill Routing
Skills live in .skills/<name>/SKILL.md. Match the user's intent to the right skill:
| User says something like… | Skill |
|---|---|
| "set up my wiki" / "initialize" | wiki-setup |
| "/wiki-history-ingest claude" / "/wiki-history-ingest codex" / "/wiki-history-ingest hermes" / "/wiki-history-ingest pi" | wiki-history-ingest |
| "ingest" / "add this to the wiki" / "process these docs" / "process this export" / "ingest this data" / logs, transcripts / "/ingest-url " / "add this URL" / "ingest this link" / "save this page" | wiki-ingest |
| "import my Claude history" / "mine my conversations" | claude-history-ingest |
| "import my Codex history" / "mine my Codex sessions" | codex-history-ingest |
| "import my Hermes history" / "mine my Hermes memories" / "ingest ~/.hermes" | hermes-history-ingest |
| "import my OpenClaw history" / "mine my OpenClaw sessions" / "ingest ~/.openclaw" | openclaw-history-ingest |
| "import my Copilot history" / "mine my Copilot sessions" / "ingest ~/.copilot" | copilot-history-ingest |
| "import my Pi history" / "mine my Pi sessions" / "ingest ~/.pi" | pi-history-ingest |
| "what's the status" / "what's been ingested" / "show the delta" | wiki-status |
| "wiki insights" / "hubs" / "wiki structure" | wiki-status (insights mode) |
| "what do I know about X" / "find info on Y" / any question | wiki-query |
| "audit" / "lint" / "find broken links" / "wiki health" | wiki-lint |
| "dedup my wiki" / "find duplicate pages" / "merge duplicates" / "identity resolution" / "consolidate my wiki" | wiki-dedup |
| "rebuild" / "start over" / "archive" / "restore" | wiki-rebuild |
| "link my pages" / "cross-reference" / "connect my wiki" | cross-linker |
| "fix my tags" / "normalize tags" / "tag audit" | tag-taxonomy |
| "update wiki" / "sync to wiki" / "save this to my wiki" | wiki-update |
| "export wiki" / "export graph" / "graphml" / "neo4j" / "export to OKF" / "OKF bundle" / "open knowledge format" | wiki-export |
| "import wiki" / "import from export" / "load graph.json" / "import vault" / "import OKF bundle" / "/wiki-import" | wiki-import |
| "color my graph" / "color code obsidian" / "color by tag/category/visibility" | graph-colorize |
| "save this" / "/wiki-capture" / "capture this" / "file this conversation" / "/wiki-capture --quick" / "quick capture" / "capture this finding" / "save this gotcha" / "drop to raw" | wiki-capture |
| "/wiki-research [topic]" / "research X" / "find everything about Y" | wiki-research |
| "create a dashboard" / "vault dashboard" / "show all X as a table" / "dynamic view" | wiki-dashboard |
| "synthesize my wiki" / "find connections" / "what concepts keep coming up together" / "/wiki-synthesize" | wiki-synthesize |
| "create a new skill" | skill-creator |
| "/vault-skill-factory" / "make a skill from my wiki" / "turn these pages into a skill" / "package my notes on X as a skill" / "build a domain-expert skill from my vault" | vault-skill-factory |
| "/wiki-claude [topic]" / "/wiki-codex [topic]" / "/wiki-hermes [topic]" / "/wiki-openclaw [topic]" / "/wiki-copilot [topic]" / "/wiki-pi [topic]" | wiki-agent |
| "/memory-bridge" / "browse codex memory" / "what did codex know about X" / "compare tool memories" / "cross-tool memory" | memory-bridge |
| "/daily-update" / "morning sync" / "refresh the wiki index" / "set up the daily cron" / "install terminal notification" | daily-update |
| "/impl-validator" / "check this implementation" / "validate what you did" / "is this correct?" | impl-validator |
| "/wiki-switch NAME" / "switch to my work wiki" / "switch vault" / "change wiki" / "list my wikis" / "show my vaults" / "create a new vault config" | wiki-switch |
| "/wiki-digest" / "what did I learn this week" / "weekly digest" / "knowledge summary" / "what's new in my wiki" / "summarize my recent learning" / "monthly review" | wiki-digest |
Cross-Project Usage
The main use case: you're working in some other project and want to sync knowledge into your wiki or query it. Two global skills handle this — wiki-update and wiki-query. They work from any directory.
wiki-update (write to wiki)
- Resolve config using the Config Resolution Protocol to get
OBSIDIAN_VAULT_PATH - Scan the current project: README, source structure, git log, package metadata
- Distill what's worth remembering (architecture decisions, patterns, trade-offs — not code listings)
- Write to
$VAULT/projects/<project-name>.md, cross-linking to concept/entity pages as needed - Update
.manifest.json,index.md, andlog.md
On repeat runs, it checks last_commit_synced in .manifest.json and only processes the delta via git log <last_commit>..HEAD.
wiki-query (read from wiki)
- Resolve config using the Config Resolution Protocol to get
OBSIDIAN_VAULT_PATH - Scan titles, tags, and
summary:frontmatter fields first (cheap pass) - Only open page bodies when the index pass can't answer
- Return a synthesized answer with
[[wikilink]]citations
Visibility Tags (optional)
Pages can carry a visibility/ tag to mark their intended reach. This is entirely optional — untagged pages behave exactly as they always have (visible everywhere). The system stays single-vault, single source of truth.
| Tag | Meaning |
|---|---|
| (no tag) | Same as visibility/public — visible in all modes |
visibility/public |
Explicitly public — visible in all modes |
visibility/internal |
Team-only — excluded when querying in filtered mode |
visibility/pii |
Sensitive data — excluded when querying in filtered mode |
Filtered mode is opt-in, triggered by phrases like "public only", "user-facing answer", "no internal content", or "as a user would see it" in a query. Default mode shows everything.
visibility/ tags are system tags — they don't count toward the 5-tag limit and are listed separately from domain/type tags in the taxonomy.
See wiki-query and wiki-export skills for how the filter is applied.
Version Control
- Use Git for every project. If the current project is not already a Git repository, initialize it before making project changes.
- One feature, one commit. Every new feature or meaningful behavior change must be represented by its own focused commit. Do not mix unrelated changes in the same commit.
- Write complete commit messages. Use Conventional Commits (
type(scope): summary) and include a body when useful that explains the reason for the change, user-visible impact, validation performed, and any known follow-up. - Commit only intended files. Before committing, inspect
git statusand stage only files that belong to the current feature or maintenance task.
File Asset Indexing
- Index source files as richly as possible. When writing
_meta/source-registry.jsonlor rebuilding_meta/file-assets.sqlite, preserve structured identifiers instead of relying only on filenames or summaries. - Keep product lookup fields explicit. Carry forward
bjd_part_numbers,competitor_part_numbers,series,pitch,pin_count,product_lines,customers,competitors,standards,business_categories,related_pages, andcatalog_pathswhenever they are known. - Merge, do not overwrite. Automatic identifier extraction may add terms, but it must not discard curated registry metadata. Registry values are the durable source for future index rebuilds and remote MCP lookup.
- Prefer precise identifiers in search ranking. Exact or prefix matches in structured part-number and series fields should rank above incidental filename substrings such as timestamps or archive hashes.
- Keep remote ingest gated. MCP ingest tools are write-capable and must remain disabled unless the service config explicitly enables the
ingesttool group viaOBSIDIAN_MCP_ENABLED_TOOLS=file-assets,ingest,mcp_service.sh tools enable ingest, ormcp_service.sh start --enable-ingest. Uploaded files and direct text notes must stage outside the vault under the MCP runtime root;wiki-ingestis responsible for accepting, archiving, and indexing sources inside the vault. Useingest_text_noteonly for short remote-agent thoughts/notes; it must wrap the text as a temporary markdown upload and then use the fixed/wiki-ingestjob path. Remote agents should usecreate_ingest_upload_ticketand the returnedupload_urlplusX-Obsidian-Wiki-Upload-Tokenfor HTTP multipart uploads; bearer-token uploads remain only for local/admin compatibility. Preferstart_job=false, thenpreview_upload_metadata, thenstart_ingest_jobafter the preview looks correct.validate_uploadandpreview_upload_metadatamay report exact sha256 duplicates, but must not claim fuzzy dedupe. Upload tickets are consumed only by authorizedPOSTuploads, the upload endpoint must enforce configured host/origin restrictions, and oversized request bodies must fail with HTTP413. Do not expose base64 or chunked upload tools in the MCP tool surface. They may launch local OpenCode only through the fixed/wiki-ingestprompt; never expose arbitrary prompt or shell execution through MCP. Remote ingest responses must not expose local runtime paths; internal job records may keep paths for the fixed local prompt. Remote ingest must keep the OpenCode readiness preflight in front of job launch, andcheck_ingest_opencode_readiness(run_smoke_test=true)should stay available for operators to verify that OpenCode can load the projectwiki-ingestskill before accepting uploads. - Keep remote query gated. MCP query tools must remain disabled unless the service config explicitly enables the
querytool group viaOBSIDIAN_MCP_ENABLED_TOOLS=file-assets,query,mcp_service.sh tools enable query, ormcp_service.sh start --enable-query. They may launch local OpenCode only through the fixed/wiki-queryprompt, with no arbitrary prompt or shell execution.ask_wikiis the preferred remote-agent query entrypoint; the asyncstart_wiki_query/status/result tools remain available for long jobs.public_onlydefaults to false, meaning remote answers may use the full local vault visibility; enable the tool group only for trusted clients and setpublic_only=trueper call for filtered user-facing answers. Remote query responses may expose log tails but must not expose local log file paths, and structured fields such asanswer_markdown,citations,warnings, andconfidencemust remain backward-compatible with the legacyanswerfield. - Keep OpenCode model choice server-side. MCP clients must not pass arbitrary model names through ingest/query tools. Configure local defaults in
.runtime/obsidian-wiki-mcp.env: ingest usesOBSIDIAN_MCP_INGEST_OPENCODE_MODEL=openai/gpt-5.5withOBSIDIAN_MCP_INGEST_OPENCODE_VARIANT=high; query usesOBSIDIAN_MCP_QUERY_OPENCODE_MODEL=openai/gpt-5.5withOBSIDIAN_MCP_QUERY_OPENCODE_VARIANT=minimal.
Core Principles
- Compile, don't retrieve. The wiki is pre-compiled knowledge. Update existing pages — don't append or duplicate.
- Track everything. Update
.manifest.jsonafter ingesting,index.md,log.md, andhot.mdafter any write operation. - Connect with
[[wikilinks]]. Every page should link to related pages. This is what makes it a knowledge graph, not a folder of files. - Frontmatter is required. Every wiki page needs:
title,category,tags,sources,created,updated. - Single source of truth. Visibility tags shape how content is surfaced — they don't duplicate or separate it.
- Keep context warm.
hot.mdis a ~500-word semantic snapshot of recent activity. Every write skill updates it so the next session can pick up where the last one left off without crawling the full vault.
Architecture Reference
For the full pattern (three-layer architecture, page templates, project org), read .skills/llm-wiki/SKILL.md.
The vault format is structurally conformant with the Open Knowledge Format (OKF) v0.1 — markdown files with YAML frontmatter, category subfolders, reserved index.md/log.md. wiki-export (OKF mode) and wiki-import are the bridge: they translate between our native frontmatter (title/category/tags/sources/created/updated + summary) and OKF (type/title/description/resource/tags/timestamp), making vaults exchangeable with any OKF tool. The OKF round-trip is lossless; the graph.json round-trip is not.