Files

14 KiB
Raw Permalink Blame History

quicksilver

Persistent memory for Claude via an Obsidian vault over the Local REST API.

Reads and writes notes across Claude/CoWork sessions using direct REST calls — no MCP server required. Each install is self-configuring: on first run the plugin prompts for the vault endpoint, API key, and operator identity, then boots the vault from a bundled scaffold.

Architecture by Jason Stedwell.


Contents


What it does

  • Loads context — at the start of any substantive conversation, reads the operator's preferences, current scope, and recent session logs from the vault (parallel GETs, ~3× faster than sequential)
  • Writes memory — records facts, preferences, decisions, and project state on request or at conversation end
  • Logs sessions — creates a session note after every meaningful conversation so future sessions can pick up where they left off
  • Bootstraps empty vaults — carries the full vault scaffold inside the plugin; can stand up a fresh Obsidian vault from zero with no manual setup
  • Migrates existing vaults — detects older schema versions (including the legacy echo-vault.md marker) and upgrades in place

Requirements

  • Obsidian running with the Local REST API plugin enabled
  • HTTPS access to the Obsidian endpoint from wherever Claude/CoWork sessions run (self-hosted behind a reverse proxy or Tailscale works well)
  • Claude or CoWork (the plugin runs as a Claude skill, not an MCP server)

Install

Quicksilver ships as a single .plugin file. The source is kept private; distribute only the packaged artifact.

  1. Download quicksilver.plugin from this repository's latest commit (or from whoever shared it with you).
  2. In CoWork → Settings → Plugins, click Install Plugin and select the file.
  3. The skill quicksilver becomes available. It will self-configure on first use.

The .plugin file is a ZIP archive with forward-slash separators — do not rebuild it with PowerShell Compress-Archive on Windows, which produces backslash paths that violate the plugin spec. Use Python zipfile instead (see Building from source).


First-run setup

The plugin ships with no endpoint or API key baked in. On first invocation, the skill detects there is no local config file and prompts for:

Prompt Example
API endpoint FQDN https://obsidian.example.com
API key the bearer token from the Local REST API plugin
Operator name Alex Rivera
Operator role Network Engineer

The skill verifies the endpoint (a 200 or 404 on the vault marker path is both fine — 404 just means the vault hasn't been scaffolded yet), then writes a local config file:

~/.quicksilver/quicksilver-config.json       (macOS/Linux)
%USERPROFILE%\.quicksilver\quicksilver-config.json   (Windows)
{
  "schema": 1,
  "endpoint": "https://obsidian.example.com",
  "api_key": "<bearer-token>",
  "operator": { "name": "Alex Rivera", "role": "Network Engineer" },
  "configured_at": "YYYY-MM-DD",
  "verified_at": "YYYY-MM-DD"
}

This file lives in the user home directory — outside the plugin and the vault — so it survives plugin reinstalls and is never committed anywhere. The API key is never written into the vault; the in-vault marker (_agent/quicksilver-vault.md) records only schema version, bootstrap date, and operator name.

On all subsequent sessions the skill reads the config silently and proceeds with no prompts.

Vault bootstrap (automatic)

If the vault marker is missing after credentials are confirmed, the skill runs a full bootstrap: creates the folder tree, seeds templates and anchor files (with the operator's name and role substituted in), and writes the marker last. The vault is fully usable after the first session.


Usage

The skill trigger is quicksilver. It fires automatically at the start of substantive conversations and on explicit phrases:

Intent Example phrases
Load context "pick up where we left off", "anything on X before my meeting?"
Save a fact "remember that", "save this", "note that", "log this decision"
Check memory "what do you know about me", "load my profile", "check my notes"
Capture to inbox "add to my inbox", "save this for later"
Track a project "start tracking this project", "log this as a new project"

What gets written where

What Where How
Quick capture / unsorted inbox/captures/inbox.md POST (append)
Operator preferences _agent/memory/semantic/operator-preferences.md PATCH
Durable facts / patterns _agent/memory/semantic/<slug>.md PUT
Project state projects/<lifecycle>/<slug>.md PUT + PATCH
Decisions (ADR-style) decisions/by-date/YYYY-MM-DD-<slug>.md PUT
Session logs _agent/sessions/YYYY-MM-DD-HHMM-<slug>.md PUT
Daily activity journal/daily/YYYY-MM-DD.md PATCH

All agent-written notes carry agent_written: true and a source_notes list for traceability.

Inbox triage

The inbox (inbox/captures/inbox.md) is the catch-all for unrouted captures. At the start of each substantive session the skill checks for items older than ~7 days and, if any are present, surfaces them once:

"Three captures from last week are still in the inbox — want to route them now or leave them?"

Routing moves each item to its proper home and logs the move to inbox/processing-log/YYYY-MM-DD.md.

Project lifecycle

Projects move through four folders that must stay in sync with the status: frontmatter field:

projects/incubating/  →  projects/active/  →  projects/on-hold/
                                           ↘  projects/archived/

The skill promotes/demotes notes by moving the file and updating status: in the same operation. A file in projects/active/ with status: on-hold is broken state — the skill repairs it on contact.


How it works

Two-layer "is this set up?" detection

Layer File Answers Holds
1. Local config ~/.quicksilver/quicksilver-config.json "Is this install configured?" FQDN + API key + operator identity
2. Vault marker _agent/quicksilver-vault.md (in vault) "Is this vault bootstrapped?" schema_version, bootstrap date, operator name — never the key

The secret lives client-side because you need it before you can reach the vault, and the plugin's safety rules forbid keys in vault notes.

Plugin-as-source-of-truth

All control logic ships inside the plugin under skills/quicksilver/. The vault holds data only — no CLAUDE.md, BOOTSTRAP.md, STRUCTURE.md, or index.md live in it. This means:

  • Portable — point the skill at any empty vault and it stands itself up
  • Updatable — update the plugin, not the vault; existing data is unaffected
  • Repairable — bootstrap is idempotent; run it again to fix missing structure

Write safety

The skill applies three write-safety rules to prevent silent data corruption:

  1. Search-before-create — before writing any new note, searches the whole vault for the slug to catch notes filed in other lifecycle folders or under a different name
  2. Read-before-append — before any POST (which appends), GETs the target file and substring-checks for the exact line about to be written; skips if already present (prevents duplicate entries from retries)
  3. Doc-map-before-PATCH — before the first PATCH to a file in a session, GETs the document map (Accept: application/vnd.olrapi.document-map+json) to confirm the exact heading path; prevents 400 invalid-target errors from stale heading assumptions

Loading order

At session start, five reads fire in parallel:

  1. Vault marker (_agent/quicksilver-vault.md) — "is it set up? which schema?"
  2. Operator preferences (_agent/memory/semantic/operator-preferences.md)
  3. Current context (_agent/context/current-context.md)
  4. Session directory listing → read the ~5 most recent by filename (lex = chrono)
  5. Today's daily note (journal/daily/YYYY-MM-DD.md)

If a project is in scope, two more searches follow (slug + human title) across all four lifecycle folders.


Vault layout

/vault/
├── README.md                       ← thin human signpost (not read for routing)
├── inbox/
│   ├── captures/inbox.md           ← quick captures, date-prefixed lines
│   ├── imports/
│   └── processing-log/
├── journal/
│   ├── daily/  weekly/  monthly/
│   └── templates/
├── projects/
│   ├── active/  incubating/  on-hold/  archived/
│   └── project-template.md
├── areas/                          ← business / personal / learning / systems
├── resources/
│   ├── concepts/  references/  meetings/  source-material/
│   └── people/
├── decisions/
│   └── by-date/                    ← YYYY-MM-DD-<slug>.md (ADR-style)
├── reviews/                        ← weekly / monthly / quarterly / annual
├── archive/
└── _agent/
    ├── quicksilver-vault.md        ← bootstrap marker (plugin-owned)
    ├── context/
    │   └── current-context.md      ← active scope + scope history
    ├── memory/
    │   ├── semantic/               ← operator-preferences.md, durable facts
    │   ├── episodic/               ← event records
    │   └── working/                ← transient, time-boxed
    ├── sessions/                   ← YYYY-MM-DD-HHMM-<slug>.md
    ├── templates/
    └── outputs/
        ├── briefs/  drafts/  summaries/  synthesis/

Plugin source layout

quicksilver.plugin.src/
├── .claude-plugin/plugin.json
├── README.md                       ← plugin-facing README (install & config)
└── skills/quicksilver/
    ├── SKILL.md                    ← operating procedure (authoritative)
    ├── references/
    │   ├── operating-contract.md   ← durable principles + safety rules
    │   ├── bootstrap.md            ← first-run / bootstrap / repair / migration
    │   ├── vault-layout.md         ← canonical layout + frontmatter conventions
    │   ├── api-reference.md        ← REST endpoint patterns + memory routing map
    │   └── session-log-template.md
    └── scaffold/                   ← files bootstrapped verbatim into the vault
        ├── quicksilver-vault.md    ← marker template
        ├── README.vault.md         ← vault README template
        ├── templates/              ← 8 note templates (daily, weekly, project, etc.)
        └── anchors/                ← operator-preferences, current-context, inbox seeds

Building from source

Rebuild quicksilver.plugin from the source directory using Python zipfile. Do not use PowerShell Compress-Archive — it emits backslash separators in the ZIP central directory, which violates the plugin spec.

cd /path/to/quicksilver
python3 - <<'EOF'
import zipfile, pathlib

src = pathlib.Path("quicksilver.plugin.src")
out = pathlib.Path("quicksilver.plugin")

with zipfile.ZipFile(out, "w", zipfile.ZIP_DEFLATED) as zf:
    for f in sorted(src.rglob("*")):
        if f.is_file():
            zf.write(f, f.as_posix())   # forward-slash paths

print(f"Built {out} ({out.stat().st_size:,} bytes, {len(zf.namelist())} files)")
EOF

Version is in .claude-plugin/plugin.json. Bump it before rebuilding.


Security

API key handling

  • The API key is stored only in the local config file (~/.quicksilver/quicksilver-config.json) on the operator's machine
  • It is never written into the vault, committed to git, or logged in session notes
  • The config file should have permissions 0600 (the skill attempts this on write)

Git history

If you fork or clone this repo: the original echo-memory predecessor committed a live API key (241265fbe…) in its history. Rotate that key on the backend regardless of whether it appears in any current source file — it is present in historical commits and should be considered compromised.

Endpoint

The Local REST API should be:

  • Behind HTTPS with a valid TLS certificate (the skill does not pass -k)
  • Not exposed on a public IP without authentication (the API key is the only auth layer)
  • Reachable from wherever Claude/CoWork sessions run — Tailscale or a reverse proxy work well for self-hosted setups

Development notes

Conventions

  • Slugs are kebab-case ASCII, max ~40 chars
  • Session filenames are canonical: YYYY-MM-DD-HHMM-<slug>.md — the HHMM component is required for correct lex-sort (which equals chrono-sort for the session-loading step)
  • All frontmatter dates are YYYY-MM-DD; session created: may use YYYY-MM-DDTHH:mm
  • [[wikilinks]] go only in note bodies (## Related sections), never in frontmatter — YAML parses them as nested lists
  • source_notes frontmatter values are plain relative paths (strings), not wikilinks

Monthly vault health

On the first substantive session of each calendar month, the skill runs a quick health pass and writes findings to reviews/monthly/YYYY-MM-vault-health.md. Checks:

  • Stale active projects (updated: > 30 days → probably on-hold)
  • Unprocessed inbox items (> 14 days)
  • Duplicate slugs across lifecycle folders
  • Key headings still present in frequently-PATCHed files

Schema versioning

The vault marker's schema_version field drives migrations. Current schema: 1. To add a migration, increment the version in scaffold/quicksilver-vault.md and add a versioned step to references/bootstrap.md under Migrations.

Scope switching

When the operator changes focus mid-session, the skill updates _agent/context/current-context.md in three writes: prepend the prior scope to ## Scope History, replace ## Scope with the new one, and bump the updated: frontmatter field. Scope History is trimmed to the last ~10 entries.