Important
This repo has moved. It now lives as the foundry/ directory of the wizzlethorpe/vaults monorepo, alongside the CLI, Foundry module, and demo vault under one shared version. This repo is archived (read-only); please open issues and PRs against the monorepo.
Sync an Obsidian vault deployed via vaults-cli into Foundry VTT as journal entries (and optionally Actors / Items). Manifest-based incremental sync, role-based auth, multi-vault support, local image cache.
v0.6.0. Public and multi-role vaults sync end to end. Wikilinks, image embeds, callouts, Bases (cards / table / list), and folder hierarchy all import. Page transclusion (![[Page]]) is dropped silently for now.
- Deploy a vault with
vaults push(Cloudflare Pages). - In Foundry, install this module and open Manage Vaults from the Journal sidebar.
- Click Add Vault, paste your vault URL. The module probes
/_manifest.jsonfornameandauth.required:- Public vault (single-role, no middleware): jumps straight into the per-vault settings dialog. No sign-in.
- Multi-role vault: same, but you can click Authenticate later to elevate above the public tier.
- Click Sync. The module fetches the manifest, diffs against its last-seen state, pulls only changed pages and images, and creates / updates journals.
The bearer token is the only credential, no copy-pasting tokens. Re-sync is incremental; manifest hashes fold in frontmatter, so even a role flip or title rename triggers an update.
Compatible with V13. Verified on V14.
vaults
- Journals. Each vault page becomes a
JournalEntryunder the vault's root folder. Folder structure mirrors the vault. - Wikilinks.
[[Page]]rewrites to@UUID[JournalEntry.<id>]{label}so cross-references stay clickable inside Foundry, including across multiple connected vaults. - Images. Embedded images are downloaded to a per-vault local cache; rewritten
<img src>points at the cached file so journals work offline. - Bases. Cards, table, and list views render natively. Card hrefs become
data-uuidcontent-links, so clicking a card navigates to the linked journal. - Callouts. Standard callouts render with the vault's CSS. Role-gated callouts inside player-visible pages are wrapped in
<section class="secret">, so non-GM viewers don't see them even when they can see the surrounding article.
You can connect any number of vaults to a single Foundry world. Each vault gets its own row in the Manage Vaults dialog, its own root folder, its own image cache, and its own auth state. Removing a vault tears down its journals, derived Actors / Items, and cached images.
Each vault has a dmRole setting that controls journal ownership on import:
- Pages whose role rank is below
dmRoleimport as Observer ownership (visible to all players). - Pages at-or-above
dmRolestay GM-only.
Combined with the <section class="secret"> wrapping, this lets you ship a public-facing journal with DM secrets inline; players see the article, GMs see everything.
Default is empty (everything imports GM-only).
Pages with the right frontmatter spawn linked documents alongside the journal:
---
foundry_base: Compendium.dnd5e.monsters.Actor.bandit
foundry:
system.attributes.hp.value: 22
---The module clones the foundry_base document into the world under a deterministic id derived from the vault + page path, then patches the foundry: overrides on top. Re-syncs update the same Actor / Item, so user edits to non-overridden fields (HP, conditions, equipped items) survive. Page deletion tears down the derived doc too, gated on a vault flag so docs you took over by hand are safe.
All state lives under a single vaults setting, an array of vault entries. The per-vault dialog edits one entry. Legacy single-vault keys (url, token, rootFolder, …) auto-migrate on first load.
Each vault entry tracks: id, label, url, rootFolder, token, role, public, knownRoles, dmRole, lastManifest, lastImageManifest, pendingState.
globalThis.Vaults = {
sync(vaultId, { forceFull = false }), // run a sync for one vault
listVaults(), // [{ id, label, url, role, public }, …]
getVault(id), // full vault entry
openVaultsDialog(), // open Manage Vaults UI
};- Page transclusion (
![[Page]]) is dropped. - Backlinks are not rendered (vaults-cli ships them as a sidebar; Foundry import currently ignores).
- One image cache per vault; large vaults can take a minute on first sync.
- Secret blocks leak through
@Embedon derived Items / Actors. When a page hasfoundry_base, the cloned Item / Actor's description embeds the page via@Embed[JournalEntry.…]. Foundry's text enricher decides whether to hide<section class="secret">content based on the parent document's permissions, not the embedded page's — so a player who owns the Item sheet sees secret blocks even when the underlying journal page would have hidden them. The journal page itself still hides them correctly. This is a Foundry-side limitation of the@Embedenricher; keep DM-only material on dedicated dm-role pages with nofoundry_base.
MIT