Use on first install, when reconfiguring mnemo, or when the user says 'setup mnemo', 'mnemo not configured', 'change vault', 'reset config', 'мнемо настрой', 'настрой мнемо', or similar — also invoked automatically when any other mnemo skill detects a missing config. Interactive onboarding that creates ~/.mnemo/config.json (vault name, taxonomy, links-section language, cascade defaults).
Installs into .claude/skills of the current project.
Are you the author of Setup?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/jojoprison-setup)
---
name: setup
description: "Use on first install, when reconfiguring mnemo, or when the user says 'setup mnemo', 'mnemo not configured', 'change vault', 'reset config', 'мнемо настрой', 'настрой мнемо', or similar — also invoked automatically when any other mnemo skill detects a missing config. Interactive onboarding that creates ~/.mnemo/config.json (vault name, taxonomy, links-section language, cascade defaults)."
model: haiku
---
# mn:setup — Interactive Onboarding
> **Invocation marker (both runtimes):** begin your reply with the exact line `🧠 mn:setup (mnemo) → running` — the user-visible confirmation that this skill actually loaded. Emit it once per invocation, before any other output.
## Portable paths
Resolve `<mnemo-root>` once to the absolute plugin root before reading bundled files or running bundled scripts. In Claude Code, use `${CLAUDE_PLUGIN_ROOT}`; in Codex, derive it from this loaded `SKILL.md` path (skill directory → `skills/` → plugin root). Replace `<mnemo-root>` with that quoted absolute path in every command — never execute the placeholder literally and never hunt versioned cache directories.
When another mnemo skill must run, use the runtime-native path: Claude Code invokes `mn:<skill>` through its Skill tool; Codex reads `<mnemo-root>/skills/<skill>/SKILL.md` completely and follows it with the prepared input. For user-facing explicit syntax, render `/mn:<skill>` in Claude Code and `$mnemo:<skill>` in Codex.
First-time setup for mnemo. Creates config.json with all settings.
## Workflow
### Step 1: Welcome
```
🧠 Welcome to mnemo — persistent memory for Codex and Claude Code.
Let's set up your configuration. This takes about 30 seconds.
```
### Step 2: Vault Name
```
What's your Obsidian vault name?
(The name shown in Obsidian's vault switcher)
> main
```
Verify vault exists:
```bash
python3 "<mnemo-root>/scripts/safe-read.py" search <<< '{"query":"test","vault":"{input}"}'
```
If error → "Vault not found. Is Obsidian open? Check the vault name."
### Step 3: Note Taxonomy
```
Which note taxonomy do you use?
[1] Atom/Molecule/Source/Session/MOC (Zettelkasten-inspired)
[2] PARA (Projects/Areas/Resources/Archive)
[3] Custom (you'll define prefixes and tags)
> 1
```
Map the selection to two adjacent config objects:
- `taxonomy` defines physical note types. Each entry is `{ "prefix": "…", "tag": "…" }`, and every prefix **must end in a filename-safe separator** such as ` — `, `: `, or ` - `. Never allow `/`, `#`, or `.` in a prefix.
- `taxonomy_roles` maps the stable semantic roles `fact`, `insight`, `source`, `session`, and `moc` to keys that exist in `taxonomy`. This is the only routing layer skills consume; never infer a destination from a display prefix or tag.
Always keep `session` and `moc` in `taxonomy` and map those two roles to themselves — they are *functional* types. The canonical workflows still resolve them through `taxonomy_roles.session` and `taxonomy_roles.moc`; they never bypass the role map.
**[1] Zettelkasten** — use the full blocks shown in Step 5 below. The role map is deterministic: `fact → atom`, `insight → molecule`, `source → source`, `session → session`, `moc → moc`.
**[2] PARA:**
```json
"taxonomy": {
"project": { "prefix": "Project — ", "tag": "project" },
"area": { "prefix": "Area — ", "tag": "area" },
"resource": { "prefix": "Resource — ", "tag": "resource" },
"archive": { "prefix": "Archive — ", "tag": "archive" },
"session": { "prefix": "Session — ", "tag": "session" },
"moc": { "prefix": "MOC — ", "tag": "moc" }
},
"taxonomy_roles": {
"fact": "resource",
"insight": "resource",
"source": "resource",
"session": "session",
"moc": "moc"
}
```
PARA organizes by actionability rather than knowledge shape, so propose `resource` for the three durable-memory roles, show the mapping, and ask the user to confirm or choose a different existing PARA key for each role. Never silently guess `project` versus `area` from content.
**[3] Custom** — ask the user for each type's key + prefix + tag; enforce the separator rule on every prefix; still include `session` and `moc` (add them yourself if the user doesn't name them). Then show the final type keys and ask once which key receives each of `fact`, `insight`, and `source`; keep `session → session` and `moc → moc`. Reject a role target that is not an exact `taxonomy` key.
**Existing config migration:** preserve a `taxonomy_roles` object only when its key set is exactly `fact`, `insight`, `source`, `session`, and `moc`, every target is an existing taxonomy key, and `session → session` plus `moc → moc`. If it is absent and `taxonomy` contains the legacy Zettelkasten keys `atom`, `molecule`, `source`, `session`, and `moc`, add the deterministic [1] map without asking. For any other missing/invalid custom map, show the existing taxonomy keys and ask once for the three content-role targets; keep the functional self-maps, do not rename types, and do not guess from prefixes/tags. Preserve all unrelated config fields.
### Step 4: Links Section Name
```
What heading do you use for note cross-references?
[1] ## Связи (Russian)
[2] ## Links
[3] ## Related
[4] ## Connections
[5] Custom
> 1
```
### Step 4.5: Cross-runtime Recall (opt-in)
```
Let Codex read this project's Claude memory, and Claude read this project's Codex memory?
[1] No (default — Obsidian + the active runtime only)
[2] Yes (read-only, exact git-project match, no copying or syncing)
> 1
```
Map the choice to `recall.runtimeMemory.enabled`. This is intentionally **off by default** because runtime memory may contain agent-generated or sensitive local context. Enabling it adds a bounded read-only overlay to `ask`; it does not create symlinks, share writers, scan transcripts, or change where either runtime stores memory. `globalSources: "explicit"` still requires the user to ask for global/cross-project memory in that specific query.
### Step 5: Save Config
Write `~/.mnemo/config.json`:
```json
{
"vault": "main",
"taxonomy": {
"atom": { "prefix": "Atom — ", "tag": "atom" },
"molecule": { "prefix": "Molecule — ", "tag": "molecule" },
"source": { "prefix": "Source — ", "tag": "source" },
"session": { "prefix": "Session — ", "tag": "session" },
"moc": { "prefix": "MOC — ", "tag": "moc" }
},
"taxonomy_roles": {
"fact": "atom",
"insight": "molecule",
"source": "source",
"session": "session",
"moc": "moc"
},
"links_section": "## Связи",
"handoff_note": "Meta — Session Handoff",
"handoff": {
"keepDays": 31,
"maxKB": 56,
"maxLineBytes": 200
},
"hot": {
"scope": "project",
"windowDays": 7,
"maxKB": 8
},
"cascade": {
"obsidian": { "enabled": true },
"claude_mem": { "enabled": false, "url": "http://127.0.0.1:37777" },
"memory_dir": { "enabled": true },
"project_rules": { "enabled": true },
"claude_md": { "enabled": false }
},
"recall": {
"codeGraph": null,
"runtimeMemory": {
"enabled": false,
"globalSources": "explicit",
"maxHits": 5,
"maxExcerptBytes": 12288
}
},
"hooks": {
"sessionStartNudge": true,
"stopNudge": false,
"autocompactNudge": false,
"invocationEcho": true,
"hotDigest": true
}
}
```
`hooks.stopNudge` ships **false** — flip it to `true` if you want the end-of-session save/session reminder (see `<mnemo-root>/references/config-schema.md`). `hooks.invocationEcho` (Claude Code only, default true) prints a `🧠 mnemo: /mn:<skill> → skill body loaded` confirmation when a `/mn:*` command expands. `hooks.hotDigest` (default true) injects the open-tails digest at session start. Everything works on these defaults even if the whole `hooks` block is omitted.
**If the user turns on `hooks.autocompactNudge`, tell them it may need one Claude Code setting.** The nudge needs to know the autocompact window, and on an account with 1M-context access mnemo deliberately refuses to guess it (the transcript records the model id without its `[1m]` suffix, so a 1M session and a 200k one are indistinguishable — guessing low would block a turn at 15% full). Run `python3 "<mnemo-root>/scripts/context-window.py" --explain` and pass on its `hint`. Two things to say plainly, because both are easy to get wrong:
- **Compaction happens before the window is full**, so the value is the desired threshold **plus the reserve** (33000 on a model whose max output is ≥ 20k). Wanting compaction at 460000 means setting `493000`.
- **A value above the model's context window does nothing** — on a 200k model, `460000` silently resolves to `200000`.
mnemo ships **no default** for `autoCompactWindow` and never writes it: it is Claude Code's setting, not mnemo's, and one account's sensible value halves another's usable context.
The `handoff` block bounds the handoff index: `keepDays` is the rotation rule (the note holds the last month of pointers), `maxKB` a backstop beneath it, `maxLineBytes` the per-line ceiling in **bytes**. The shipped numbers come from a measured vault (7.5 sessions/day); on a much busier one, raise `maxKB` before shortening `keepDays`.
Use the Step 4.5 answer for `recall.runtimeMemory.enabled`; the JSON above shows the safe default. If an existing config is being edited, preserve every unrelated field and change only the requested setting.
### Step 6: Create Handoff Note (only if missing)
First check — skip this step entirely if the handoff note already exists:
```bash
python3 "<mnemo-root>/scripts/safe-read.py" read <<< '{"file":"{handoff_note}","vault":"{vault}"}'
```
If empty output, create through the bundled shell-free writer in either runtime:
```bash
python3 "<mnemo-root>/scripts/vault-write.py" <<< '{"action":"create","vault":"{vault}","note":"Meta — Session Handoff","content":"{one JSON-escaped Markdown string: meta frontmatter, an H1, and one line stating that this note is an index of pointers to session notes — the last handoff.keepDays days — not a store of open work}"}'
```
`create` is exclusive and atomic. If it reports `conflict`, re-read the note rather than overwriting it.
### Step 6.5: Project Hub Note (optional)
Offer: "Create a hub note for short-name navigation? E.g. `[[ProjectName]]` → its MOC."
**Why:** Obsidian's resolver ignores frontmatter `aliases` for bare `[[Name]]` links (by design) — only a real file named `ProjectName.md` makes `[[ProjectName]]` resolve. See `<mnemo-root>/references/tool-routing.md` ("Hub notes"). Without it, every short `[[ProjectName]]` reference is a broken ghost.
If user confirms, resolve `taxonomy_roles.moc` to its configured prefix and create through the same writer:
```bash
python3 "<mnemo-root>/scripts/vault-write.py" <<< '{"action":"create","vault":"{vault}","note":"{short-name}","content":"{one JSON-escaped Markdown hub body linking to the mapped moc note}"}'
```
Skip if a file with that name already exists (`obsidian read` returns content). Note name must not contain `#` / `.` / `/` (see `<mnemo-root>/references/tool-routing.md` naming rules).
### Step 7: Done
Render the completion message with one runtime-native `{prefix}`: `/mn:` in Claude Code or `$mnemo:` in Codex. Replace the placeholder before showing the message.
```
🧠 mnemo is ready!
Your skills:
{prefix}ask — search & synthesize
{prefix}save — memory routing cascade
{prefix}session — session notes + handoff
{prefix}review — session completeness review
{prefix}connect — discover hidden links
{prefix}setup — configure or reconfigure mnemo
{prefix}health — vault audit & analytics
Config saved to: ~/.mnemo/config.json
Handoff note created: Meta — Session Handoff
Try: {prefix}health
```
## Gotchas
Common failures in `<mnemo-root>/references/gotchas.md`. Full config schema in `<mnemo-root>/references/config-schema.md`. Skill-specific rules:
- **Run once** — if `~/.mnemo/config.json` exists, show current values and ask before overwriting. User may just want to change one field, not rebuild everything.
- **Verify Obsidian is open during vault name step** — run the Step 2 `safe-read.py search` probe with `{"query":"test","vault":"{input}"}`. It fails fast if the vault name is wrong or Obsidian isn't running, while keeping the user-provided name out of shell syntax.
- **Don't create vault structure** — mnemo works with existing vaults. Do not create folders, templates, or sample notes. The user's vault is theirs.
- **PARA taxonomy selection** — create `project/area/resource/archive` types plus functional `session/moc`, then confirm the explicit `taxonomy_roles` targets. Custom taxonomy accepts any prefixes as long as each ends in a filename-safe separator such as ` — `, `: `, or ` - `; never `/`, `#`, or `.`.
- **Role-map integrity** — write exactly the five stable role keys and require every value to name an existing taxonomy key. Never route by comparing human-facing prefixes or tags.
- **One write path in both runtimes** — all vault Markdown goes through `scripts/vault-write.py`; never require an external Obsidian MCP and never use inline `obsidian create/append content=`.