# Setup

> 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).

- Skill: `jojoprison/setup` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add jojoprison/setup`
- Raw SKILL.md: https://api.skillmd.com/api/skills/jojoprison/setup/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: jojoprison (https://skillmd.com/u/jojoprison)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/jojoprison/setup

---


# 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=`.

