@dinasor/mnemo-cli 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,46 +1,72 @@
1
- # Changelog
2
-
3
- All notable changes to Mnemo are documented here.
4
-
5
- Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Mnemo uses [Semantic Versioning](https://semver.org/).
6
-
7
- ## [Unreleased]
8
-
9
- ## [0.0.1] - 2026-02-21
10
-
11
- ### Added
12
- - First public Mnemo release with dual installers: `memory.ps1` (Windows PowerShell 5.1+/7+) and `memory_mac.sh` (macOS/Linux POSIX shell).
13
- - Installer CLI support for `--dry-run` / `-DryRun`, `--force` / `-Force`, project naming, and optional vector enablement.
14
- - Modular installer architecture with dedicated core and feature modules under `scripts/memory/installer/` (bootstrap, path resolution, I/O, bridges, scaffold, hooks, vector, MCP, `.gitignore`).
15
- - Canonical memory root at `.mnemo/` with compatibility bridges to `.cursor/` and `.agent/` so existing IDE integrations continue to work.
16
- - Bridge manager with cross-platform fallback behavior (symlink/junction/hardlink/mirror) and repair/migration logic for legacy layouts.
17
- - Canonical memory scaffold including always-read files (`hot-rules.md`, `active-context.md`, `memo.md`), lessons, journals, digests, ADR, and templates.
18
- - Atomic lesson workflow (`L-XXX-*`) and monthly journal workflow with rebuildable indexes/digests.
19
- - Helper script suite for daily operations (PowerShell + shell variants): rebuild index, lint memory, query memory, add lesson, add journal entry, clear active context.
20
- - Tag vocabulary enforcement and memory lint guardrails for frontmatter, structure, and token-safety checks.
21
- - Optional SQLite FTS support (`memory.sqlite`) when Python is available, including build/query helpers.
22
- - Optional vector mode with `mnemo_vector.py` MCP server and tools: `vector_search`, `vector_sync`, `vector_forget`, `vector_health`, `memory_status`.
23
- - Vector embedding provider support for both OpenAI and Gemini.
24
- - Autonomy runtime templates installed with vector mode (`autonomy/*` + `policies.yaml`) for ingestion, lifecycle, reranking, context safety, and policy handling.
25
- - Portable git hooks via `.githooks/` with automatic `core.hooksPath` setup.
26
- - Hook automation: `pre-commit` rebuild/lint and optional `post-commit` non-blocking vector sync.
27
- - Multi-agent bridge outputs: `CLAUDE.md`, `AGENTS.md`, and `.agent/rules/memory-system.md`.
28
- - Cross-platform CI coverage (Windows/macOS/Ubuntu), regression tests, modularization guardrails, and Python syntax checks for autonomy/retrieval modules.
29
- - Nightly benchmark workflow for retrieval quality/drift monitoring plus artifact upload.
30
- - GitHub release workflow for tag-based publishing with preflight/version/changelog validation and packaged installer assets.
31
- - Governance and contribution assets: `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md`, `SUPPORT.md`, issue templates, PR template, `CODEOWNERS`, and Dependabot config.
32
-
33
- ### Changed
34
- - Versioning is centralized in root `VERSION` and consumed by installers and generated output.
35
- - Installer/runtime path resolution prefers canonical `.mnemo` while preserving `.cursor` compatibility bridges.
36
- - Python resolution strategy is aligned across memory tooling (`py` / `python3` / `python` fallback behavior where applicable).
37
- - Managed `.gitignore` and hook behavior now reflect canonical `.mnemo` artifacts while keeping bridge compatibility.
38
-
39
- ### Fixed
40
- - Duplicate managed `.gitignore` entries on repeated force installs.
41
- - Bridge idempotency/self-copy failures around `.cursor/mcp.json` compatibility targets.
42
- - Version string drift between installer metadata and generated output by using `VERSION` as single source of truth.
43
- - Python fallback handling in memory query flows that previously depended on a single interpreter name.
44
-
45
- [Unreleased]: https://github.com/DiNaSoR/Mnemo/compare/v0.0.1...HEAD
46
- [0.0.1]: https://github.com/DiNaSoR/Mnemo/releases/tag/v0.0.1
1
+ # Changelog
2
+
3
+ All notable changes to Mnemo are documented here.
4
+
5
+ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Mnemo uses [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.0.3] - 2026-02-21
10
+
11
+ ### Changed
12
+ - Vector engine now loads project `.env` values (when `GEMINI_API_KEY` is not already set in the shell) before provider resolution, so local API key setup works more reliably in CLI and MCP contexts.
13
+ - Default vector provider auto-resolves to `gemini` when `MNEMO_PROVIDER` is unset and `GEMINI_API_KEY` is available; otherwise it falls back to `openai`.
14
+ - Vector memory root discovery now prioritizes the script location (repo-local `scripts/memory/mnemo_vector.py`) before current working directory scanning, preventing cross-project context leaks when invoked from another directory.
15
+ - Embedded POSIX fallback vector engine now mirrors the same `.env` and provider-resolution behavior as the primary template.
16
+
17
+ ### Added
18
+ - `mnemo_vector.py` now supports direct CLI operations: `sync`, `search`, `forget`, `health`, and `status`, enabling manual vector workflows outside MCP tool calls.
19
+
20
+ ## [0.0.2] - 2026-02-21
21
+
22
+ ### Changed
23
+ - Installers no longer generate root `CLAUDE.md` and `AGENTS.md`; integrations now use canonical `.mnemo/memory/` and agent bridge rules under `.agent/rules/`.
24
+ - Agent rule naming is normalized to ordered files: `00-memory-system.md` and `01-vector-search.md` (vector mode), aligned with cursor rule naming.
25
+ - Installer-managed `.gitignore` now uses top-level Mnemo paths (`.mnemo/`, `.cursor/memory/`, `.cursor/rules/`, `.cursor/mcp.json`, `.agent/rules/`, `scripts/memory/`, `.githooks/`) for cleaner defaults in target repositories.
26
+ - README IDE guidance now points Claude/Codex users to canonical `.mnemo/memory/` retrieval flow and updated agent rule paths.
27
+
28
+ ### Fixed
29
+ - PowerShell installer no longer hard-fails when `git config core.hooksPath .githooks` cannot be written (permission/lock); it warns and continues.
30
+ - POSIX vector re-runs are idempotent for autonomy module installation when `--force` is not used.
31
+ - Cross-platform installer regression tests now validate the new numbered agent rule output.
32
+
33
+ ## [0.0.1] - 2026-02-21
34
+
35
+ ### Added
36
+ - First public Mnemo release with dual installers: `memory.ps1` (Windows PowerShell 5.1+/7+) and `memory_mac.sh` (macOS/Linux POSIX shell).
37
+ - Installer CLI support for `--dry-run` / `-DryRun`, `--force` / `-Force`, project naming, and optional vector enablement.
38
+ - Modular installer architecture with dedicated core and feature modules under `scripts/memory/installer/` (bootstrap, path resolution, I/O, bridges, scaffold, hooks, vector, MCP, `.gitignore`).
39
+ - Canonical memory root at `.mnemo/` with compatibility bridges to `.cursor/` and `.agent/` so existing IDE integrations continue to work.
40
+ - Bridge manager with cross-platform fallback behavior (symlink/junction/hardlink/mirror) and repair/migration logic for legacy layouts.
41
+ - Canonical memory scaffold including always-read files (`hot-rules.md`, `active-context.md`, `memo.md`), lessons, journals, digests, ADR, and templates.
42
+ - Atomic lesson workflow (`L-XXX-*`) and monthly journal workflow with rebuildable indexes/digests.
43
+ - Helper script suite for daily operations (PowerShell + shell variants): rebuild index, lint memory, query memory, add lesson, add journal entry, clear active context.
44
+ - Tag vocabulary enforcement and memory lint guardrails for frontmatter, structure, and token-safety checks.
45
+ - Optional SQLite FTS support (`memory.sqlite`) when Python is available, including build/query helpers.
46
+ - Optional vector mode with `mnemo_vector.py` MCP server and tools: `vector_search`, `vector_sync`, `vector_forget`, `vector_health`, `memory_status`.
47
+ - Vector embedding provider support for both OpenAI and Gemini.
48
+ - Autonomy runtime templates installed with vector mode (`autonomy/*` + `policies.yaml`) for ingestion, lifecycle, reranking, context safety, and policy handling.
49
+ - Portable git hooks via `.githooks/` with automatic `core.hooksPath` setup.
50
+ - Hook automation: `pre-commit` rebuild/lint and optional `post-commit` non-blocking vector sync.
51
+ - Multi-agent bridge outputs under `.cursor/rules/` and `.agent/rules/` for IDE-specific rule loading.
52
+ - Cross-platform CI coverage (Windows/macOS/Ubuntu), regression tests, modularization guardrails, and Python syntax checks for autonomy/retrieval modules.
53
+ - Nightly benchmark workflow for retrieval quality/drift monitoring plus artifact upload.
54
+ - GitHub release workflow for tag-based publishing with preflight/version/changelog validation and packaged installer assets.
55
+ - Governance and contribution assets: `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md`, `SUPPORT.md`, issue templates, PR template, `CODEOWNERS`, and Dependabot config.
56
+
57
+ ### Changed
58
+ - Versioning is centralized in root `VERSION` and consumed by installers and generated output.
59
+ - Installer/runtime path resolution prefers canonical `.mnemo` while preserving `.cursor` compatibility bridges.
60
+ - Python resolution strategy is aligned across memory tooling (`py` / `python3` / `python` fallback behavior where applicable).
61
+ - Managed `.gitignore` and hook behavior now reflect canonical `.mnemo` artifacts while keeping bridge compatibility.
62
+
63
+ ### Fixed
64
+ - Duplicate managed `.gitignore` entries on repeated force installs.
65
+ - Bridge idempotency/self-copy failures around `.cursor/mcp.json` compatibility targets.
66
+ - Version string drift between installer metadata and generated output by using `VERSION` as single source of truth.
67
+ - Python fallback handling in memory query flows that previously depended on a single interpreter name.
68
+
69
+ [Unreleased]: https://github.com/DiNaSoR/Mnemo/compare/v0.0.3...HEAD
70
+ [0.0.3]: https://github.com/DiNaSoR/Mnemo/releases/tag/v0.0.3
71
+ [0.0.2]: https://github.com/DiNaSoR/Mnemo/releases/tag/v0.0.2
72
+ [0.0.1]: https://github.com/DiNaSoR/Mnemo/releases/tag/v0.0.1
package/README.md CHANGED
@@ -86,9 +86,9 @@ Use the section that matches your IDE. Each project should run Mnemo install onc
86
86
  | IDE / Agent | What installer creates | What you do next |
87
87
  |---|---|---|
88
88
  | Cursor | `.mnemo/rules/cursor/00-memory-system.mdc` (+ `.mnemo/mcp/cursor.mcp.json`, bridged to `.cursor/mcp.json`) | Restart Cursor, run `vector_health`, then `vector_sync` |
89
- | Claude Code | `CLAUDE.md` bridge file | Open repo in Claude Code and follow read order from `CLAUDE.md` |
90
- | Gemini Antigravity | `.agent/rules/memory-system.md` | Ensure Antigravity loads project rules from `.agent/rules/` |
91
- | OpenAI Codex | `AGENTS.md` | Start Codex from repo root so `AGENTS.md` is in scope |
89
+ | Claude Code | `.mnemo/memory/` knowledge base (also visible via `.cursor/memory`) | Open repo in Claude Code and follow retrieval order from `.mnemo/memory/index.md` |
90
+ | Gemini Antigravity | `.agent/rules/00-memory-system.md` (+ `.agent/rules/01-vector-search.md` in vector mode) | Ensure Antigravity loads project rules from `.agent/rules/` |
91
+ | OpenAI Codex | `.mnemo/memory/` knowledge base (also visible via `.cursor/memory`) | Start Codex from repo root and follow retrieval order from `.mnemo/memory/index.md` |
92
92
  | Windsurf / Other IDEs | `.mnemo/memory/` knowledge base (also visible at `.cursor/memory/`) | Point memory/context path to `.mnemo/memory/` |
93
93
 
94
94
  ### 1) Cursor IDE 🟦
@@ -105,23 +105,23 @@ You should see MCP tools:
105
105
  ### 2) Claude Code 🤝
106
106
 
107
107
  1. Run Mnemo install in your project root.
108
- 2. Confirm `CLAUDE.md` exists (auto-generated by installer).
108
+ 2. Confirm `.mnemo/memory/` exists (and `.cursor/memory/` bridge is present).
109
109
  3. Start Claude Code from the project root.
110
- 4. Keep `.mnemo/memory/` committed so memory travels with the repo (Cursor still reads through bridge).
110
+ 4. Follow retrieval order from `.mnemo/memory/index.md`.
111
111
 
112
112
  ### 3) Gemini Antigravity 🔷
113
113
 
114
114
  1. Run Mnemo install in your project root.
115
- 2. Confirm `.agent/rules/memory-system.md` exists.
115
+ 2. Confirm `.agent/rules/00-memory-system.md` exists.
116
116
  3. Ensure your Antigravity setup loads `.agent/rules/`.
117
117
  4. (Optional) Enable vector mode for semantic memory workflows.
118
118
 
119
119
  ### 4) OpenAI Codex 🧪
120
120
 
121
121
  1. Run Mnemo install in your project root.
122
- 2. Confirm `AGENTS.md` exists.
123
- 3. Launch Codex from the same root so `AGENTS.md` is used.
124
- 4. Follow the retrieval order defined in `AGENTS.md`.
122
+ 2. Confirm `.mnemo/memory/` exists (and `.cursor/memory/` bridge is present).
123
+ 3. Launch Codex from the same project root.
124
+ 4. Follow retrieval order from `.mnemo/memory/index.md`.
125
125
 
126
126
  ### 5) Windsurf / Other IDEs 🌊
127
127
 
@@ -137,7 +137,7 @@ You should see MCP tools:
137
137
  - **Always-read layer**: `.mnemo/memory/hot-rules.md`, `active-context.md`, `memo.md`
138
138
  - **Atomic lessons**: `.mnemo/memory/lessons/L-XXX-*.md` + generated lesson index
139
139
  - **Monthly journal + digests**: `.mnemo/memory/journal/YYYY-MM.md` + `.mnemo/memory/digests/*.digest.md`
140
- - **Rule enforcement**: `.mnemo/rules/cursor/00-memory-system.mdc` (bridged to `.cursor/rules/`)
140
+ - **Rule enforcement**: `.mnemo/rules/cursor/00-memory-system.mdc` and `.mnemo/rules/agent/00-memory-system.md` (bridged to `.cursor/rules/` and `.agent/rules/`)
141
141
  - **Helper scripts**: `scripts/memory/*` (rebuild, lint, query, add-lesson, add-journal-entry, clear-active)
142
142
  - **Optional SQLite FTS**: `.mnemo/memory/memory.sqlite` when Python is available
143
143
  - **Optional vector layer**: `scripts/memory/mnemo_vector.py` + MCP tools
@@ -183,7 +183,8 @@ Runner triggers:
183
183
  00-memory-system.mdc
184
184
  01-vector-search.mdc # vector mode only
185
185
  agent/
186
- memory-system.md
186
+ 00-memory-system.md
187
+ 01-vector-search.md # vector mode only
187
188
  mcp/
188
189
  cursor.mcp.json # vector mode only
189
190
 
@@ -217,7 +218,7 @@ scripts/
217
218
  | `add-lesson.ps1` | Creates next `L-XXX` lesson with normalized tags |
218
219
  | `add-journal-entry.ps1` | Adds entry under current date in monthly journal |
219
220
  | `clear-active.ps1` | Resets `active-context.md` |
220
- | `mnemo_vector.py` | Vector sync/search MCP server (vector mode only) |
221
+ | `mnemo_vector.py` | Vector MCP server + CLI (`sync`, `search`, `forget`, `health`, `status`) in vector mode |
221
222
 
222
223
  ## 🔐 Git hooks and API keys
223
224
 
@@ -229,12 +230,17 @@ Mnemo auto-configures `core.hooksPath` to `.githooks` and installs:
229
230
  Important:
230
231
  - Cursor MCP tools read API keys from `.mnemo/mcp/cursor.mcp.json` env placeholders (`.cursor/mcp.json` stays bridged).
231
232
  - Git hooks read API keys from your shell environment.
233
+ - If `GEMINI_API_KEY` is not already in the environment, `scripts/memory/mnemo_vector.py` also tries loading keys from project-root `.env`.
232
234
 
233
235
  ```sh
234
236
  # bash/zsh example
235
237
  export OPENAI_API_KEY="sk-..."
236
238
  # or
237
239
  export GEMINI_API_KEY="..."
240
+
241
+ # optional direct CLI usage (outside MCP tool calls)
242
+ python3 scripts/memory/mnemo_vector.py sync
243
+ python3 scripts/memory/mnemo_vector.py health
238
244
  ```
239
245
 
240
246
  ## ✅ Recommended daily workflow
package/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.3
package/memory.ps1 CHANGED
@@ -108,10 +108,29 @@ Ensure-MnemoCanonicalBridges -Ctx $ctx
108
108
 
109
109
  # Auto-configure portable hooks path (removes the manual 'git config' step)
110
110
  if (-not $DryRun -and (Test-Path $ctx.GitDir)) {
111
- $currentHooksPath = & git -C $RepoRoot config core.hooksPath 2>$null
112
- if ($currentHooksPath -ne ".githooks") {
113
- & git -C $RepoRoot config core.hooksPath .githooks 2>$null
114
- Write-Host "Configured: git config core.hooksPath .githooks" -ForegroundColor Green
111
+ $nativeErrorPrefVar = Get-Variable -Name PSNativeCommandUseErrorActionPreference -ErrorAction SilentlyContinue
112
+ $nativeErrorPrefOld = $null
113
+ if ($null -ne $nativeErrorPrefVar) {
114
+ $nativeErrorPrefOld = $PSNativeCommandUseErrorActionPreference
115
+ $PSNativeCommandUseErrorActionPreference = $false
116
+ }
117
+
118
+ try {
119
+ $currentHooksPath = (& git -C $RepoRoot config core.hooksPath 2>$null | Out-String).Trim()
120
+ if ($currentHooksPath -ne ".githooks") {
121
+ $null = & git -C $RepoRoot config core.hooksPath .githooks 2>$null
122
+ if ($LASTEXITCODE -eq 0) {
123
+ Write-Host "Configured: git config core.hooksPath .githooks" -ForegroundColor Green
124
+ } else {
125
+ Write-Warning "Could not set git core.hooksPath automatically (permission denied or repo locked). Continuing."
126
+ }
127
+ }
128
+ } catch {
129
+ Write-Warning "Could not set git core.hooksPath automatically. Continuing."
130
+ } finally {
131
+ if ($null -ne $nativeErrorPrefVar) {
132
+ $PSNativeCommandUseErrorActionPreference = $nativeErrorPrefOld
133
+ }
115
134
  }
116
135
  }
117
136
 
@@ -140,7 +159,7 @@ Write-Host ""
140
159
  if ($EnableVector -and (-not $DryRun)) {
141
160
  Write-Host "Vector tools enabled ($VectorProvider):" -ForegroundColor Cyan
142
161
  Write-Host " MCP tools: vector_search, vector_sync, vector_forget, vector_health, memory_status" -ForegroundColor DarkGray
143
- Write-Host " Rule: .cursor/rules/01-vector-search.mdc" -ForegroundColor DarkGray
162
+ Write-Host " Rules: .cursor/rules/01-vector-search.mdc and .agent/rules/01-vector-search.md" -ForegroundColor DarkGray
144
163
  Write-Host " MCP: .cursor/mcp.json -> MnemoVector server" -ForegroundColor DarkGray
145
164
  Write-Host ""
146
165
  Write-Host "Autonomous memory runtime:" -ForegroundColor Cyan
package/memory_mac.sh CHANGED
@@ -561,36 +561,12 @@ SEARCH FIRST, THEN FETCH:
561
561
  EOF
562
562
 
563
563
  # -------------------------
564
- # Multi-agent bridge files
564
+ # Agent bridge files
565
565
  # -------------------------
566
566
 
567
567
  mkdir -p "$AGENT_RULES_DIR"
568
568
 
569
- write_file "$REPO_ROOT/CLAUDE.md" <<'EOF'
570
- # Project Memory (Mnemo)
571
-
572
- This project uses Mnemo for structured AI memory.
573
- Memory lives in `.cursor/memory/` as the single source of truth.
574
-
575
- ## Read Order (ALWAYS)
576
- 1. `.cursor/memory/hot-rules.md` - tiny invariants (<20 lines)
577
- 2. `.cursor/memory/active-context.md` - current session state
578
- 3. `.cursor/memory/memo.md` - long-term project truth + ownership
579
-
580
- ## Search First, Then Fetch
581
- - `.cursor/memory/lessons/index.md` → find lesson ID → open only that lesson file
582
- - `.cursor/memory/digests/YYYY-MM.digest.md` → before raw journal archaeology
583
- - `.cursor/memory/journal/YYYY-MM.md` → only for deep history
584
-
585
- ## After Any Feature/Fix
586
- 1. Update `active-context.md` during work
587
- 2. Add journal entry when done
588
- 3. Create lesson if you discovered a pitfall
589
- 4. Update `memo.md` if project truth changed
590
- 5. Clear `active-context.md` when task is merged
591
- EOF
592
-
593
- write_file "$AGENT_RULES_DIR/memory-system.md" <<'EOF'
569
+ write_file "$AGENT_RULES_DIR/00-memory-system.md" <<'EOF'
594
570
  ---
595
571
  description: Mnemo memory system - structured AI memory in .cursor/memory/
596
572
  alwaysApply: true
@@ -623,28 +599,6 @@ This project uses Mnemo for structured AI memory. All memory lives in `.cursor/m
623
599
  - Clear active-context.md when task is merged
624
600
  EOF
625
601
 
626
- write_file "$REPO_ROOT/AGENTS.md" <<'EOF'
627
- # Memory System (Mnemo)
628
-
629
- This project uses Mnemo for structured AI memory.
630
- Memory location: `.cursor/memory/`
631
-
632
- ## Retrieval Order
633
- 1. Read `.cursor/memory/hot-rules.md` first (tiny, <20 lines)
634
- 2. Read `.cursor/memory/active-context.md` for current session
635
- 3. Read `.cursor/memory/memo.md` for project truth + ownership
636
- 4. Search `.cursor/memory/lessons/index.md` before creating new patterns
637
- 5. Check `.cursor/memory/digests/` before raw journal archaeology
638
-
639
- ## Authority Order (highest to lowest)
640
- 1. Lessons override EVERYTHING
641
- 2. active-context.md overrides memo/journal (but NOT lessons)
642
- 3. memo.md is long-term project truth
643
- 4. Journal is history
644
- 5. Existing codebase
645
- 6. New suggestions (lowest priority)
646
- EOF
647
-
648
602
  write_file "$MEM_SCRIPTS_DIR/customization.md" <<'EOF'
649
603
  # Mnemo Memory Customization Prompt (paste into an AI)
650
604
 
@@ -1867,9 +1821,70 @@ from mcp.server.fastmcp import FastMCP
1867
1821
 
1868
1822
  SCHEMA_VERSION = 2
1869
1823
  EMBED_DIM = 1536
1870
- MEM_ROOT = Path(".cursor/memory")
1871
- DB_PATH = MEM_ROOT / "mnemo_vector.sqlite"
1872
- PROVIDER = os.getenv("MNEMO_PROVIDER", "openai").lower()
1824
+
1825
+
1826
+ def _resolve_memory_root() -> Path:
1827
+ override = os.getenv("MNEMO_MEMORY_ROOT", "").strip()
1828
+ if override:
1829
+ return Path(override).expanduser().resolve()
1830
+
1831
+ script_repo = Path(__file__).resolve().parents[2]
1832
+ for rel in ((".mnemo", "memory"), (".cursor", "memory")):
1833
+ candidate = script_repo.joinpath(*rel)
1834
+ if candidate.exists():
1835
+ return candidate
1836
+
1837
+ cwd = Path.cwd().resolve()
1838
+ for root in (cwd, *cwd.parents):
1839
+ for rel in ((".mnemo", "memory"), (".cursor", "memory")):
1840
+ candidate = root.joinpath(*rel)
1841
+ if candidate.exists():
1842
+ return candidate
1843
+ return script_repo / ".mnemo" / "memory"
1844
+
1845
+
1846
+ def _parse_env_line(raw_line: str):
1847
+ line = raw_line.strip()
1848
+ if not line or line.startswith("#"):
1849
+ return None
1850
+ if line.startswith("export "):
1851
+ line = line[7:].strip()
1852
+ if "=" not in line:
1853
+ return None
1854
+ key, value = line.split("=", 1)
1855
+ key = key.strip()
1856
+ if not key or any(ch.isspace() for ch in key):
1857
+ return None
1858
+ value = value.strip()
1859
+ if value and len(value) >= 2 and value[0] == value[-1] and value[0] in {"'", '"'}:
1860
+ value = value[1:-1]
1861
+ elif " #" in value:
1862
+ value = value.split(" #", 1)[0].rstrip()
1863
+ return key, value
1864
+
1865
+
1866
+ def _load_project_env() -> None:
1867
+ if os.getenv("GEMINI_API_KEY"):
1868
+ return
1869
+ env_path = Path(".env")
1870
+ if not env_path.exists():
1871
+ return
1872
+ try:
1873
+ for raw_line in env_path.read_text(encoding="utf-8").splitlines():
1874
+ parsed = _parse_env_line(raw_line)
1875
+ if not parsed:
1876
+ continue
1877
+ key, value = parsed
1878
+ os.environ.setdefault(key, value)
1879
+ except OSError:
1880
+ pass
1881
+
1882
+
1883
+ MEM_ROOT = _resolve_memory_root()
1884
+ _DB_OVERRIDE = os.getenv("MNEMO_DB_PATH", "").strip()
1885
+ DB_PATH = Path(_DB_OVERRIDE).expanduser().resolve() if _DB_OVERRIDE else (MEM_ROOT / "mnemo_vector.sqlite")
1886
+ _load_project_env()
1887
+ PROVIDER = os.getenv("MNEMO_PROVIDER", "gemini" if os.getenv("GEMINI_API_KEY") else "openai").lower()
1873
1888
 
1874
1889
  SKIP_NAMES = {
1875
1890
  "README.md",
@@ -2202,6 +2217,32 @@ This rule supplements `00-memory-system.mdc` and does not replace governance.
2202
2217
  - `vector_forget` - remove stale entries.
2203
2218
  - `vector_health` - DB/API health check.
2204
2219
 
2220
+ ## Fallback
2221
+ If vector search is unavailable, keep using:
2222
+ - `scripts/memory/query-memory.sh --query "..."`
2223
+ - `scripts/memory/query-memory.sh --query "..." --use-sqlite`
2224
+ EOF
2225
+
2226
+ write_file "$AGENT_RULES_DIR/01-vector-search.md" <<'EOF'
2227
+ ---
2228
+ description: Mnemo vector semantic retrieval layer (optional)
2229
+ alwaysApply: true
2230
+ ---
2231
+
2232
+ # Vector Memory Layer (Optional)
2233
+
2234
+ This rule supplements `00-memory-system.md` and does not replace governance.
2235
+
2236
+ ## Use vector tools when:
2237
+ - You do not know the exact keyword for prior context.
2238
+ - Keyword/FTS search did not find relevant history.
2239
+
2240
+ ## MCP tools
2241
+ - `vector_search` - semantic retrieval with cosine similarity.
2242
+ - `vector_sync` - incremental indexing.
2243
+ - `vector_forget` - remove stale entries.
2244
+ - `vector_health` - DB/API health check.
2245
+
2205
2246
  ## Fallback
2206
2247
  If vector search is unavailable, keep using:
2207
2248
  - `scripts/memory/query-memory.sh --query "..."`
@@ -2344,25 +2385,13 @@ gi="$REPO_ROOT/.gitignore"
2344
2385
  GI_BEGIN="# >>> Mnemo (generated) - do not edit this block manually <<<"
2345
2386
  GI_END="# <<< Mnemo (generated) >>>"
2346
2387
 
2347
- ignore_lines=".mnemo/memory/memory.sqlite
2348
- .cursor/memory/memory.sqlite
2349
- .mnemo/mcp/cursor.mcp.json
2350
- .cursor/mcp.json"
2351
- if [ "$ENABLE_VECTOR" = "1" ]; then
2352
- ignore_lines="$ignore_lines
2353
- .mnemo/memory/mnemo_vector.sqlite
2354
- .mnemo/memory/mnemo_vector.sqlite-journal
2355
- .mnemo/memory/mnemo_vector.sqlite-wal
2356
- .mnemo/memory/mnemo_vector.sqlite-shm
2357
- .mnemo/memory/.sync.lock
2358
- .mnemo/memory/.autonomy/
2359
- .cursor/memory/mnemo_vector.sqlite
2360
- .cursor/memory/mnemo_vector.sqlite-journal
2361
- .cursor/memory/mnemo_vector.sqlite-wal
2362
- .cursor/memory/mnemo_vector.sqlite-shm
2363
- .cursor/memory/.sync.lock
2364
- .cursor/memory/.autonomy/"
2365
- fi
2388
+ ignore_lines=".mnemo/
2389
+ .cursor/memory/
2390
+ .cursor/rules/
2391
+ .cursor/mcp.json
2392
+ .agent/rules/
2393
+ scripts/memory/
2394
+ .githooks/"
2366
2395
 
2367
2396
  if [ "$DRY_RUN" = "1" ]; then
2368
2397
  echo "[DRY RUN] WOULD UPDATE: $gi (managed Mnemo block)"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dinasor/mnemo-cli",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "Mnemo installer CLI for the current project folder.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -13,28 +13,16 @@ function Update-MnemoGitignore {
13
13
  $giBeginMarker = "# >>> Mnemo (generated) - do not edit this block manually <<<"
14
14
  $giEndMarker = "# <<< Mnemo (generated) >>>"
15
15
 
16
+ # User-facing default: ignore the full Mnemo generated footprint so target repos stay clean by default.
16
17
  $ignoreLines = @(
17
- ".mnemo/memory/memory.sqlite",
18
- ".cursor/memory/memory.sqlite",
19
- ".mnemo/mcp/cursor.mcp.json",
20
- ".cursor/mcp.json"
18
+ ".mnemo/",
19
+ ".cursor/memory/",
20
+ ".cursor/rules/",
21
+ ".cursor/mcp.json",
22
+ ".agent/rules/",
23
+ "scripts/memory/",
24
+ ".githooks/"
21
25
  )
22
- if ($EnableVector) {
23
- $ignoreLines += @(
24
- ".mnemo/memory/mnemo_vector.sqlite",
25
- ".mnemo/memory/mnemo_vector.sqlite-journal",
26
- ".mnemo/memory/mnemo_vector.sqlite-wal",
27
- ".mnemo/memory/mnemo_vector.sqlite-shm",
28
- ".mnemo/memory/.sync.lock",
29
- ".mnemo/memory/.autonomy/",
30
- ".cursor/memory/mnemo_vector.sqlite",
31
- ".cursor/memory/mnemo_vector.sqlite-journal",
32
- ".cursor/memory/mnemo_vector.sqlite-wal",
33
- ".cursor/memory/mnemo_vector.sqlite-shm",
34
- ".cursor/memory/.sync.lock",
35
- ".cursor/memory/.autonomy/"
36
- )
37
- }
38
26
 
39
27
  $giLineEndings = "CRLF"
40
28
  $giContent = ""
@@ -189,30 +189,6 @@ SEARCH FIRST, THEN FETCH:
189
189
  - When you discover a bug pattern -> suggest creating a lesson
190
190
  - When unsure about architecture -> check lessons/index.md first
191
191
  - Don't create parallel systems -> check memo.md ownership map
192
- "@
193
-
194
- $claudeMd = @"
195
- # Project Memory (Mnemo)
196
-
197
- This project uses [Mnemo](https://github.com/DiNaSoR/Mnemo) for structured AI memory.
198
- Memory lives in ``.cursor/memory/`` as the single source of truth.
199
-
200
- ## Read Order (ALWAYS)
201
- 1. ``.cursor/memory/hot-rules.md`` - tiny invariants (<20 lines)
202
- 2. ``.cursor/memory/active-context.md`` - current session state
203
- 3. ``.cursor/memory/memo.md`` - long-term project truth + ownership
204
-
205
- ## Search First, Then Fetch
206
- - ``.cursor/memory/lessons/index.md`` -> find lesson ID -> open only that lesson file
207
- - ``.cursor/memory/digests/YYYY-MM.digest.md`` -> before raw journal archaeology
208
- - ``.cursor/memory/journal/YYYY-MM.md`` -> only for deep history
209
-
210
- ## After Any Feature/Fix
211
- 1. Update ``active-context.md`` during work
212
- 2. Add journal entry when done
213
- 3. Create lesson if you discovered a pitfall
214
- 4. Update ``memo.md`` if project truth changed
215
- 5. Clear ``active-context.md`` when task is merged
216
192
  "@
217
193
 
218
194
  $static = @{
@@ -222,7 +198,6 @@ Memory lives in ``.cursor/memory/`` as the single source of truth.
222
198
  (Join-Path $Ctx.MemoryDir "memo.md") = $memo
223
199
  (Join-Path $Ctx.JournalDir "$month.md") = $journalMonth
224
200
  (Join-Path $Ctx.RulesDir "00-memory-system.mdc") = $memoryRule
225
- (Join-Path $Ctx.RepoRoot "CLAUDE.md") = $claudeMd
226
201
  }
227
202
 
228
203
  foreach ($kv in $static.GetEnumerator()) {
@@ -397,7 +372,7 @@ What did we choose?
397
372
  Tradeoffs, risks, follow-ups.
398
373
  "@ -ForceWrite:$Force
399
374
 
400
- # Multi-agent bridges
375
+ # Agent bridge rules
401
376
  $geminiRule = @"
402
377
  ---
403
378
  description: Mnemo memory system - structured AI memory in .cursor/memory/
@@ -426,37 +401,7 @@ This project uses Mnemo for structured AI memory. All memory lives in ``.cursor/
426
401
  - Clear active-context.md when task is merged
427
402
  "@
428
403
 
429
- $agentsMd = @"
430
- # Memory System (Mnemo)
431
-
432
- This project uses Mnemo for structured AI memory.
433
- Memory location: ``.cursor/memory/``
434
-
435
- ## Retrieval Order
436
- 1. Read ``.cursor/memory/hot-rules.md`` first (tiny, <20 lines)
437
- 2. Read ``.cursor/memory/active-context.md`` for current session
438
- 3. Read ``.cursor/memory/memo.md`` for project truth + ownership
439
- 4. Search ``.cursor/memory/lessons/index.md`` before creating new patterns
440
- 5. Check ``.cursor/memory/digests/`` before raw journal archaeology
441
-
442
- ## Authority Order (highest to lowest)
443
- 1. Lessons override EVERYTHING
444
- 2. active-context.md overrides memo/journal (but NOT lessons)
445
- 3. memo.md is long-term project truth
446
- 4. Journal is history
447
- 5. Existing codebase
448
- 6. New suggestions (lowest priority)
449
-
450
- ## After Any Feature/Fix
451
- - Update active-context.md during work (scratchpad)
452
- - Add journal entry to journal/YYYY-MM.md when done
453
- - Create lessons/L-XXX-title.md if you discovered a pitfall
454
- - Update memo.md if project truth changed
455
- - Clear active-context.md when task is merged
456
- "@
457
-
458
- Write-MnemoFile (Join-Path $Ctx.MnemoRulesAgentDir "memory-system.md") $geminiRule -ForceWrite:$Force
459
- Write-MnemoFile (Join-Path $Ctx.RepoRoot "AGENTS.md") $agentsMd -ForceWrite:$Force
404
+ Write-MnemoFile (Join-Path $Ctx.MnemoRulesAgentDir "00-memory-system.md") $geminiRule -ForceWrite:$Force
460
405
 
461
406
  Write-Host "`nMemory scaffold installed." -ForegroundColor Cyan
462
407
  }
@@ -99,5 +99,34 @@ If vector search is unavailable, keep using:
99
99
 
100
100
  Write-MnemoFile (Join-Path $Ctx.RulesDir "01-vector-search.mdc") $vectorRule -ForceWrite:$Force
101
101
 
102
+ $agentVectorRule = @"
103
+ ---
104
+ description: Mnemo vector semantic retrieval layer (optional)
105
+ alwaysApply: true
106
+ ---
107
+
108
+ # Vector Memory Layer (Optional)
109
+
110
+ This rule supplements ``00-memory-system.md`` and does not replace governance.
111
+
112
+ ## Use vector tools when:
113
+ - You do not know the exact keyword for prior context.
114
+ - Keyword/FTS search did not find relevant history.
115
+
116
+ ## MCP tools
117
+ - ``vector_search`` - semantic retrieval with authority-aware reranking.
118
+ - ``vector_sync`` - incremental indexing.
119
+ - ``vector_forget`` - remove stale entries.
120
+ - ``vector_health`` - DB/API health check.
121
+ - ``memory_status`` - JSON summary for autonomous monitoring.
122
+
123
+ ## Fallback
124
+ If vector search is unavailable, keep using:
125
+ - ``scripts/memory/query-memory.ps1 -Query "..."``
126
+ - ``scripts/memory/query-memory.ps1 -Query "..." -UseSqlite``
127
+ "@
128
+
129
+ Write-MnemoFile (Join-Path $Ctx.MnemoRulesAgentDir "01-vector-search.md") $agentVectorRule -ForceWrite:$Force
130
+
102
131
  return $vectorPython
103
132
  }
@@ -9,6 +9,8 @@ import re
9
9
  import json
10
10
  import sqlite3
11
11
  import hashlib
12
+ import argparse
13
+ import sys
12
14
  from pathlib import Path
13
15
 
14
16
  import sqlite_vec
@@ -27,19 +29,78 @@ def _resolve_memory_root() -> Path:
27
29
  if override:
28
30
  return Path(override).expanduser().resolve()
29
31
 
32
+ script_repo = Path(__file__).resolve().parents[2]
33
+ for rel in ((".mnemo", "memory"), (".cursor", "memory")):
34
+ candidate = script_repo.joinpath(*rel)
35
+ if candidate.exists():
36
+ return candidate
37
+
30
38
  cwd = Path.cwd().resolve()
31
39
  for root in (cwd, *cwd.parents):
32
40
  for rel in ((".mnemo", "memory"), (".cursor", "memory")):
33
41
  candidate = root.joinpath(*rel)
34
42
  if candidate.exists():
35
43
  return candidate
36
- return cwd / ".mnemo" / "memory"
44
+ return script_repo / ".mnemo" / "memory"
45
+
46
+
47
+ def _resolve_repo_root(memory_root: Path) -> Path:
48
+ root = memory_root.resolve()
49
+ if root.name == "memory" and root.parent.name in {".mnemo", ".cursor"}:
50
+ return root.parent.parent
51
+ cwd = Path.cwd().resolve()
52
+ for candidate in (cwd, *cwd.parents):
53
+ if candidate.joinpath(".mnemo", "memory").exists() or candidate.joinpath(".cursor", "memory").exists():
54
+ return candidate
55
+ return cwd
56
+
57
+
58
+ def _parse_env_line(raw_line: str) -> tuple[str, str] | None:
59
+ line = raw_line.strip()
60
+ if not line or line.startswith("#"):
61
+ return None
62
+ if line.startswith("export "):
63
+ line = line[7:].strip()
64
+ if "=" not in line:
65
+ return None
66
+
67
+ key, value = line.split("=", 1)
68
+ key = key.strip()
69
+ if not key or any(ch.isspace() for ch in key):
70
+ return None
71
+
72
+ value = value.strip()
73
+ if value and len(value) >= 2 and value[0] == value[-1] and value[0] in {"'", '"'}:
74
+ value = value[1:-1]
75
+ elif " #" in value:
76
+ value = value.split(" #", 1)[0].rstrip()
77
+ return key, value
78
+
79
+
80
+ def _load_project_env(repo_root: Path) -> None:
81
+ # Keep shell-provided values authoritative; only fill missing vars from .env.
82
+ if os.getenv("GEMINI_API_KEY"):
83
+ return
84
+ env_path = repo_root / ".env"
85
+ if not env_path.exists():
86
+ return
87
+ try:
88
+ for raw_line in env_path.read_text(encoding="utf-8").splitlines():
89
+ parsed = _parse_env_line(raw_line)
90
+ if not parsed:
91
+ continue
92
+ key, value = parsed
93
+ os.environ.setdefault(key, value)
94
+ except OSError:
95
+ pass
37
96
 
38
97
 
39
98
  MEM_ROOT = _resolve_memory_root()
99
+ REPO_ROOT = _resolve_repo_root(MEM_ROOT)
100
+ _load_project_env(REPO_ROOT)
40
101
  _DB_OVERRIDE = os.getenv("MNEMO_DB_PATH", "").strip()
41
102
  DB_PATH = Path(_DB_OVERRIDE).expanduser().resolve() if _DB_OVERRIDE else (MEM_ROOT / "mnemo_vector.sqlite")
42
- PROVIDER = os.getenv("MNEMO_PROVIDER", "openai").lower()
103
+ PROVIDER = os.getenv("MNEMO_PROVIDER", "gemini" if os.getenv("GEMINI_API_KEY") else "openai").lower()
43
104
 
44
105
  SKIP_NAMES = {
45
106
  "README.md", "index.md", "lessons-index.json",
@@ -552,5 +613,42 @@ def memory_status() -> str:
552
613
  return json.dumps({"error": str(e)})
553
614
 
554
615
 
616
+ def _run_cli(argv: list[str]) -> int:
617
+ parser = argparse.ArgumentParser(description="Mnemo vector CLI")
618
+ sub = parser.add_subparsers(dest="command", required=True)
619
+
620
+ sub.add_parser("sync", help="Rebuild vector index from memory markdown files")
621
+
622
+ p_search = sub.add_parser("search", help="Semantic search memory")
623
+ p_search.add_argument("query", help="Search query text")
624
+ p_search.add_argument("--top-k", type=int, default=8, help="Number of results to return")
625
+
626
+ p_forget = sub.add_parser("forget", help="Remove vectors by source path")
627
+ p_forget.add_argument("ref_path", help="Reference path to remove (exact match)")
628
+
629
+ sub.add_parser("health", help="Check DB and embedding provider health")
630
+ sub.add_parser("status", help="Return JSON memory status summary")
631
+
632
+ args = parser.parse_args(argv)
633
+ try:
634
+ if args.command == "sync":
635
+ print(vector_sync())
636
+ elif args.command == "search":
637
+ print(vector_search(args.query, top_k=args.top_k))
638
+ elif args.command == "forget":
639
+ print(vector_forget(args.ref_path))
640
+ elif args.command == "health":
641
+ print(vector_health())
642
+ elif args.command == "status":
643
+ print(memory_status())
644
+ except Exception as e:
645
+ print(f"ERROR: {e}", file=sys.stderr)
646
+ return 1
647
+ return 0
648
+
649
+
555
650
  if __name__ == "__main__":
651
+ cli_commands = {"sync", "search", "forget", "health", "status"}
652
+ if len(sys.argv) > 1 and sys.argv[1] in cli_commands:
653
+ raise SystemExit(_run_cli(sys.argv[1:]))
556
654
  mcp.run()