# Set up or migrate a vault

The configured workflow uses Obsidian Git for commit, pull, and push. The agent
can work from any folder; the selected vault is independent of caller cwd.
Setup is preview-first and never installs plugin binaries, initializes Git,
configures remotes/authentication, or synchronizes notes as an incidental step.

## 1. Prepare tools and select paths

Install Claude Code or Pi, Python 3.14 or newer, `jq`, Git, and Obsidian. Install the package's Python dependencies (PyYAML and markdown-it-py) in the Python environment used by both clients; see the [README requirements](../README.md#requirements). Ensure `python3 --version` reports the supported version. Setup
scripts ship with the package but are not added to the shell path; these
examples use a repository checkout:

```sh
PLUGIN_DIR="$(pwd -P)" # Run from the checkout root, or use its absolute path.
VAULT="$HOME/Notes/MyVault" # Replace with the intended absolute vault path.
```

Keep the variables in the same shell. Set `OBSIDIAN_AGENT_CONFIG` before preview
if selecting a non-default integration config. Do not guess or retarget a
config that points to a different vault.

## 2. Scaffold a new wiki

For an existing wiki, preserve its contract and entry point and skip to the
configuration step. For a new directory or an empty vault, preview:

```sh
python3 "$PLUGIN_DIR/scripts/bootstrap-vault.py" --vault "$VAULT"
```

Review the proposed directories, file writes, prerequisite diagnostics, and
`planHash`. The scaffold creates missing `.obsidian/`, `wiki/quickstart.md`, and
generated navigation. It does not create/migrate the integration config, enable
plugins, or initialize Git. Obsidian Git can be installed after the scaffold
exists; its absence is reported rather than preventing this first step.

Apply only the reviewed plan:

```sh
python3 "$PLUGIN_DIR/scripts/bootstrap-vault.py" --vault "$VAULT" --apply --confirm 'PASTE_SCAFFOLD_HASH_HERE'
```

Scaffolding leaves existing notes alone and refuses incompatible indexes,
logs, symlinks, or changed inputs. Preserve and review a conflict rather than
deleting a file to force setup through.

## 3. Install and enable Obsidian Git

Open the folder as a vault in Obsidian. Install and enable Obsidian Git from
Settings > Community Plugins. The configuration step checks the installed
manifest and enabled list; it does not download or enable plugin code for you.

Use the owner-controlled workflow to initialize/use the Git repository and set
up identity, remote, and authentication. Inspect existing repositories instead
of automatically creating a nested one. See
[Git setup](../skills/wiki/references/git-setup.md) for ignore rules and privacy.
No personal credentials, remote URL, or identity belongs in shipped templates.

## 4. Preview the configuration profile

Use the explicit configuration option for a new integration or existing-vault
migration:

```sh
python3 "$PLUGIN_DIR/scripts/bootstrap-vault.py" --vault "$VAULT" --configure
```

Review the selected settings differences and ignore additions. Unrelated
configuration values/private preimages are bound to the hash but not dumped in
the preview. Setup must preserve existing notes, vault conventions, and unknown
settings. A minimal settings profile supplies missing values; it does not reset
existing schedules or override an existing choice to disable pushing.

| Setting | Default/proposal |
| --- | --- |
| Agent vault selection | The explicitly selected vault |
| Deprecated agent auto-commit | `false`; the runtime never commits even if a legacy value is `true` |
| Obsidian Git commit/sync | Five-minute debounce after file edits stop |
| Separate commit/push intervals | Disabled; combined commit-and-sync |
| Separate push interval | Zero; this does not disable combined pushing |
| Automatic pull | Eight minutes and on app startup |
| Commit squashing | Proposed `false`, explicitly shown for review |
| Derived state exclusions | Retrieval, lifecycle tracking, and any retained non-Git ownership journal |

Confirm with this plan's exact hash:

```sh
python3 "$PLUGIN_DIR/scripts/bootstrap-vault.py" --vault "$VAULT" --configure --apply --confirm 'PASTE_CONFIGURE_HASH_HERE'
```

Configuration apply refuses unmet plugin prerequisites and stale/concurrent
changes. An open Obsidian instance can rewrite settings; re-preview if inputs
change. Setup does not implicitly pause/reload the app or run commit/pull/push.
A repeated completed configuration preview should propose no changes.

### Selected config and repair

The default config is `~/.config/obsidian-second-brain/properties.json`.
`OBSIDIAN_AGENT_CONFIG` selects another path; `OBSIDIAN_VAULT_PATH` is an
invocation override. Runtime paths may be absolute; internal authored links
remain portable.

Null/missing vault selection requires an explicit choice. A config targeting
another vault is preserved, not silently retargeted. For malformed JSON or
invalid field types, stop the affected wiki writes, propose the exact minimal
repair, and obtain approval of those changes before editing only the selected
config. Preserve unrelated fields and revalidate in the same session. Do not
repeat an unchanged repair proposal or reset other agent/plugin settings.

## 5. Use the wiki from the source workspace

Launch Claude Code or Pi where the main task belongs, including a repository
outside the vault. Use `/obsidian-second-brain:wiki` in Claude Code or `/skill:wiki`
in Pi as the general entry point. The focused skills are namespaced as
`/obsidian-second-brain:wiki-query`, `/obsidian-second-brain:wiki-save`,
`/obsidian-second-brain:wiki-ingest`, `/obsidian-second-brain:wiki-research`, and
`/obsidian-second-brain:wiki-health` in Claude Code; use `/skill:wiki-query`,
`/skill:wiki-save`, `/skill:wiki-ingest`, `/skill:wiki-research`, and
`/skill:wiki-health` in Pi. Query and health are read-only; conversation save requires an explicitly
selected answer or insight; ingest/research do not imply capture or automatic
filing. An explicitly requested local UTF-8 source capture and optional
recoverable batch for larger multi-page edits are available as separate,
reviewed package CLI workflows; neither is required for small edits. The
startup locator identifies the selected vault; the skill reads its existing
contract and relevant pages rather than loading the entire index into every
unrelated conversation. A pre-existing flat wiki remains flat.

Supported file writes are guarded by destination. Normal Markdown pages need
YAML frontmatter with `type`; generated indexes and the lifecycle log are never
agent-authored. Curated sources and settings remain outside normal wiki-write
permissions. Shell writes bypass pre-tool protection, so follow the manual
middleware order in the skill when needed.

The lifecycle validates changed pages and finalizes a writing batch with
navigation, logging, and optional retrieval refresh. An invalid changed page
keeps its batch pending for repair; unrelated historical defects are reported
without preventing normal repairs. Startup and unrelated read-only shutdown
perform no vault writes. Keep one wiki writer session at a time; Pi supports
multiple wiki writes in one parallel tool batch. Navigation reads are blocked
while captured writes are in flight. After an aborted run, Pi recovers missing
tool callbacks at agent end without requiring a session restart; changed bytes
still pass validation before navigation or log publication.

Obsidian Git runs independently. Its enabled settings do not prove that it is
currently loaded, unpaused, authenticated, or successfully pushing. Local wiki
work can continue while the app is closed, but automatic backups cannot. Git
history is recovery support, not a multi-page transaction or write sandbox.

## Read-only CLI search and diagnostics

When `obsidian-second-brain` is on shell `PATH`, use
`obsidian-second-brain search "query terms" --json` or
`obsidian-second-brain doctor --json`. Claude/Pi plugin installation does not
necessarily add the npm bin to `PATH`; if it is missing, invoke the active
package's Node launcher using the package-relative procedure in the
[shared workflow reference](../skills/wiki/references/focused-workflows.md#run-the-package-cli).
That derives an absolute package root from Claude's loaded skill base directory
or Pi's loaded skill path, without relying on caller cwd or guessing an npm cache path.
Both routes resolve the selected vault consistently with the integration.
Search reports structured results, fallback, and freshness without rebuilding
an index. Doctor reports
configuration, dependency, vault, cache-exclusion, lifecycle, and retrieval
status; it does not repair anything. `obsidian-second-brain evidence-report
--json` is an additional read-only report. For direct, hash-bound page reads
without an index, see the [retrieval read/outline commands](retrieval-reads.md). Optional source/claim ledgers are
canonical wiki data and are never migrated or required; the report describes
structure and declared metadata, not factual verification. Use the generated index hierarchy if
search is unavailable or unhelpful. See the
[focused workflow reference](../skills/wiki/references/focused-workflows.md)
for scope boundaries.

## Local retrieval

Use package-owned helpers from any working directory; no scripts are copied
into the vault by new setup:

```sh
python3 "$PLUGIN_DIR/scripts/bm25-index.py" build --vault "$VAULT"
python3 "$PLUGIN_DIR/scripts/retrieve.py" "query terms" --vault "$VAULT"
```

Keep `.vault-meta/retrieval/` and `.vault-meta/lifecycle/` effectively ignored.
Later negations or already-tracked files require review; neither runtime nor
setup silently stages/untracks them. Existing helper copies and ownership
journals remain untouched. The helper-copy provisioner is retired; use the
package-owned commands above.

The lifecycle refreshes the package BM25 cache once per validated finalized
changed batch when retrieval refresh is enabled. It durably records a retry
before clearing changed-page state. Failure/timeout or refused acknowledgment
leaves content/navigation/log published but retrieval pending; Claude and Pi
expose that distinction. A later permitted writer finalization or an explicit
BM25 `build` retries without duplicating navigation/log publication. Unrelated
startup/read-only shutdown, search and doctor do not perform repair.
`features.retrievalRefresh: false` disables automatic builds, not truthful
pending/stale diagnostics. External Obsidian/manual/shell edits remain outside
automatic coverage; use an explicit build after reviewing those changes.
Missing/corrupt cache falls back to generated
navigation. Exact topic-title matches are boosted; ISO-date queries stay lexical
and prioritize matching dated notes, then relevant dated sections. Additional
qualifiers refine dated-section relevance. Read a pending new page by path
rather than assuming search has already indexed it.

Fresh BM25 caches bind all eligible source hashes, so preserved-mtime edits are
also diagnosed. Structured freshness includes `current-by-hash`, `stale`,
`stale-projection`, `pending-content`, `pending-refresh`, and `unknown`; old
unprojected caches require an explicit build, never an implicit search migration.
A current file hash proves byte freshness, not factual currency.

Current lexical/semantic inputs and excerpts mask only clear single-line
strikethrough, leaving code fences, inline/indented code, quotes, frontmatter,
escapes, link/HTML lines and ambiguous Markdown unchanged. Projection preserves
original character coordinates and source hashes. ISO-date queries retain raw
historical lexical content; there is no date-free historical-intent detector or
new flag. Unmarked stale tables and contradictions still need human review.
Never silently edit authored history to improve a score.

Page-level BM25 remains the default and does not require embeddings. Semantic
chunk indexing and hybrid search are separate, explicit opt-ins; both require
Ollama running locally with a model you have already installed. Build the cached
chunk vectors only when requested, then opt in to rank fusion per search:

```sh
python3 <package-dir>/scripts/obsidian-second-brain.py build --vault <vault-root> \
  --semantic-chunks --ollama-model <installed-model>
python3 <package-dir>/scripts/retrieve.py "query terms" --vault <vault-root> \
  --hybrid --ollama-model <installed-model>
```

These are **manual document builds**, not background inference. Exact projected
raw-unit input hashes, verified model digest and a versioned input/options scheme
form a cache namespace. Unchanged inputs can move/repeat without document
inference; grouping/pooling and source mappings are recomputed as needed. Input
vectors and pooled chunks are distinct. The first explicit build of a legacy
pooled cache or changed projection/scheme must populate compatible unit vectors;
old vectors are not relabeled or used for the new current policy. Unreachable
input vectors are pruned only during explicit builds. Counts/characters, build
duration and cache bytes are reported, including local-edit builds.

The derived cache is `.vault-meta/retrieval/chunks.json`; changed, removed, or
otherwise stale pages are excluded as semantic evidence. Hybrid search fuses
semantic chunk candidates with page-level BM25. If an embedding request or
installed-model identity check is unavailable, hybrid search falls back to
page-level BM25; cached vectors stay on disk but are not used until the current
identity can be verified. Compatible unchanged entries can remain on disk during
a service outage; changed entries are deferred. Cached searches send only a
query input and never lazily embed documents or invoke legacy reranking.
ISO-date queries remain lexical. No build or search
command installs a model. A repeatable deterministic boundary-logic comparison is
available with `python3 scripts/benchmark-semantic-retrieval.py`; its hand-authored
vectors are not live model-quality evidence. The separate
[read-only evaluation command](retrieval-evaluation.md) uses reviewed paired
EN/IT intents and temporal evidence on prepared private snapshots. Live runs are
explicit, never CI dependencies, and do not install models or refresh caches.

Embedding operations default to `qwen3-embedding:4b`. Use `--ollama-model` to
select another already-installed model. Old-model semantic vectors are excluded
when selecting a different model; explicitly rebuild with `build --semantic-chunks`
only after the selected model is available. Neither search nor ordinary BM25
builds install models or migrate semantic caches.

Embedding reranking is separate and opt-in:

```sh
ollama pull qwen3-embedding:4b
python3 "$PLUGIN_DIR/scripts/retrieve.py" "query terms" --vault "$VAULT" --rerank
```

Start Ollama and install the model yourself. Reranking sends the query and
candidate content only to a loopback endpoint, ignores proxies, rejects
redirects, and falls back to BM25 when unavailable. Normal retrieval makes no
model/network request. The legacy contextual-prefix helper is a no-op, not
model-augmented indexing.

## Configure the vault agent

The packaged specialist resolves the same vault from any caller cwd. Claude
Code supports `@agent-obsidian-second-brain:wiki-vault`. Pi users can optionally
install `pi-subagents` and run
`/run obsidian-second-brain.wiki-vault "your task"`. The runner is not required
for the skill or lifecycle. Neither specialist pins a model or effort.

### Claude Code

On Claude Code **2.1.292+**, select **Vault agent effort** in the plugin's
`/config` settings, then invoke the explicit delegation entry point:

```text
/obsidian-second-brain:wiki-agent Summarize the selected wiki topic without edits
```

The saved `vault_agent_effort` preference accepts `inherit` (the default), `low`,
`medium`, `high`, `xhigh`, or `max`. Select `low` independently on each host to
request a smaller specialist reasoning budget without changing the parent or
other agents. Available levels depend on the selected model and account policy.
The manifest's option picker requires Claude Code 2.1.271+ to load the plugin;
scoped delegation requires 2.1.292+ for the native `Agent` effort parameter.

The entry point reads the preference in its Markdown body and asks the parent
to pass it as the packaged agent invocation's native `effort` parameter.
`inherit` omits the parameter. This is prompt-directed delegation, not dynamic
effort frontmatter or a forced package default. It preserves the packaged agent
identity, instruction updates, and plugin hooks without creating a local copy.
Direct `@agent-obsidian-second-brain:wiki-vault` mentions and other wiki skills
bypass this entry point and do not apply its preference; ask explicitly for a
native per-invocation effort when using those routes. A resumed agent retains
its original effort, so start a fresh invocation after changing the preference.

`CLAUDE_CODE_EFFORT_LEVEL` overrides both agent frontmatter and per-invocation
effort and also affects the parent. It is not an agent-scoped configuration
method. Policy caps and model limitations can change the applied level; do not
change global settings or copy an agent to work around them. Older clients or
an unavailable effort parameter must produce an explicit limitation instead of
silently substituting session-wide settings.

Requested effort is not proof of effective effort. Inspect the harness's task
information, debug records, or captured request settings where available; report
unknown when diagnostics do not expose it. Static package checks and a scripted
local-provider contract do not prove a real model follows the delegation skill
or that a paid provider accepts the requested level. Subscription-backed checks
remain tracked in [issue #1](https://github.com/soulwaxx/obsidian-second-brain/issues/1).

### Pi

Merge an override into user settings without replacing existing fields:

```json
{
  "subagents": {
    "agentOverrides": {
      "obsidian-second-brain.wiki-vault": {
        "thinking": "low"
      }
    }
  }
}
```

Use the exact canonical key `obsidian-second-brain.wiki-vault`. The native
`pi-subagents` override affects the specialist, not the parent; it keeps the
packaged instructions and does not require a model override. Remove `thinking`
to restore inheritance. Pi's documented levels are `off`, `minimal`, `low`,
`medium`, `high`, `xhigh`, and `max`; support depends on the model/provider.
Per-run selections and project settings can override a user preference, so
inspect the child session's recorded `thinking_level_change` rather than relying
on the runner summary or the model's self-report. An omitted summary value does
not prove thinking is off. No package-owned Pi reasoning setting is added.

Keep one wiki writer; multiple read-only agents can consult the vault concurrently.

## Check a problem

| Symptom | Check |
| --- | --- |
| Missing/ambiguous vault | Inspect the selected config and invocation override; do not create a wiki in caller cwd. |
| Configuration apply refuses plugin readiness | Install/enable the supported Obsidian Git version, then preview again. Scaffold creation can precede this. |
| Existing index/log conflict | Preserve the reported file; review ownership/content before any migration. |
| Invalid integration config | Use the exact, approved selected-config repair; unrelated repository work remains independent. |
| Pending batch does not finalize | Repair/remove its invalid changed pages and retry; do not edit the log/index directly. |
| Exclusion diagnostic | Check effective ignores and already-tracked state; review fixes before applying. |
| Search misses a recent page | Ensure its batch finalized; explicitly rebuild if needed, or use generated navigation. |
| No automatic backup/push | Check the running app, paused automation, credentials, and plugin status; configuration alone is not proof of sync. |

Package verification commands are in the [README](../README.md#verify-the-package).
Other optional Obsidian plugins and appearance choices remain owner-controlled;
see the [plugin guide](../skills/wiki/references/plugins.md) and
[visual guide](../skills/wiki/references/css-snippets.md).
