Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions .planning/ONBOARDING-SPEC.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Spec — Install / Onboarding Rework

**Status:** DRAFT → building.
**Why:** install/onboarding is the #1 adoption blocker (claim `mm-300f`). 3 overlapping docs, no from-zero happy path, interactive-only setup that isn't detect-first, no verify, no full-stack orchestration.
**Locked decisions:** (1) BOTH — agent install prompt drives a detect-first idempotent setup, then verifies; (2) FULL-STACK default, friction absorbed by the agent, with a graceful no-Docker fallback; (3) Claude Code + Codex from v1; brownfield-reuse; consolidate docs.
**Constraint (STOP rule):** ENHANCE `setup_hooks.py` additively — do NOT rewrite from scratch. Preserve every existing wiring function and its idempotent remove-then-add behavior.

---

## 1. New module — `memorymaster/surfaces/setup_detect.py`

Pure, side-effect-free environment probing. Subprocess calls are read-only, `shell=False`, timeout-bounded (≤5s each), and NEVER raise (degrade to "unknown/absent").

```python
@dataclass(frozen=True)
class Detected:
python_version: str
pip_ok: bool
os: str # "Windows" | "Linux" | "Darwin"
docker: bool # `docker --version` ok
docker_compose: bool # `docker compose version` ok
ollama: bool # http GET OLLAMA_URL/api/tags ok OR `ollama --version`
ollama_models: tuple[str, ...]
qdrant: bool # http GET QDRANT_URL/healthz ok
obsidian_vault: str | None # path if an obsidian-vault/ found under cwd
gitnexus: bool # `.gitnexus/` present OR `npx gitnexus` resolvable
claude_code: bool # ~/.claude/ exists
codex: bool # ~/.codex/ exists
mm_installed: bool # `import memorymaster` works
mm_mcp_registered: bool # memorymaster already in ~/.claude.json mcpServers
existing_hooks: tuple[str, ...] # memorymaster hooks already in settings.json

def detect_environment(*, cwd: Path | None = None) -> Detected: ...
def format_plan(d: Detected, *, want_full_stack: bool) -> list[str]:
"""Human-readable 'will do / will skip (already present) / can't (missing dep)' lines."""
```

Brownfield = the report drives skip-if-present everywhere.

---

## 2. `setup_hooks.py` — additive enhancements

Keep all existing functions (`install_hooks`, `install_mcp`, `append_instructions`, `setup_steward_cron`, `install_obsidian_skills`). Add:

1. **argparse, non-interactive mode.** `main()` parses:
`--yes/-y` (no prompts, accept defaults), `--db PATH`, `--provider {google,openai,anthropic,ollama}`, `--api-key`, `--model`, `--project-root PATH`, `--full-stack/--no-full-stack`, `--no-cron`, `--no-obsidian-skills`, `--codex/--no-codex`, `--verify-only`, `--json` (machine-readable result for the agent prompt). When a flag is given, never prompt for that value. `ask`/`ask_yn` must honor a global non-interactive flag (return the default/flag value instead of calling `input()`).
2. **Detect-first.** Call `detect_environment()` early; print `format_plan(...)`; in interactive mode confirm, in `--yes` proceed.
3. **Idempotent + brownfield.** Skip MCP/hook/cron/skill steps whose target is already present (use the Detected report). Re-running must be a no-op-ish (already idempotent for hooks — extend to MCP: don't clobber unless `--force`).
4. **Fix the MCP-path bug.** Register the server via the entry point: `command="memorymaster-mcp"` (preferred) or `[PYTHON_EXE, "-m", "memorymaster.surfaces.mcp_server"]` — NOT the deprecated `memorymaster.mcp_server`. Also register for Codex when `codex` detected (its MCP config location).
5. **Full-stack orchestration (the locked default).** New `setup_full_stack(detected, *, interactive, yes)`:
- If `docker_compose` present: offer/run `docker compose up -d qdrant ollama` (reuse repo `docker-compose.yml`); wait for health; `ollama pull` the configured model. Reuse if `qdrant`/`ollama` already healthy (brownfield).
- **No-Docker fallback:** if Docker absent AND Qdrant/Ollama not already running → print a clear, non-fatal message: "Running in SQLite-only mode. Vector recall + local LLM auto-ingest are OFF. To enable them: install Docker and re-run with `--full-stack`, or point QDRANT_URL/OLLAMA_URL at existing services." Setup continues and succeeds in degraded mode.
- Never block the core install on stack failures.
6. **Verify step.** New `verify_install(db_path)`: init a throwaway check — ingest a sentinel claim then `query_memory` it back via `service`, confirm round-trip; if MCP registered, note "restart session to load MCP". Print PASS/PARTIAL with exactly what works. Reachable via `--verify-only`.
7. **`--json` output** for the agent prompt: emit `{detected, planned, applied, verify, degraded}` so the agent can parse and report.

---

## 3. Agent install prompt — `docs/AGENT-INSTALL.md`

A copy-paste block the user gives Claude Code **or** Codex. It instructs the agent to:
1. `pip install "memorymaster[mcp,security,qdrant,embeddings]"` (full-stack extras).
2. Run `memorymaster-setup --yes --full-stack --json` and read the JSON.
3. Report the plan (what was wired, what was reused/brownfield, what degraded).
4. Run `memorymaster-setup --verify-only` and show the round-trip result.
5. Tell the user to restart the session to load hooks + MCP.
Include a Claude-Code variant and a Codex variant (Codex MCP config path differs; Codex has no Stop hook → point at the session-end script, mirroring current `append_instructions`).

---

## 4. Docs consolidation

- **README.md:** replace the install section with a **30-second quickstart** — the single happy path: `pip install` → paste the agent prompt (link `docs/AGENT-INSTALL.md`) → restart → verified. One short "manual / advanced" pointer to `INSTALLATION.md`.
- **INSTALLATION.md:** stays as the reference matrix (extras, Docker, Helm, env vars, troubleshooting). Add the new flags + `--verify-only`.
- **docs/INTEGRATING.md:** remove install overlap; keep only the 3-beat agent contract / integration semantics. Cross-link, don't duplicate.

---

## 5. Tests (MANDATORY, hermetic)

All tests MUST patch `HOME`/`CLAUDE_DIR`/`CODEX_DIR` to `tmp_path` and mock `subprocess.run`/HTTP — **never touch the real `~/.claude`**. Cover:
- `setup_detect`: each probe parses canned output; all degrade to absent on timeout/error; no exceptions escape.
- `setup_hooks` non-interactive: `--yes --provider ... --db ...` wires hooks/MCP into a tmp HOME; re-run is idempotent (no duplicate hook entries; settings.json stays valid JSON).
- MCP registration uses the correct (non-deprecated) command.
- No-Docker fallback: Docker absent → setup still succeeds, degraded message emitted, exit 0.
- `verify_install`: round-trip ingest+query on a tmp DB returns PASS.
- `--json` emits valid parseable JSON.

---

## 6. Safety constraints
- Never corrupt existing `settings.json` / `.claude.json` — read-merge-write, preserve unknown keys, keep valid JSON on every path.
- All external-tool probes timeout-bounded, `shell=False`, never fatal.
- The build/test run must NOT execute the real installer against the developer machine.

## 7. Acceptance criteria (verifiable)
- [ ] `memorymaster-setup --yes --db <tmp> --provider ollama --no-cron --no-obsidian-skills` runs non-interactively to completion in a patched HOME, exit 0.
- [ ] Re-running it produces no duplicate hooks and identical settings.json (idempotent).
- [ ] MCP entry uses `memorymaster-mcp` / `surfaces.mcp_server`, not the deprecated path.
- [ ] Docker-absent path prints the degraded-mode message and still exits 0.
- [ ] `--verify-only` round-trips a sentinel claim (PASS) on a tmp DB.
- [ ] `--json` output parses.
- [ ] New + existing tests green; ruff clean; full suite collects clean.
- [ ] README quickstart ≤ ~30 lines to first verified memory; `docs/AGENT-INSTALL.md` present with Claude + Codex variants.
69 changes: 56 additions & 13 deletions INSTALLATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,27 +47,70 @@ pip install -e ".[dev,mcp,security]"
memorymaster --db memory.db init-db
```

### Interactive setup (hooks + MCP + cron)
### Setup (hooks + MCP + cron)

After `pip install memorymaster`, run the interactive installer to wire
MemoryMaster into Claude Code (hooks, MCP server, steward cron) and
optionally into Codex:
After `pip install memorymaster`, run the installer to wire MemoryMaster into
Claude Code (hooks, MCP server, steward cron) and optionally Codex.

**Recommended — let your agent drive it** (paste [`docs/AGENT-INSTALL.md`](docs/AGENT-INSTALL.md)
into Claude Code or Codex):

```bash
memorymaster-setup
memorymaster-setup --yes --full-stack --json
```

This will:
**Manual / interactive:**

- Ask for your LLM provider (Gemini / OpenAI / Anthropic / Ollama) and API key
- Ask where `memorymaster.db` should live (default: current directory)
- Copy 7 hook scripts to `~/.claude/hooks/` and wire them into `~/.claude/settings.json`: recall, classify, validate-wiki, session-start, auto-ingest, pre-compact, plus the 6-hour steward cron
- Register the `memorymaster` MCP server globally in `~/.claude.json`
- Optionally append Codex `AGENTS.md` + global `CLAUDE.md` integration snippets
- Optionally install the steward cron (Linux/macOS) or Task Scheduler job (Windows)
```bash
memorymaster-setup
```

Running from a cloned repo? `python scripts/setup-hooks.py` also works — it is
a 3-line shim that calls the same `memorymaster.setup_hooks:main` function.
a 3-line shim that calls the same `memorymaster.surfaces.setup_hooks:main` function.

#### `memorymaster-setup` flags

| Flag | Default | Description |
|------|---------|-------------|
| `-y` / `--yes` | off | Non-interactive; accept all defaults (no `input()` prompts) |
| `--db PATH` | `<project-root>/memorymaster.db` | Path to the SQLite database |
| `--provider {google,openai,anthropic,ollama}` | prompted | LLM provider for the auto-ingest Stop hook |
| `--api-key KEY` | prompted | API key for the chosen provider |
| `--model MODEL` | provider default | LLM model id |
| `--project-root PATH` | cwd | Directory where `memorymaster.db` lives |
| `--full-stack` | on | Bring up Qdrant + Ollama via Docker Compose |
| `--no-full-stack` | off | Skip the vector + local-LLM stack |
| `--no-cron` | off | Skip steward cron setup |
| `--no-obsidian-skills` | off | Skip Obsidian skills install |
| `--codex` | auto-detect | Force Codex MCP + instructions wiring |
| `--no-codex` | — | Skip Codex wiring |
| `--force` | off | Overwrite existing MCP entries (default: skip if present) |
| `--verify-only` | off | Run only the sentinel round-trip verify and exit |
| `--json` | off | Emit machine-readable JSON result on stdout (human chatter goes to stderr) |

#### What the installer does

- Probes your environment first (Python, Docker, Qdrant, Ollama, `~/.claude/`, `~/.codex/`) and prints a plan; existing components are reused, not overwritten.
- Copies 7 hook scripts to `~/.claude/hooks/` and wires them into `~/.claude/settings.json`: recall, classify, validate-wiki, session-start, auto-ingest, pre-compact, plus the 6-hour steward cron.
- Registers the `memorymaster` MCP server globally in `~/.claude.json` (using `memorymaster.surfaces.mcp_server` — not the deprecated path).
- Optionally appends Codex `AGENTS.md` + global `CLAUDE.md` integration snippets.
- Optionally installs the steward cron (Linux/macOS) or Task Scheduler job (Windows).
- Runs a sentinel round-trip verify at the end (`--verify-only` to run this step alone).

#### No-Docker degraded mode

If Docker is absent and Qdrant/Ollama are not already running, the installer
continues without them and prints:

```
Running in SQLite-only mode. Vector recall + local LLM auto-ingest are OFF.
To enable them: install Docker and re-run with --full-stack, or point
QDRANT_URL / OLLAMA_URL at existing services.
```

Setup exits 0. Core hooks, MCP, and SQLite-based recall all work normally in
degraded mode. Add vector search later by installing Docker and re-running
`memorymaster-setup --full-stack --yes`.

## Docker Compose

Expand Down
66 changes: 16 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,72 +104,38 @@ Reproduce: `python tests/bench_longmemeval.py --retrieval-only`. Full methodolog

- **Docker** for Qdrant — vector retrieval. SQLite FTS5 is the default and works out of the box; add Qdrant when you want semantic recall on top of keyword search.

## 15-minute quickstart
## 30-second quickstart

From zero to a recalled claim and a live dashboard. No Qdrant, no Postgres, no LLM key required for these steps (SQLite + FTS5 is the default).

**1. Install (2 min)**
**1. Install**

```bash
pip install "memorymaster[mcp]"
memorymaster --db memorymaster.db init-db
pip install "memorymaster[mcp,security,qdrant,embeddings]"
```

**2. Configure a provider (3 min, optional for this walkthrough)**

Recall and ingest below work with zero config. An LLM provider is only needed for the steward/wiki cycles — pick one when you're ready (see [Pick your LLM provider](#pick-your-llm-provider)). For a Claude Code subscriber, the cheapest path is:
**2. Let your agent do the rest**

```bash
export MEMORYMASTER_LLM_PROVIDER=claude_cli # reuses your Claude Code OAuth, no API key
```
Paste the contents of [`docs/AGENT-INSTALL.md`](docs/AGENT-INSTALL.md) into Claude Code or Codex. The agent will:
- run `memorymaster-setup --yes --full-stack --json` (detects your environment, wires hooks + MCP, starts Qdrant + Ollama if Docker is present, or falls back to SQLite-only mode gracefully)
- report what was wired, what was reused (brownfield), and what degraded
- run `memorymaster-setup --verify-only` and show the round-trip result

**3. Ingest a claim via CLI (1 min)**
**3. Restart your session**

```bash
memorymaster --db memorymaster.db ingest \
--text "Server uses PostgreSQL 16" \
--source "session://chat|turn-3|user confirmed"
```
Hooks and MCP load on session start. Restart Claude Code / Codex once.

**4. Recall it (1 min)**
**4. Verify**

A freshly-ingested claim starts life as a `candidate` (unvalidated). The CLI `query`/`context` paths *exclude* candidates by default — that's the governance model: unvalidated facts don't silently leak into recall until the steward promotes them. To see your brand-new claim before a validation cycle, pass `--include-candidates`:
After restart, run in your agent:

```bash
# Hybrid retrieval (lexical + freshness + confidence)
memorymaster --db memorymaster.db query "database version" \
--retrieval-mode hybrid --include-candidates

# Token-budgeted context block — the killer feature for agents
memorymaster --db memorymaster.db context "database" \
--budget 4000 --format xml --include-candidates
```

You should see the PostgreSQL 16 claim come back, ranked, with its citation. (Drop `--include-candidates` and you'll get zero results until step 7's `run-cycle` promotes it to `confirmed` — that's working as designed, not a bug.)

**5. Open the dashboard (2 min)**

```bash
memorymaster --db memorymaster.db run-dashboard # serves on http://127.0.0.1:8765
```

Open the URL: you'll see your claim in **Claims**, plus governance panels — **Conflicts**, **Review Queue**, **Recall Analysis** (why each claim ranked where it did), **Audit Log**, **Provenance by Agent**, and **Reliability**.

**6. Wire it into your agent (3 min)**

```bash
memorymaster-setup # interactive: hooks, MCP, steward cron, CLAUDE.md / AGENTS.md
query_memory("test")
```

That installs the MCP server and the auto-ingest Stop hook so your agent recalls and stores memory automatically. See [MCP server](#mcp-server) for the config block.

**7. Run a validation cycle (1 min, needs a provider)**
You should get a recall response from the MCP server. Done.

```bash
memorymaster --db memorymaster.db run-cycle # extract, validate, decay, compact
```
---

For the one-prompt agent install (paste into any agent with shell access), see [`docs/handbook.md#one-prompt-agent-install`](docs/handbook.md#one-prompt-agent-install).
For manual setup, advanced flags (`--provider`, `--db`, `--no-cron`, `--no-full-stack`, `--verify-only`, `--json`, and more), Docker, Helm, and Postgres, see [INSTALLATION.md](INSTALLATION.md).

## Pick your LLM provider

Expand Down
Loading
Loading