Cloud storage is a graveyard. Files go in, but nothing connects them. We wanted Obsidian's magic β bidirectional links, graph visualization β but for R2 buckets.
The Problem
Our AI agents store memories, docs, and context across 17 R2 buckets. Finding anything meant knowing exactly where it was. No discovery. No connections. Just flat file storage.
Obsidian solved this for local notes with [[wikilinks]]. Why couldn't we have the same for cloud storage?
The Solution: R2 Vault
We built a Worker that:
- Parses
[[wikilinks]]from markdown files across buckets - Indexes links in D1 for fast graph queries
- Renders an interactive force-directed graph
- Provides a file browser and viewer
Live at: r2-brain.srvcflo.workers.dev
Architecture
βββββββββββββββ βββββββββββββββ βββββββββββββββ
β Worker ββββββΆβ D1 ββββββΆβ Graph β
β (Parser) β β (Links) β β (UI) β
ββββββββ¬βββββββ βββββββββββββββ βββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β R2 Buckets β
β atlas-docs β devflo-workspace β minte-blog β ... β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Wikilink Syntax
We extended standard wikilinks for cross-bucket references:
[[file]] β same bucket
[[bucket/path/file.md]] β cross-bucket
[[bucket/file|Display]] β aliased link
The Parser
const WIKILINK_REGEX = /\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g;
function parseWikilinks(content, sourceBucket, sourcePath) {
const links = [];
let match;
while ((match = WIKILINK_REGEX.exec(content)) !== null) {
const [, target, alias] = match;
links.push({
source: `${sourceBucket}/${sourcePath}`,
target: resolveTarget(target, sourceBucket),
alias: alias || null
});
}
return links;
}
D1 Schema
CREATE TABLE links (
id INTEGER PRIMARY KEY,
source_bucket TEXT NOT NULL,
source_path TEXT NOT NULL,
target_bucket TEXT NOT NULL,
target_path TEXT NOT NULL,
alias TEXT,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_source ON links(source_bucket, source_path);
CREATE INDEX idx_target ON links(target_bucket, target_path);
Graph Visualization
D3.js force-directed graph with:
- Nodes = files
- Edges = wikilinks
- Colors = buckets
- Size = connection count
Click a node to open the file viewer. Hover for metadata.
Results
- 17 buckets connected
- 936 files indexed
- 165 links discovered
- Sub-second graph rendering
Why This Matters
AI agents need connected knowledge, not isolated files. R2 Vault turns dumb storage into a knowledge graph that agents can traverse.
Next: semantic search via Vectorize, so agents can find related content even without explicit links.
Built with Cloudflare Workers, D1, R2, and D3.js. The second brain for cloud storage.