If you've used Obsidian, you know the magic of wikilinks โ€” type [[filename]] and suddenly your notes are connected. What if you could have that for cloud storage?

This week we built R2 Vault โ€” an Obsidian-style knowledge graph that runs entirely on Cloudflare's edge, turning scattered R2 buckets into a connected second brain.

The Problem: Islands of Information

When you have multiple AI agents working on different domains (development, security, social media, tutoring), each accumulates its own context and memory. We were storing markdown files across several R2 buckets:

  • A collaboration bucket for cross-agent handoffs
  • Individual workspace buckets per agent
  • Project documentation scattered across repos

The files would reference each other informally ("see the protocol doc" or "check the skills audit"), but there was no way to actually navigate those relationships. Classic information silo problem.

Obsidian solved this for local files. We wanted the same for cloud storage.

R2 Vault brings the Obsidian workflow to R2:

  1. Parses wikilinks in the format [[bucket/path/to/file.md]]
  2. Indexes relationships into a D1 database (Cloudflare's edge SQLite)
  3. Exposes a graph API for visualization and queries
  4. Resolves backlinks so you can see what references any given file

The parser handles the same patterns you'd use in Obsidian:

// Standard link
[[atlas-collab-pub/protocol.md]]

// Link with display text (pipe syntax)
[[atlas-collab-pub/protocol.md|The Protocol]]

// Relative links (within same bucket)
[[./related-doc.md]]

// Cross-bucket references
[[devflo-workspace-prod/memory/2026-02-24.md]]

The parser extracts source file, target file, link text, and line number โ€” everything needed to build a proper graph structure.

The Schema

The D1 schema is intentionally simple:

-- Nodes (files)
CREATE TABLE files (
  id INTEGER PRIMARY KEY,
  bucket TEXT NOT NULL,
  path TEXT NOT NULL,
  title TEXT,
  last_indexed INTEGER,
  UNIQUE(bucket, path)
);

-- Edges (links between files)
CREATE TABLE links (
  id INTEGER PRIMARY KEY,
  source_id INTEGER REFERENCES files(id),
  target_bucket TEXT NOT NULL,
  target_path TEXT NOT NULL,
  display_text TEXT,
  line_number INTEGER
);

Views provide convenient access patterns:

  • v_graph_nodes โ€” Files with link counts (in/out)
  • v_graph_edges โ€” Resolved links with source/target info
  • v_backlinks โ€” What files link TO a given file
  • v_broken_links โ€” Links pointing to non-existent files

That last one is gold for maintenance. Obsidian users know the pain of broken internal links โ€” now we catch them automatically.

The API Surface

R2 Vault exposes REST endpoints:

Endpoint Purpose
POST /api/index Trigger full re-index of all buckets
GET /api/graph Full graph data for visualization
GET /api/file/:bucket/:path Single file with its links
GET /api/backlinks/:bucket/:path What references this file
GET /api/search?q=term Full-text search across indexed files
GET /api/stats Index statistics

Indexing Strategy

Full re-indexing isn't cheap, so we track last_indexed timestamps and support incremental updates. The indexer:

  1. Lists objects in each configured R2 bucket
  2. Filters to .md and .json files
  3. Fetches content and parses for wikilinks
  4. Upserts file records and link relationships
  5. Prunes orphaned links from deleted files

One gotcha: R2's list operation is paginated (max 1000 objects per call). The indexer handles pagination correctly, which seems obvious but bit us during initial testing.

Graph Visualization: The Obsidian Experience

The graph view is what makes Obsidian magical. We're using D3.js for a force-directed layout:

  • Nodes = files (sized by connection count)
  • Edges = wikilinks between files
  • Colors = different buckets
  • Clusters = densely connected file groups

Click a node to see its content and backlinks. Zoom and pan to explore. It's not as polished as Obsidian's graph yet, but it's functional.

Wildlife Research: An Unexpected Use Case

While building R2 Vault, we also shipped a wildlife research pipeline that demonstrates the multi-agent coordination pattern.

The Setup

We have a trail camera in southeast Oklahoma that syncs photos to an API. A dashboard Worker pulls those events into D1 with full metadata: species, weather conditions, moon phase, barometric pressure.

Two Agents, One Data Source

The same camera data feeds two different agents:

  1. Security Agent (6:00 AM): Looks for unknown vehicles, suspicious activity, unfamiliar people. Posts to a security channel.

  2. Wildlife Researcher (6:15 AM): Analyzes animal behavior. Identifies species, tracks individual deer by antler configuration, correlates activity with weather patterns.

Same data, different lenses. The 15-minute offset ensures they don't step on each other's API calls.

Lessons from the Week

1. Workers Hate new Function()

We tried using Handlebars.js for template rendering. Cloudflare's runtime blocks dynamic code evaluation for security reasons.

The fix: Replace Handlebars with simple regex interpolation.

// Before (broken)
const template = Handlebars.compile(source);

// After (works)
const html = source.replace(/\{\{(\w+)\}\}/g, (_, key) => data[key] ?? '');

2. Incremental > Batch for Indexing

Our first indexer did full re-indexes on every run. With thousands of files across multiple buckets, that's slow. Tracking change timestamps and doing incremental updates cut indexing time by 80%.

3. Graph Visualization is Its Own Project

We have the API. We have the data. Making it look good in a browser is a whole separate challenge. Force-directed layouts, zoom/pan, node clustering โ€” there's a reason Obsidian spent years on their graph view.

What's Next for R2 Vault

  1. Auto-linking suggestions โ€” Surface files that mention similar concepts but aren't explicitly linked
  2. Embedding search โ€” Vector similarity for semantic search, not just keywords
  3. Daily notes โ€” Auto-create timestamped notes like Obsidian's daily notes plugin
  4. Publish to web โ€” One-click publish selected files as a static site

The knowledge graph pattern generalizes well. Any time you have scattered documentation, wikilinks + a graph database give you discoverability for free.


Obsidian changed how we think about personal knowledge management. R2 Vault brings that same connected thinking to cloud storage โ€” because your AI agents deserve a second brain too.

Ship it. Link it. Graph it.