# Onboarding a new Alexandria user (laptop-only)

A step-by-step runbook to deploy Alexandria for one person on their Mac, with **no always-on server**: a private Obsidian vault + a daily emailed digest (via GitHub Actions) + Claude connected to the vault. Follow it top to bottom while sitting with them. Placeholders look like `<THIS>`.

> The milestone that proves it works is **Part H** — a real digest email arriving. Parts I–J add the Obsidian + Claude usage layer.

> **Deploying an always-on Mac mini appliance instead?** Use [`APPLIANCE.md`](APPLIANCE.md) — the `server-macos` sibling to this laptop runbook (launchd + dotenv secrets + the automated `setup-appliance.command`).

---

> **Shortcut for Parts 0 / A / B:** send the user `install/install-alexandria.command` (or the `.pkg`). They right-click → Open it once (macOS quarantines emailed scripts), and it installs Homebrew + prerequisites, signs them into GitHub, and installs the Alexandria CLI. Then skip to **Part C**. (They still need read access to the `alexandria` repo — the collaborator grant below — before running it.)
>
> **Zero-install alternative:** the single-zip path — `Alexandria.zip` from keystone.computer/install (spec: [`DISTRIBUTION.md`](DISTRIBUTION.md)) stands a local brain up with no GitHub, no collaborator grant, and no secrets; the digest and sync of this runbook become upgrades. **On such a folder brain, don't run Parts 0–C or I literally** — the paths (`~/Obsidian/vault`), the sequencing (repo before render), and the collaborator/PAT machinery are all this runbook's technician-led layout, not yours. Backup/sync = the brain's own **`github-sync`** skill (say *"sync to GitHub"*). **Email is not available on a folder brain at all** — see the note at the bottom of this doc.
>
> **Even faster — the guided path:** after that base install, it opens Claude Code; type **"install alexandria"** and choose **laptop**. The `alexandria-install` skill then drives Parts C–L for you (this doc is its reference). Choosing **appliance** instead runs the `server-macos` path in [`APPLIANCE.md`](APPLIANCE.md).

## Part 0 — Prerequisites (gather first)

Accounts the user needs:
- A **GitHub account** — the whole system runs on it (the vault is a private GitHub repo, and the CLI installs from GitHub). **If they don't have one, create it free at https://github.com/signup FIRST.** They sign in with `gh auth login` (a browser flow) in Part A.
- An **Anthropic API key** — console.anthropic.com → *API keys* → create one. Needs a little billing credit; one digest costs a few cents.
- A **Gmail account with 2-Step Verification ON** (to send the digest). Any SMTP works, but this guide uses Gmail.

One-time access grant (you do this from your account):
- Add the user as a **read collaborator on `keystone-computer/alexandria`** so the install can clone the software (Part B):
  `gh repo add-collaborator keystone-computer/alexandria <THEIR_GH_USERNAME> --permission read`
  (or GitHub web → the alexandria repo → Settings → Collaborators → Add).
- *(No software token to mint anymore: the render vendors the engine wheel into the vault at
  `.github/engine/`, and the scheduled workflows install it straight from the checkout.)*

On their Mac, install the tools (Terminal):
```sh
# Homebrew (if not present): https://brew.sh
brew install git gh python@3.11 ripgrep obsidian
```
(`obsidian` is a cask; if `brew install obsidian` complains, use `brew install --cask obsidian` or download from obsidian.md.)

`ripgrep` (`rg`) is **required**, not a nicety: the brain's agents search the vault with raw regex as a first-class tool, and `rg` reads the vault-root `.ignore` the template ships — quarantining Claude Code session worktrees under `.claude/` (full copies of every note), `.obsidian/`, and machine-generated snapshot folders, the paths that turn a plain `grep -r` into duplicate hits. Verify with `rg --version`.

---

## Part A — Sign the user into GitHub on their machine
**They need a GitHub account first** — if they don't have one, create it at https://github.com/signup, then sign in. `gh auth login` opens a browser: choose **GitHub.com → SSH → Login with a web browser**, and authorize. Signing in over SSH also uploads a **no-passphrase account SSH key** to their GitHub account (`gh ssh-key add`, idempotent) — **leave the passphrase blank** so vault sync stays hands-free.
```sh
gh auth login --hostname github.com --git-protocol ssh --web   # as THE USER; leave the key passphrase blank
gh auth setup-git      # sets git to prefer SSH so Obsidian/Git pushes to their private repo without prompts
```

## Part B — Install the Alexandria CLI
```sh
ALX="$HOME/Library/Application Support/Alexandria/app"
mkdir -p "$ALX"
git clone git@github.com:keystone-computer/alexandria.git "$ALX"   # SSH (the account key from Part A)
cd "$ALX"
python3 -m venv .venv
.venv/bin/pip install -e .
# quick check:
.venv/bin/alexandria --version
```
For the rest of the guide, just type **`alexandria`** — the installer puts it on your PATH (so it resolves for you *and* for Claude Code's shell). Installed by hand instead? Either `source ~/alexandria/.venv/bin/activate` once, or call `~/alexandria/.venv/bin/alexandria` directly.

## Part C — Create their private vault repo
```sh
gh repo create <THEIR_GH_USERNAME>/<VAULT_REPO> --private
# pick a repo name, e.g. obsidian-vault-<firstname> — the local folder is always ~/Obsidian/vault
git clone git@github.com:<THEIR_GH_USERNAME>/<VAULT_REPO>.git ~/Obsidian/vault   # SSH — vault sync stays hands-free
```

## Part D — Write their (minimal) config
This is the **technical** config — just enough for a *working* vault ([the "make it work" half of the setup arc](SETUP-ARC.md)). **The owner personalizes the rest themselves later** — **their own name**, the agent's name/personality, and their real areas — by saying "Hello" in Claude Code (Part L). So keep this **identity-neutral**: `agent.address` left at the placeholder **"Alexandria"** (a brain has an *address*, not a name; the legacy `agent.name` key mirrors it), **no owner name, no areas.** Ask them for just the **email where the digest should land**. **Don't ask for their name** (it's identity — Part L) or **their timezone** (`alexandria init` auto-detects it). Create `~/Library/Application Support/Alexandria/onboard-config.json`:

```json
{
  "alexandria": { "version": "0.1.0", "template_ref": "v0.1.0",
                  "source_repo": "keystone-computer/alexandria", "source_ref": "main",
                  "maintainer": { "name": "<you>", "contact": "<your email>" } },
  "repo": "<THEIR_GH_USERNAME>/<VAULT_REPO>",
  "owner": { "emails": ["<their_gmail@gmail.com>"] },
  "agent": { "address": "Alexandria", "name": "Alexandria", "personalized": false, "email": "<gmail-localpart>+alexandria@gmail.com" },
  "areas": [],
  "owner_digests": [
    { "id": "rest", "title": "Daily Digest", "areas": "rest", "to": "<their email>", "personal": true }
  ],
  "automation": { "runner": "laptop-github-actions", "send_hour_local": 7, "weather": true },
  "modules": { "enabled": ["core", "laptop-github-actions"] },
  "secrets": { "backend": "github-actions",
               "required": ["ANTHROPIC_API_KEY", "SMTP_HOST", "SMTP_USER", "SMTP_PASS"] }
}
```
Notes:
- **Neutral by design.** `agent.address` holds the placeholder **"Alexandria"** (never offered as a default — it's the software's name), `agent.personalized` is `false`, and there are **no owner name and no areas** — the owner names themselves (which creates their personal Area via `alexandria seed-area`), gives the brain its address, and adds their real areas in **Part L**. A `Travel` area is scaffolded automatically. `owner.name` + `timezone_default` are omitted on purpose (the CLI auto-detects the timezone; the name comes at "Hello").
- **Email is an alias of their own Gmail — not a new account.** `agent.email` is the *From* the digest is sent as; the standard is a **"+" alias** of their own mailbox (mail to it lands in their inbox; replies route back). The account you authenticate as is their **real Gmail**, set later as the `SMTP_USER` secret. For a **custom domain**, ask the provider (Google Workspace / Microsoft 365 / Other) — but a personal Gmail +alias is simplest for the first setup.
- One `"areas": "rest"` digest = everything in one brief. `owner_digests[].to` is where the digest is **received** (can be their main email).

## Part E — Render the vault
```sh
alexandria init \
  --vault "~/Obsidian/vault" \
  --config "$HOME/Library/Application Support/Alexandria/onboard-config.json"
alexandria doctor --vault "~/Obsidian/vault"
```
`doctor` should print `OK — no errors.` It will list the secrets still to set (next part).

## Part F — Get the Gmail App Password (the #1 friction point)
This is for **their own Gmail** (the account the agent sends *as an alias of*). The account must qualify for App Passwords — check all of these first:
- **2-Step Verification is ON** (myaccount.google.com → Security). App Passwords don't exist without it — the usual reason the option is missing.
- **Not enrolled in Google's Advanced Protection Program** (it disables App Passwords).
- **Workspace accounts:** the admin must allow App Passwords (Admin console → Security). If 2-Step is on but the option is still hidden, the admin has disabled it — use a personal Gmail, or have them enable it.

Then:
1. Open **myaccount.google.com/apppasswords** → name it "Alexandria" → **Create** → copy the **16-character** code (use it **without spaces**). This is `SMTP_PASS` (and `IMAP_PASS` if you enable inbound later).
2. `SMTP_USER` = their **real Gmail address** (the account you authenticate as — **not** the `+alias`). `SMTP_HOST` = `smtp.gmail.com`.

## Part G — Set the secrets in GitHub
Print the exact commands, then run them with the real values:
```sh
alexandria secrets --vault "~/Obsidian/vault"
```
It prints `gh secret set …` lines. **The `ANTHROPIC_API_KEY` was already collected during install** (it lives in the off-repo secrets file), so **reuse it instead of re-typing** — only `SMTP_PASS` needs a fresh value from the owner:
```sh
# Reuse the Anthropic key the installer already stored (it never prints to screen):
gh secret set ANTHROPIC_API_KEY --repo <THEIR_GH_USERNAME>/<VAULT_REPO> \
  --body "$(grep '^ANTHROPIC_API_KEY=' "$HOME/Library/Application Support/Alexandria/alexandria.env" | cut -d= -f2-)"
gh secret set SMTP_HOST        --repo <THEIR_GH_USERNAME>/<VAULT_REPO> --body "smtp.gmail.com"
gh secret set SMTP_USER        --repo <THEIR_GH_USERNAME>/<VAULT_REPO> --body "<their_gmail@gmail.com>"
gh secret set SMTP_PASS        --repo <THEIR_GH_USERNAME>/<VAULT_REPO> --body "<16-char app password>"
```
(No software-repo token: the render vendors the engine wheel into the vault at `.github/engine/`, and the workflows install it from the checkout — commit and push the wheel with the vault.)

## Part H — Push, allow Actions to write, and TEST THE DIGEST ✅
```sh
cd ~/Obsidian/vault
# (optional but nice) add a couple of real todos so the first digest has content:
#   open Areas/<Area 1>/<Area 1> TODO.md and add a line like:
#   - [ ] (P1) Call the auditor   \n     - added 2026-06-20, due 2026-06-25
git add -A && git commit -m "alexandria: initial vault" && git push -u origin main
```
Allow the workflow to commit the Action Board back: GitHub web → the repo → **Settings → Actions → General → Workflow permissions →** select **"Read and write permissions"** **→ Save.**

Now trigger the digest immediately (don't wait for the 7am cron):
```sh
gh workflow run "Alexandria Daily Digest" --repo <THEIR_GH_USERNAME>/<VAULT_REPO>
gh run watch --repo <THEIR_GH_USERNAME>/<VAULT_REPO>     # or watch on the Actions tab
```
**Success = the digest email lands in `<their email>`** and the run is green. (See Troubleshooting if not.)

## Part I — Obsidian + sync
The vault ships **Obsidian Git pre-installed** — its code *and* its ~10-min auto-sync settings — so this is mostly just permitting community plugins. **Full walk-through:** `Agent/Obsidian Setup.md` in the vault.
1. Open Obsidian → *Open folder as vault* → `~/Obsidian/vault`. If prompted, **Trust author and enable plugins**.
2. Settings → **Community plugins** → **Turn on community plugins** (exits Restricted/Safe mode — the "trust author" prompt). **Obsidian Git loads immediately, already configured** (10-min auto pull/commit/push, using the `gh auth setup-git` credentials) — confirm a **sync status** shows; reload Obsidian if it didn't pick up the enable.
3. *(Optional, for the local Claude MCP in Part J)* **Browse** → install **Semantic Notes Vault MCP** → Enable; note its **local URL/port + API key** for `claude_desktop_config.json`. (Its key/certs are per-machine — see `Agent/Obsidian Setup.md`.)
4. They can now read/edit notes locally; changes sync to GitHub, and the daily Action Board syncs back down.

## Part J — Connect Claude
1. In Claude (desktop or claude.ai) → Settings → **Connectors** → add the **GitHub** connector, authorized to `<VAULT_REPO>`. (This alone covers web + mobile.)
2. *(Optional, desktop power-up — local MCP)* Follow `~/Obsidian/vault/Agent/Claude Desktop MCP.md` to add the `obsidian-vault` + `vault-filesystem` servers to `~/Library/Application Support/Claude/claude_desktop_config.json` (using the Semantic plugin's URL/key from Part I.3 and the vault's absolute path), then **Cmd-Q and reopen Claude Desktop**.
3. Test the connector: start a new Claude chat and ask it to **list the files in `<VAULT_REPO>`** — it should read the repo through the connector.
4. **Don't paste the standing context block yet.** `Agent/Standing Context.md` embeds the agent's name and the owner's name — both still neutral placeholders on this un-personalized vault. The **owner** pastes it into their assistant's standing-instructions field (Claude: Settings → Profile; ChatGPT: custom instructions) as the *last* step of personalization, once those names are real — see Part L.
5. **Hand off to the owner for personalization — see Part L.** (Don't personalize it yourself; that's the owner's step.)

## Part K — What they can expect daily
- A **Daily Digest** email each morning at `send_hour_local`, written by their assistant from their open todos.
- Chat with Claude to add/triage todos, file notes, ask "what's on my plate." Edit locally in Obsidian too.
- **To update Alexandria later:** pull the software checkout, then re-render — `git -C "$HOME/Library/Application Support/Alexandria/app" pull --ff-only && alexandria update --vault ~/Obsidian/vault` (`update` is render-only; Config + notes untouched). Their agent runs it for them from a Claude Code session at the vault ("update yourself"). Zip-installed folder brains use the zip channel instead (`alexandria update --from-zip`). Both the old CI update lane (trigger commit → Action → PR) and the old in-command checkout pull are retired.

## Part L — Hand off: the owner personalizes their agent (say "Hello" in Claude Code)
The vault is live but **neutral** — a default agent named "Alexandria" (`agent.personalized: false`) and just the owner's personal area. **The owner makes it theirs, themselves.** The simplest path: **open the vault in Claude Code and say "Hello."** Tell them:

> Open your vault in **Claude Code** (`cd` into it and run `claude`) and just say **"Hello."** I'll introduce myself and walk you through picking my address, my personality and voice, your real areas of responsibility, and how you like your daily brief — and save it all to your vault. The very last step hands you a standing context block to paste into your assistant's settings, with my address already in it. (Prefer **Claude Desktop**? Say **"set up my agent"** there instead.) Say **"settings"** anytime afterward to tune any one thing.

Under the hood that's the vault's **`settings`** first-run pass (address → propagated across every file, personality/voice/working style, areas, digest, key people + frameworks). In Claude Code the skill auto-loads and AGENTS.md's *First run* block routes the greeting; in Claude Desktop the owner triggers it explicitly. **The chat path:** if the vault's MCP server is running (`alexandria serve`, or the Orion desktop's own sidecar), any connected chat client detects the un-personalized vault (`capabilities()` → `personalized: false`) and can run the same interview end-to-end over the wire — the server's `onboarding` tool serves the playbook; only marking areas **confidential** stays a Claude-Code-at-the-vault follow-up (see `CHAT-ONBOARDING.md`). Its **final step is pasting the now-correctly-named `Agent/Standing Context.md`** into the owner's assistant's standing-instructions field (Claude: Settings → Profile; ChatGPT: custom instructions) — the technician deliberately left it un-pasted because it embeds the agent + owner names. Either way it writes the vault files, commits to `main`, and flips `agent.personalized` to `true`. **The deployer doesn't run this — the owner does, when they're ready.**

---

## Folder brain — email is not available (for now)

**A local (zip) brain has no email channel.** The emailed digest and inbound email cannot
be set up on a folder brain today — they are runbook/hosted-tier features (this runbook's
laptop tier, the appliance, or a managed brain). Don't walk a folder-brain owner through
Parts D–H; the brain's own surfaces present the brief as on-demand and offer no email
upgrade. *(A folder-brain email lane existed briefly on 2026-08-31 and was withdrawn the
same day — Will's call: no email features on local brains for now.)*

## Troubleshooting (Part H is where issues surface)
- **No email, run failed at the send step** → almost always SMTP: the Gmail App Password is wrong/has spaces, or 2-Step Verification isn't on, or `SMTP_USER` ≠ the Gmail that owns the App Password. Re-do Part F and re-set `SMTP_PASS`.
- **Run failed at the Anthropic step** → bad/empty `ANTHROPIC_API_KEY`, or no billing credit on the Anthropic account.
- **Run green but Action Board didn't commit back** → you skipped the "Read and write permissions" toggle in Part H; set it and re-run.
- **`gh workflow run` says no workflow found** → confirm the push happened and `.github/workflows/alexandria-digest.yml` is in the repo on GitHub.
- **Digest is empty / looks sparse** → expected on a brand-new vault; add a few real todos (Part H note) and re-run.
- **Obsidian Git can't push** → run `gh auth setup-git` again; confirm `git push` works manually from the vault folder.
