---
name: set-vault-root
description: Prompt-driven setter for .planning/config.json vault.root with SPEC §18.10 convention default
applies_to_agents: []   # human-invoked only (slash command surface)
---

# Skill: set-vault-root

Set or change the Obsidian vault root for the current project. Persists to
`.planning/config.json` under `vault.root` (project scope — never touches
`~/.claude/get-magic-done/config.json`).

## When activated

- `/gmd:set-vault-root` slash command (primary surface)
- `/gmd:update` workflow when `components.obsidian` flips disabled → enabled
- Installer (`bin/install.js`) AFTER the Optional Components checklist when
  the user ticks Obsidian — the installer calls `setVaultRoot` directly via
  the same shared helper, so behavior is identical across all three surfaces

## Contract (locked by CONTEXT.md Decision A, v1.3.4)

- **Placement:** dual-surface (this skill + `commands/gmd/set-vault-root.md`).
- **Default:** convention path `~/AiVaults/{git-basename}/{git-basename}`, free-text
  editable (not a menu, not a disk-scan).
- **Skip:** accept-default via empty input + `[y/N]` confirm writes the
  convention path AND prints a one-liner forward-pointer.
- **Config target:** project-level only. `.planning/config.json` `vault.root`.
  Never `~/.claude/get-magic-done/config.json`.

## Flow

### Step 1 — Read current state

```bash
# Current vault.root (if any)
CURRENT=$(node -e "const c=require('./bin/lib/planning-config.js').readPlanningConfig(process.cwd()); console.log((c.vault&&c.vault.root)||'')")

# Convention-path default — reuse git-basename derivation from vault-project.js
DEFAULT=$(node -e "const p=require('path'),os=require('os'),{execSync}=require('child_process'); try { const r=execSync('git rev-parse --show-toplevel',{stdio:['ignore','pipe','ignore']}).toString().trim(); const b=p.basename(r); console.log(p.join(os.homedir(),'AiVaults',b,b)); } catch { console.log(''); }")
```

### Step 2 — Prompt

Show the current value (if set) and use AskUserQuestion to offer:

```
Where should the Obsidian vault live?
  Current: <value from CURRENT, or "(not set — convention fallback in use)">
  Default: <DEFAULT>
  (Press Enter to accept default, type a different path, or leave blank + confirm to skip)
```

Use AskUserQuestion with two options:
1. **"Accept default"** (writes `DEFAULT`)
2. **"Enter custom path"** (ask user to type an absolute path or `~/...`)

If the user selects "Enter custom path" but submits an empty string, ask a
follow-up `[y/N]` "Skip and accept convention default?" — on `y` write the
convention path; otherwise re-prompt.

### Step 3 — Persist

Call the shared writer:

```bash
node -e "require('./bin/lib/planning-config.js').setVaultRoot(process.cwd(), '<chosen-path>')"
```

`setVaultRoot` handles tilde expansion + relative→absolute resolution +
merging with existing `vault.*` fields (preserves `vault.projectName`).

### Step 4 — Skip-path forward pointer

If the user chose the skip path (empty + confirm), print:

```
note: vault root defaulted to <absolute-path>. Run /gmd:set-vault-root to change.
```

(The one-liner is informational; no action required.)

### Step 5 — Emit the resolved status line

Run a dry-run vault-init to surface the new `resolved:` line so the user
sees which SPEC §18.10 tier now owns the path:

```bash
node bin/gmd-tools.cjs vault-init --dry-run --raw 2>&1 | head -1
```

Expected stderr-merged output (for a freshly-persisted project-config):

```
resolved: <absolute-path> (source: project-config)
```

## Non-goals

- Does not write to `~/.claude/get-magic-done/config.json` (global scope is
  out of scope for v1.3.4).
- Does not scan disk for existing `.obsidian/` markers (deferred; see
  `.planning/phases/24-vault-resolver-unification/24-CONTEXT.md` Deferred).
- Does not dedupe pre-existing split vaults (forward-pointing at
  `/gmd:cleanup --vault-dedupe` in v1.3.5 instead).
- Does not prompt unless the user explicitly invokes the slash command or the
  installer/update workflow detects an obsidian-enable flip.

## Error handling

- If `git rev-parse --show-toplevel` fails (not in a git repo):
  `DEFAULT` is empty; require user to enter an absolute path explicitly;
  the skip path is unavailable (no convention to fall back on).
- If `.planning/` cannot be created (permission error): surface the error
  message from `setVaultRoot`; do not silently swallow.
