feat: add global vault config fallback via ~/.config/napkin/config.json - #15
Open
cad0p wants to merge 2 commits into
Open
feat: add global vault config fallback via ~/.config/napkin/config.json#15cad0p wants to merge 2 commits into
cad0p wants to merge 2 commits into
Conversation
Add XDG-compliant global config fallback to findVault() resolution. When no .napkin/ directory is found walking up from cwd, check $XDG_CONFIG_HOME/napkin/config.json (defaults to ~/.config/napkin/config.json) for a configured vault path before creating a bare vault. Resolution order: 1. Walk up from cwd for .napkin/ (or .obsidian/.napkin/) 2. Read vault path from ~/.config/napkin/config.json 3. Create bare vault at cwd (last resort) This enables tools like pi-napkin to configure a default vault without per-project .napkin/ directories, and removes the need for framework-specific vault resolution wrappers.
- Fix tilde expansion to only match ~ and ~/ (not ~user) - Resolve relative vault paths relative to config directory (not cwd) - Remove redundant type annotation - Add test isolation for auto-create test (set XDG_CONFIG_HOME) - Add tests for global config fallback, invalid config, and vault resolution
This was referenced May 3, 2026
cad0p
marked this pull request as ready for review
May 4, 2026 00:19
There was a problem hiding this comment.
Pull request overview
This PR adds an XDG-style global config fallback to vault discovery so the CLI/SDK can resolve a default vault from ~/.config/napkin/config.json when no local .napkin directory is found. It extends the existing vault resolution logic and adds tests around the new fallback behavior.
Changes:
- Added global config lookup in
findVault()using$XDG_CONFIG_HOME/napkin/config.jsonwith~expansion and config-relative path resolution. - Updated vault discovery flow so the global config is consulted before auto-creating a bare vault.
- Added tests for XDG fallback behavior and invalid global config handling; lockfile now includes
@types/node.
Reviewed changes
Copilot reviewed 2 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
src/utils/vault.ts |
Adds the global-config fallback path into vault resolution and introduces config parsing helpers. |
src/utils/vault.test.ts |
Adds tests for global fallback behavior and isolates some cases from host XDG_CONFIG_HOME. |
package-lock.json |
Records the new @types/node dev dependency and its transitive type package. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+50
to
+53
| // Fall back to global vault from user config | ||
| const globalVault = getGlobalConfigVault(); | ||
| if (globalVault) { | ||
| return resolveVaultLayout(globalVault, path.dirname(globalVault)); |
Comment on lines
+52
to
+74
| test("falls back to global vault from XDG config", () => { | ||
| const globalDir = fs.mkdtempSync(path.join(os.tmpdir(), "napkin-global-vault-")); | ||
| const configDir = fs.mkdtempSync(path.join(os.tmpdir(), "napkin-global-config-")); | ||
| const napkinConfigDir = path.join(configDir, "napkin"); | ||
| fs.mkdirSync(napkinConfigDir, { recursive: true }); | ||
| // Create a vault in globalDir | ||
| const napkinDir = path.join(globalDir, ".napkin"); | ||
| fs.mkdirSync(path.join(napkinDir, ".obsidian"), { recursive: true }); | ||
| fs.writeFileSync( | ||
| path.join(napkinDir, "config.json"), | ||
| JSON.stringify({ vault: { root: "..", obsidian: "../.obsidian" } }), | ||
| ); | ||
| // Write global config pointing to globalDir | ||
| fs.writeFileSync( | ||
| path.join(napkinConfigDir, "config.json"), | ||
| JSON.stringify({ vault: globalDir }), | ||
| ); | ||
| const origXdg = process.env.XDG_CONFIG_HOME; | ||
| process.env.XDG_CONFIG_HOME = configDir; | ||
| try { | ||
| const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "napkin-fallback-")); | ||
| const result = findVault(tmpDir); | ||
| expect(result.configPath).toBe(path.join(globalDir, ".napkin")); |
Comment on lines
+82
to
+83
| const napkinDir = path.join(vaultPath, ".napkin"); | ||
| if (fs.existsSync(napkinDir)) return napkinDir; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add XDG-compliant global config fallback to
findVault()resolution order. When no.napkin/directory is found walking up from cwd, the CLI now checks $XDG_CONFIG_HOME/napkin/config.json (defaults to ~/.config/napkin/config.json) for a configured vault path before creating a bare vault.Motivation
Agent frameworks like pi-napkin need a way to configure a default vault for projects that don't have a local
.napkin/directory. Currently, pi-napkin has its own vault-resolve.ts that duplicates napkin's walk-up logic and adds a\~/.pi/agent/napkin.jsonfallback. Moving this into napkin-ai eliminates the duplication and gives all agent frameworks a consistent, standard way to configure a default vault.Resolution order
.napkin/(or.obsidian/.napkin/)vaultfield from $XDG_CONFIG_HOME/napkin/config.jsonConfig format
Changes
getGlobalConfigVault()between walk-up loop andcreateBareVault()XDG_CONFIG_HOMEenv var (defaults to~/.config)~and~/...(not\~user)Companion PR