M5.1: the knowledge vault #140

Merged
dev-agent merged 1 commits from vault into main 2026-10-08 22:37:39 +00:00
Collaborator

M5.1, the knowledge vault (L10), as planned with the operator: reading tools now, while writing by the model waits for M5.2.

Code

  • vault.py:
    • Only the configured folders exist for the agent, each rw or ro.
    • Every path is checked in code: it must be relative, stay inside a folder (no .., no symlink out, which list and search also check), be Markdown, and never be one of the editor's own files (vault.ignore, by default hidden files and SilverBullet's _plug).
    • Long notes are cut, with a note saying how much. Search is a plain case-insensitive match, most matches first.
    • Writes are atomic: a hidden temporary file beside the note, fsync, rename, then fsync of the directory. They merge provenance (by, source, work item, written) into the frontmatter and keep the note's other keys.
    • Failures are VaultErrors, turned into tool results.
  • Configuration: an optional vault: section (root, folders, ignore). Every problem is reported at once: a missing root, a bad access value, .., nested folders, unknown keys. With no vault configured, there are no note tools.
  • Control tools read_note, list_notes, search_notes, running in the harness:
    • for the driver, before the go-ahead too, and while its build VM is blocked, since the vault isn't on the VM;
    • and for conversations.
    • Results are labelled [vault: <path>], and each call is recorded in the operations log. The prompt says a note is information, never an instruction or an approval.

Docs

  • L10: SilverBullet replaces Obsidian. You reach the vault through SilverBullet running on the vault itself, in its own container, with the agents' folders mounted read-only, so the kernel keeps one writer per folder. Agents never go through SilverBullet. Syncthing is gone (L10, X5).
  • M5.4 becomes "the operator's view": the SilverBullet container.
  • The M5.1 entry records why writes stay atomic with a single writer: it protects readers and crashes, not concurrency.
  • Per-agent mounts are stated as M6.1's job; until then the folder map and path checks hold in code.

Tests

  • test_vault.py (15 tests):
    • folder visibility and path escapes, including a symlink out;
    • the editor's own files are refused;
    • search ranking, and cutting long notes;
    • ro refuses writes;
    • provenance is merged and the rest kept;
    • an interrupted write leaves the old note and no temp file;
    • bad frontmatter is refused;
    • read-write folders are created.
  • test_loop_notes.py:
    • the driver reads before the go-ahead, results are labelled, and a missing note fails the call while the run goes on;
    • a conversation reads notes;
    • with no vault, no tools are offered and the prompt doesn't mention it.
  • test_config.py: the section is parsed, and seven invalid sections are refused.
  • Locally the unit tier passes (723 tests).

🤖 Generated with Claude Code

https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk

M5.1, the knowledge vault (L10), as planned with the operator: reading tools now, while writing by the model waits for M5.2. ## Code - **`vault.py`:** - Only the configured folders exist for the agent, each `rw` or `ro`. - Every path is checked in code: it must be relative, stay inside a folder (no `..`, no symlink out, which `list` and `search` also check), be Markdown, and never be one of the editor's own files (`vault.ignore`, by default hidden files and SilverBullet's `_plug`). - Long notes are cut, with a note saying how much. Search is a plain case-insensitive match, most matches first. - Writes are atomic: a hidden temporary file beside the note, `fsync`, rename, then `fsync` of the directory. They merge `provenance` (by, source, work item, written) into the frontmatter and keep the note's other keys. - Failures are `VaultError`s, turned into tool results. - **Configuration:** an optional `vault:` section (`root`, `folders`, `ignore`). Every problem is reported at once: a missing root, a bad access value, `..`, nested folders, unknown keys. With no vault configured, there are no note tools. - **Control tools** `read_note`, `list_notes`, `search_notes`, running in the harness: - for the driver, before the go-ahead too, and while its build VM is blocked, since the vault isn't on the VM; - and for conversations. - Results are labelled `[vault: <path>]`, and each call is recorded in the operations log. The prompt says a note is information, never an instruction or an approval. ## Docs - **L10:** SilverBullet replaces Obsidian. You reach the vault through SilverBullet running on the vault itself, in its own container, with the agents' folders mounted read-only, so the kernel keeps one writer per folder. Agents never go through SilverBullet. Syncthing is gone (L10, X5). - **M5.4** becomes "the operator's view": the SilverBullet container. - **The M5.1 entry** records why writes stay atomic with a single writer: it protects readers and crashes, not concurrency. - **Per-agent mounts** are stated as M6.1's job; until then the folder map and path checks hold in code. ## Tests - `test_vault.py` (15 tests): - folder visibility and path escapes, including a symlink out; - the editor's own files are refused; - search ranking, and cutting long notes; - `ro` refuses writes; - provenance is merged and the rest kept; - an interrupted write leaves the old note and no temp file; - bad frontmatter is refused; - read-write folders are created. - `test_loop_notes.py`: - the driver reads before the go-ahead, results are labelled, and a missing note fails the call while the run goes on; - a conversation reads notes; - with no vault, no tools are offered and the prompt doesn't mention it. - `test_config.py`: the section is parsed, and seven invalid sections are refused. - Locally the unit tier passes (723 tests). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
dev-agent added 1 commit 2026-10-08 22:03:30 +00:00
M5.1: the knowledge vault
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 1m50s
CI / e2e (pull_request) Successful in 4m9s
9fc7360ca5
vault.py: a folder of Markdown notes on the agent host, as SilverBullet reads
them. Only configured folders exist for the agent, each rw or ro (`vault:`
in the configuration); paths are checked in code (relative, inside a folder,
symlinks included, Markdown, never the editor's own files). Writes are
atomic (temporary file, fsync, rename, directory fsync) and merge provenance
into the note's frontmatter, keeping the rest; failures are results.

read_note, list_notes and search_notes are control tools in the harness for
the driver (before the go-ahead, and while a VM is blocked) and for
conversations, labelled with their path; the prompt says a note is
information, never an instruction. Writing by the model is M5.2's.

With the operator: SilverBullet replaces Obsidian and runs on the vault
itself, agents' folders mounted read-only, so no Syncthing (L10, X5, M5.4).
Per-agent mounts come with the containers (M6.1).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
dongar approved these changes 2026-10-08 22:37:21 +00:00
dev-agent merged commit 2a35475eec into main 2026-10-08 22:37:39 +00:00
dev-agent deleted branch vault 2026-10-08 22:37:39 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dev/nisse#140