# Native Pi wiki read tools

The package's Pi extension registers four direct, default-active, read-only tools:
`wiki_search`, `wiki_outline`, `wiki_read`, and `wiki_doctor`. They do not add wiki text to prompts, replace the user's active-tool selection, write vault/config files, build indexes, settle lifecycle captures, or expose evidence-report and write operations. Their annotations are non-destructive, idempotent, read-only, and closed-world hints, not permission enforcement.

Each result has an `operation` and `ok` state, plus the existing CLI response in `payload` when available. Failures can include bounded `code`, `message`, and `processStatus`. A result with `ok: false` is returned as a tool error while retaining structured diagnostics. Search keeps BM25 ranking, read references, fallback, semantic errors, and freshness as reported by the existing retrieval code; empty results, pending refreshes, and fallback are not verified evidence. `wiki_doctor` reports invalid config details in `payload.config.error` without attempting repair.

Vault selection is an optional absolute `vault` input, then `OBSIDIAN_VAULT_PATH`, then the selected configuration's `vaultPath`. Explicit tool inputs must be absolute; invocation/config paths use the CLI's existing resolver, including its caller-cwd behavior for relative selections. The selected config comes from `OBSIDIAN_AGENT_CONFIG` or the existing default path. Default-selected search/read/outline fail with a visible config diagnostic when that config is malformed; a valid invocation override can still select a vault, while doctor continues to report config errors. Explicit-vault `wiki_read` and `wiki_outline` do not load or inspect integration config, matching standalone CLI reads. The Python bridge reuses the CLI config loader and retrieval/read functions where config selection applies. Standalone CLI `read` and `outline` still require `--vault` and remain configuration-independent. The selected package install's `scripts/obsidian-second-brain.mjs` is invoked by absolute path derived from the extension module; it runs the package-relative Python bridge without shell interpolation, npm/PATH lookup, or a second installation.

Search defaults to 10 BM25 results, up to 100, with the existing 4,000-character query limit. Hybrid search is opt-in; only then may it contact the existing bounded loopback-only Ollama endpoint. It never probes or installs a model by default. `semanticError` and fallback remain visible when hybrid retrieval fails.

Outline defaults to 10 entries and supports up to 100. Pagination must carry the returned `expectedHash`. Read requires that hash and exactly one section selector or complete start/end span; raw/current views preserve source coordinates. Reads default to 12,000 characters (maximum 12,000) and return a cursor continuation when truncated. Continuations retain the original selection and hash. Existing hidden, symlink, alias, hardlink, non-regular and reserved-page restrictions remain owned by the Python read implementation.

Native calls have a 30-second deadline, 256 KiB transport-output cap, 8 KiB stderr cap, and 64 KiB model-facing JSON cap. Excessive output is a structured `output-limit` error suggesting a smaller request; evidence is never clipped. Cancellation/timeout terminates the launcher and its process group on verified macOS/Linux platforms. Windows process-tree termination is not verified. Native calls set `PYTHONDONTWRITEBYTECODE=1` and do not modify Python bytecode caches.

## Optional live provider check (not part of deterministic tests)

Do not run this as part of package tests. Obtain explicit approval for the provider/model, effort, turn/time budget, credentials, and possible charges. Use a public-safe synthetic fixture, only the four wiki tools, no retries or provider substitution, and an isolated Pi profile/session. Keep session/settings in memory and model-cache storage isolated. Existing auth must be accessed read-only, without copying credentials or permitting refresh/profile writes; stop if that mechanism or the approved model is unavailable. Disable unrelated resource discovery and provider/agent retries, and enforce both request-count and wall-clock limits in the supervising harness. Before and after, compare byte and mtime snapshots of the synthetic vault/config and owner profile files. Never use a personal vault or permit writes. Persisted transcript tool results may contain JSON text rather than `structuredContent`; validate the actual recorded representation and run snapshot checks even if another assertion fails.

A development smoke check used Pi 1.4.0, `openai/gpt-6.1-sol` at low effort, an eight-turn/120-second limit, and read-only existing OAuth storage. The first trial called all four tools and answered the synthetic question, but its recorder failed before completing hash/snapshot assertions. After separate approval, a corrected trial completed in four model turns (about 20 seconds): search discovered the page, outline supplied the hash/section used by read, doctor reported status separately, and the answer retained the internal-only qualification, unknown external availability, and superseded-plan distinction. Synthetic vault/config bytes and mtimes and the inspected owner profile files were unchanged; fixtures were removed. This is one successful bounded tool-use smoke check, not a comparative quality benchmark or proof of general model adherence. Windows process cleanup and other models/clients were not live-tested.
