vaultbase

Documentation

Everything you need to run VaultBase.

Quick Start

# Install
go install github.com/MimirLLC/vaultbase/cmd/vaultbase@latest

# Create and initialize a vault
mkdir -p ~/vault
vaultbase init ~/vault company

# Create your first user
vaultbase user create admin@company.com "Admin" "your-password"
vaultbase role assign company owner admin@company.com
vaultbase permission add company owner folder "/**" "read,write,delete,admin"

# Start
vaultbase serve --vault=company --addr=0.0.0.0:8990

Open http://localhost:8990 and log in with your email and password.

Installation

From source

git clone https://github.com/MimirLLC/vaultbase
cd vaultbase
make build
./vaultbase --help

Go install

go install github.com/MimirLLC/vaultbase/cmd/vaultbase@latest

Docker

docker build -t vaultbase .
docker run -p 8990:8990 -v ./vault:/vault -v ./data:/data vaultbase

Vault Setup

A vault is a directory of markdown files. Initialize it and register with VaultBase:

mkdir -p ~/vault/engineering ~/vault/sales ~/vault/shared ~/vault/users
vaultbase init ~/vault company
# Creates default roles: owner, admin, editor, viewer, agent

VaultBase reads YAML frontmatter for permission matching:

---
tags: [architecture, public]
---
# System Architecture
Your content here...

Identity Stack

VaultBase loads a three-tier identity stack at the top of every agent briefing, so every session starts with the same shared frame: org values, team conventions, and the current user's preferences. Nothing gets re-taught.

Files
  • /vault-context.md — org identity (admin-editable)
  • /groups/<name>/context.md — shared team context
  • /users/<you>/context.md — personal context (self-writable)

On tenant provisioning, /vault-context.md and the owner's personal file are seeded with template prompts. Existing files are never clobbered.

Writing identity from an agent

# MCP: scope can be "org", "team:<group>", or "me"
vault_identity_set({
  scope: "me",
  mode: "append",
  content: "Prefers minimal deps. Owns auth and billing."
})

# Team-level conventions — synced across every group member
vault_identity_set({
  scope: "team:engineering",
  mode: "write",
  content: "# Engineering\n\nTest-first. 80% coverage bar.\n..."
})

What the agent sees in a briefing

L0 — Identity
  Org:   Acme is a B2B compliance platform. Compliance > speed.
  Team:  Engineering — test-first, 80% coverage, no Friday deploys.
  You:   Shane — principal engineer, minimal deps, owns auth + billing.

L1 — Recent decisions, pending outcomes, stale alerts, knowledge gaps...

Missing identity files silently drop from the briefing. RBAC still applies — an agent never sees another user's personal context.

Permissions

Three resource types: folder, file, tag. Each permission has an effect: allow or deny. Deny always wins.

# Folder permissions
vaultbase permission add company eng-editor folder "/engineering/**" "read,write"
vaultbase permission add company viewer folder "/hr/**" "read" --effect=deny

# Tag permissions (frontmatter only)
vaultbase permission add company viewer tag "#public" "read"

# Per-user folders — {user} expands to email prefix
vaultbase permission add company employee folder "/users/{user}/**" "read,write"
# shane@co.com → /users/shane/**
# alice@co.com → /users/alice/**

Resolution order

  1. Explicit file-level permission
  2. Folder-level permission (closest ancestor)
  3. Tag-level permission (frontmatter only)
  4. Vault-level role default
  5. Deny wins at any level

Sync Daemon

Auto-syncs your local vault with the server. No manual push/pull.

# Clone from server
vaultbase clone \
  --server=https://vk.company.com \
  --email=you@company.com \
  --password=pass \
  ~/.vaults/company

# Start daemon
vaultbase sync --path=~/.vaults/company

# Check status
vaultbase status ~/.vaults/company

Offline & Conflicts

Local edits queue to disk the moment they happen. Close your laptop, fly across the country, keep writing — on reconnect the queue drains in order. Never silently drops a change, never blindly last-write-wins.

How the queue works

# Persisted at ~/.config/vaultbase-editor/sync-state.json
{
  "baselines": {
    "/policies/pricing.md": {
      "hash": "a1b2...",
      "content": "..."
    }
  },
  "pending": {
    "/policies/pricing.md": {
      "content": "...your local edit...",
      "baseHash": "a1b2...",
      "baseContent": "...the version you diverged from...",
      "queuedAt": 1712504400000
    }
  }
}

Push protocol

Every write carries the base_hash the client started from. The server compares it against the current server version:

  • base_hash matches → accept, return new hash, baseline advances
  • base_hash stale → reject, return server content + hash for 3-way merge
  • no-op (content already matches) → accept silently
  • force: true → override after client-side merge

3-way merge

On conflict, the client runs a line-level 3-way merge against the captured base. Clean merges push back automatically with force: true. Dirty merges write standard conflict markers to the live file:

<<<<<<< local
Discount authority up to 15% for annual contracts.
||||||| base
Discount authority up to 10% for annual contracts.
=======
Discount authority up to 12% for annual contracts.
>>>>>>> server

Conflict UI

The editor surfaces conflicts in three places:

  • Amber badge in the titlebar with the count of unresolved files
  • Warning dot next to conflicted files in the sidebar file tree
  • An in-editor banner with Keep mine, Use server, and Open server version actions

The original server version is always saved next to the file as <path>.conflict-<ISO>.md so nothing is ever lost. Clearing the markers auto-clears the conflict state on your next save.

Live Events (SSE)

GET /api/events is a Server-Sent Events stream that broadcasts file and trace changes the moment they're accepted. Every subscriber gets an RBAC-filtered view — you only receive events for files your role can read.

Subscribe

# EventSource doesn't support custom headers — pass the token as a query param
const es = new EventSource(
  "https://your-server/api/events?token=vk_..."
);

es.addEventListener("file_updated", (msg) => {
  const ev = JSON.parse(msg.data);
  // { path, hash, actor, time }
});

es.addEventListener("file_deleted", (msg) => { /* ... */ });

Event types

  • connected — sent once after authentication succeeds
  • file_updated — file was written or overwritten
  • file_deleted — file was deleted

Behaviour

  • 25-second heartbeat keeps the connection alive through nginx and other proxies
  • Slow subscribers get events dropped rather than blocking the broadcaster
  • The editor uses SSE for live updates, falling back to 10s polling if the stream drops
  • When an SSE update arrives for a file you have pending edits on, the next drain hits the conflict path proactively

Context Graph

VaultBase captures not just knowledge but the reasoning behind decisions. Every decision an agent or human makes becomes a searchable precedent for future decisions.

Agent reads docs → makes decision → creates trace
                                              ↓
                                      trace links to inputs,
                                      policies, and reasoning
                                              ↓
Next agent faces similar situation → searches precedent
                                   → finds past decisions with outcomes
                                   → makes better-informed decision
                                   → creates new trace → graph grows

Decision Traces

A decision trace is a markdown file that records why a decision was made.

Create a trace (CLI)

vaultbase trace create --vault=company \
  --type=pricing \
  --summary="8% discount for Acme annual renewal" \
  --decision=approved \
  --reasoning="Within agent authority per pricing-v3 §4.2" \
  --input="/sales/acme.md:primary" \
  --input="/policies/pricing-v3.md:governing" \
  --policy="pricing-v3 §4.2: up to 10% for annual" \
  --tag=pricing --tag=discount --tag=acme

Create a trace (MCP)

trace_create({
  type: "pricing",
  summary: "8% discount for Acme annual renewal",
  decision: "approved",
  reasoning: "Within agent authority per pricing-v3 §4.2...",
  inputs: [
    { path: "/sales/acme.md", role: "primary" },
    { path: "/policies/pricing-v3.md", role: "governing" }
  ],
  policies_applied: ["pricing-v3 §4.2: up to 10% for annual"],
  tags: ["pricing", "discount", "acme"]
})

Search precedent

# CLI
vaultbase trace precedent --type=pricing "annual contract discount"

# MCP
trace_find_precedent({ type: "pricing", context: "annual discount" })

Record outcomes

vaultbase trace outcome dt-2026-04-05-777 \
  --status=successful \
  --notes="Contract renewed for 2 years. Revenue maintained."

Intelligence Features

Agent Briefings

Get a context packet before starting any task. Returns recent decisions, pending outcomes, knowledge gaps, and stale document alerts.

vaultbase briefing --vault=company --task="pricing request"
# or MCP: vault_briefing({ task_context: "pricing request" })
Consistency Checking

When you create a decision trace, VaultBase automatically checks for contradictory prior decisions and returns warnings. The trace is still created — the warning is informational.

Knowledge Gaps

VaultBase tracks searches that return zero results. Over time, patterns emerge: "refund policy" searched 7 times with no results = missing document.

vaultbase gaps --vault=company
# or MCP: vault_gaps()
Revision Tracking

Track revision levels for policies, ISO procedures, and controlled documents. Decision traces referencing outdated revisions are flagged.

vaultbase revision record /policies/pricing.md --vault=company --rev=v4 \
  --summary="Increased discount authority"

vaultbase revision stale dt-2026-04-05-777
# → Is stale: pricing.md revised to v4 since this decision

AI Agent Access

Tier 1 — Local files

Agent runs in a synced vault directory. Reads/writes files directly. Zero overhead. The agent doesn't need to know VaultBase exists.

Tier 2 — Skill files

Static .skill.md bundles scoped to a role. Drop into CLAUDE.md includes. Low context cost.

Tier 3 — MCP server

Dynamic search and queries. Permission-scoped. For remote agents or large vaults where local files are impractical.

MCP Server

Vault content (read-only)

  • vault_list — list files (permission-filtered)
  • vault_read — read a file
  • vault_search — full-text search (FTS5 BM25)
  • vault_query — query by tag or path pattern

Context graph

  • trace_create — record a decision with inputs, policies, reasoning
  • trace_find_precedent — find similar past decisions
  • trace_update_outcome — record what happened after a decision
  • trace_search — search traces by type, tag, actor, outcome

Intelligence & briefings

  • vault_briefing — identity stack + recent activity + gaps + stale alerts
  • vault_gaps — queries that returned zero results, ranked by frequency
  • vault_doc_revision — record a new document revision
  • vault_revision_history — full revision history for a document
  • vault_stale_check — flag traces citing outdated revisions

Identity (L0 context)

  • vault_identity_set — write/append an identity file at scope org, team:<group>, or me

Knowledge write-back

  • vault_learn — write a new learning, insight, runbook, or FAQ
  • vault_update_doc — update an existing document with reason (auto-records revision)
  • vault_index — re-index the vault for search

Admin

  • admin_list_users, admin_create_user
  • admin_list_roles, admin_create_role, admin_assign_role
  • admin_add_permission, admin_list_permissions
  • admin_create_apikey, admin_audit_log

Configuration

{
  "mcpServers": {
    "vaultbase": {
      "url": "http://your-server:8990/mcp",
      "headers": {
        "Authorization": "Bearer vk_your_api_key"
      }
    }
  }
}

Skill Files

vaultbase pull-skills --vault=company --role=engineering-agent -o ./skills/

# Output: engineering-agent.skill.md
# Contains only files the role can read
# Include in CLAUDE.md or Cursor rules

Knowledge Write-Back

Agents don't just read from the vault — they write back to it. Every conversation that produces knowledge should be captured.

Write a learning

# MCP: write new knowledge
vault_learn({
  path: "/learnings/pricing-insights.md",
  content: "# Pricing Insights\n\nMost customers accept 5-8%...",
  category: "insight",
  source: "Q1 pricing review"
})

Update an existing document

# MCP: update with correction
vault_update_doc({
  path: "/policies/pricing.md",
  content: "...updated content...",
  reason: "Agent authority increased from 10% to 15%"
})

Categories: learning, correction, insight, runbook, faq. Write mode: write (new/overwrite) or append (add to existing).

Docker

docker build -t vaultbase .

docker run -d \
  --name vaultbase \
  -p 8990:8990 \
  -v /path/to/vault:/vault \
  -v /path/to/data:/data \
  vaultbase

# Initialize inside container
docker exec vaultbase vaultbase init /vault company --db=/data/vaultbase.db
docker exec vaultbase vaultbase user create admin@co.com "Admin" "pass" --db=/data/vaultbase.db

CLI Reference

vaultbase init <path> <name>             Initialize a vault
vaultbase serve --vault=<name>           Start the server
vaultbase login <email> <password>       Get an API key

vaultbase user create/list               Manage users
vaultbase role list/assign/revoke        Manage roles
vaultbase permission add/list            Manage permissions
vaultbase apikey create/list             Manage API keys

vaultbase vault list                     List vaults
vaultbase vault files --vault=<name>     List files
vaultbase vault read --vault=<name>      Read a file
vaultbase vault search --vault=<name>    Search content
vaultbase vault query --vault=<name>     Query by tag/path

vaultbase pull-skills                    Generate skill files

vaultbase clone --server=<url>           Clone vault
vaultbase sync --path=<path>             Start sync daemon
vaultbase status [path]                  Sync status