mneme-cli 0.5.0__tar.gz → 0.5.2__tar.gz

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.
Files changed (50) hide show
  1. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/AGENTS.md +169 -1
  2. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/CHANGELOG.md +78 -0
  3. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/CLAUDE.md +1 -1
  4. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/CODER.md +1 -1
  5. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/EXAMPLES.md +2 -2
  6. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/FEATURES.md +8 -1
  7. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/PKG-INFO +103 -19
  8. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/README.md +100 -16
  9. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/__init__.py +2 -2
  10. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/config.py +2 -2
  11. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/core.py +1020 -58
  12. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/server.py +2 -2
  13. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/templates/workspace/README.md +1 -1
  14. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/ui.html +2 -2
  15. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/pyproject.toml +4 -2
  16. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/tests/test_core.py +529 -4
  17. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/LICENSE +0 -0
  18. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/MANIFEST.in +0 -0
  19. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/__main__.py +0 -0
  20. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/profiles/eu-mdr.md +0 -0
  21. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/profiles/iso-13485.md +0 -0
  22. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/profiles/mappings/dds.json +0 -0
  23. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/profiles/mappings/requirements.json +0 -0
  24. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/profiles/mappings/risk-register.json +0 -0
  25. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/profiles/mappings/test-cases.json +0 -0
  26. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/profiles/mappings/user-needs.json +0 -0
  27. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/search.py +0 -0
  28. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/templates/workspace/.gitignore +0 -0
  29. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/templates/workspace/AGENTS.md +0 -0
  30. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/templates/workspace/inbox/.gitkeep +0 -0
  31. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/templates/workspace/index.md +0 -0
  32. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/templates/workspace/log.md +0 -0
  33. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/templates/workspace/profiles/README.md +0 -0
  34. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/templates/workspace/profiles/mappings/.gitkeep +0 -0
  35. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/templates/workspace/schema/entities.json +0 -0
  36. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/templates/workspace/schema/graph.json +0 -0
  37. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/templates/workspace/schema/tags.json +0 -0
  38. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/templates/workspace/sources/.gitkeep +0 -0
  39. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme/templates/workspace/wiki/_templates/page.md +0 -0
  40. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/mneme_cli.egg-info/SOURCES.txt +0 -0
  41. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/setup.cfg +0 -0
  42. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/tests/__init__.py +0 -0
  43. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/tests/test_agent_loop.py +0 -0
  44. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/tests/test_bug_regressions.py +0 -0
  45. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/tests/test_ingest_csv.py +0 -0
  46. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/tests/test_profile.py +0 -0
  47. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/tests/test_schema_search.py +0 -0
  48. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/tests/test_search.py +0 -0
  49. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/tests/test_tornado_lint.py +0 -0
  50. {mneme_cli-0.5.0 → mneme_cli-0.5.2}/tests/test_trace.py +0 -0
@@ -213,6 +213,10 @@ out manually, then run `resync-resolve`.
213
213
  mneme tags suggest <client>/<page> # build tag packet
214
214
  mneme tags suggest <client>/<page> --json # raw dict
215
215
  mneme tags apply <client>/<page> --add t1,t2 --remove t3
216
+
217
+ # Bulk variants -- packet up to N pages in one round-trip
218
+ mneme tags bulk-suggest --client <c> --filter req- --limit 50 --out packet.md
219
+ mneme tags bulk-apply response.json # response: {"pages": [{wiki_path, add, remove}, ...]}
216
220
  ```
217
221
 
218
222
  `mneme tags suggest` builds a **tag packet**: the page content, current
@@ -245,6 +249,124 @@ mneme tags list # all tags + counts
245
249
  mneme tags merge <old> <new> # rename across all pages
246
250
  ```
247
251
 
252
+ ### 3.7 ENTITY — agent-driven classification
253
+
254
+ ```bash
255
+ mneme entity suggest --client <c> --limit 50 # classification packet
256
+ mneme entity apply --id iso-13485 --type standard # one at a time
257
+ mneme entity bulk-apply classifications.json # batch
258
+ ```
259
+
260
+ `mneme entity suggest` builds an **entity packet**: every `unknown`-typed
261
+ entity, the workspace's current type distribution, the valid type
262
+ vocabulary, an example wiki page per entity, and a prompt. The agent
263
+ returns a JSON array of `{id, type}` objects which `bulk-apply` writes
264
+ back atomically. Same philosophy as tags: mneme stays deterministic, the
265
+ LLM does the classification.
266
+
267
+ Valid types: `standard`, `company`, `person`, `product`, `technology`,
268
+ `concept`, `brand`, `unknown`.
269
+
270
+ ### 3.8 HOME — generated landing page
271
+
272
+ ```bash
273
+ mneme home --client <c> # wiki/<c>/HOME.md
274
+ mneme home --all-clients # wiki/HOME.md (cross-client)
275
+ ```
276
+
277
+ Generates an Obsidian-friendly navigation hub with Dataview queries
278
+ (group by type, by ID prefix like `REQ-*` / `DDS-*`, top tags) and a
279
+ plain-markdown `<details>` fallback so the page is useful outside
280
+ Obsidian. Run after a large ingest, or whenever the wiki's shape
281
+ changes meaningfully.
282
+
283
+ ### 3.9 TRACE — linking the full V-model chain
284
+
285
+ The trace chain a notified body expects has two legs that both terminate
286
+ at code and tests:
287
+
288
+ ```
289
+ UN ──implemented-by──┐
290
+ ├──> REQ ──detailed-in──> DDS ──implemented-in──> codebase
291
+ RMA ──mitigated-by────┘ └──verified-by───> tests
292
+ ```
293
+
294
+ The first three links (UN→REQ, RMA→REQ, REQ→DDS) are created
295
+ automatically by the CSV mappings in `profiles/mappings/` (or by
296
+ `mneme trace add` when ingesting structured sources). The last two
297
+ links (DDS→codebase, DDS→tests) close the V-model and are the agent's
298
+ responsibility when a user passes you one or more repositories.
299
+
300
+ **When the user passes you a repo path, you must:**
301
+
302
+ ```bash
303
+ # 1. Inventory: what code modules / test files exist?
304
+ mneme scan-repo <repo-path> <client>
305
+ # → reports which wiki pages reference the repo's modules, and which do not.
306
+
307
+ # 2. For each DDS page that corresponds to a code module, add the link.
308
+ # The target is a git URL or an absolute repo path; mneme treats it
309
+ # as an opaque string (not a wiki slug) — the target may live outside
310
+ # the workspace.
311
+ mneme trace add <client>/dds-cyb-001 \
312
+ "github.com/<org>/<repo>/blob/main/src/auth/password_policy.py" \
313
+ implemented-in
314
+
315
+ # 3. For each DDS page that has a corresponding test, add the link.
316
+ # The test target can be a wiki page (for test-plan docs) or an
317
+ # external path (for a test file in a repo).
318
+ mneme trace add <client>/dds-cyb-001 <client>/test-auth-001 verified-by
319
+ mneme trace add <client>/dds-cyb-001 \
320
+ "github.com/<org>/<repo>/blob/main/tests/test_password_policy.py" \
321
+ verified-by
322
+ ```
323
+
324
+ Do this for every DDS page that has implementing code or a verifying
325
+ test. When there are tens or hundreds of links to create (typical for
326
+ a real medical-device codebase):
327
+
328
+ ```bash
329
+ # Batch approach — the agent parses the repo, maps DDS → files,
330
+ # then writes a shell script of `mneme trace add` lines and runs it.
331
+ # mneme has no bulk-trace-add subcommand yet; scripting is the way.
332
+ for pair in dds-cyb-001:src/auth/password_policy.py \
333
+ dds-cyb-002:src/auth/mfa.py \
334
+ dds-cyb-003:src/auth/rate_limiter.py; do
335
+ dds=${pair%%:*}; file=${pair##*:}
336
+ mneme trace add <client>/$dds "<repo-url>/$file" implemented-in
337
+ done
338
+ ```
339
+
340
+ **Verify the chain is now complete:**
341
+
342
+ ```bash
343
+ mneme trace gaps <client>
344
+ # → should report 0 hazards without mitigation, 0 DDS without
345
+ # implementation link, 0 DDS without verification link
346
+
347
+ mneme trace show <client>/un-001
348
+ # → UN.001
349
+ # implemented-by -> REQ.SYS.001
350
+ # detailed-in -> DDS.CYB.001
351
+ # implemented-in -> github.com/.../password_policy.py
352
+ # verified-by -> github.com/.../test_password_policy.py
353
+ ```
354
+
355
+ **Relationship vocabulary — use exactly these strings:**
356
+
357
+ | Relationship | From → To | Semantics |
358
+ |---|---|---|
359
+ | `implemented-by` | UN → REQ | The user need is met by this requirement |
360
+ | `mitigated-by` | RMA → REQ | The hazard is mitigated by this requirement |
361
+ | `derived-from` | REQ → UN / REQ → higher-level REQ | Parent requirement |
362
+ | `detailed-in` | REQ → DDS | The requirement is elaborated by this design spec |
363
+ | `implemented-in` | DDS → codebase | The design spec is realised by this source file / module |
364
+ | `verified-by` | DDS → test / REQ → test | The spec/requirement is verified by this test |
365
+ | `validated-by` | DDS → clinical/usability study | Validation (not verification) evidence |
366
+
367
+ Stick to this vocabulary. Custom relationships confuse downstream
368
+ matrix exports and break the default `trace gaps` heuristics.
369
+
248
370
  ---
249
371
 
250
372
  ## 4. Profiles and the writing-style contract
@@ -537,7 +659,53 @@ file.
537
659
  Stop conditions: inbox is empty, `mneme stats` shows a plausible page
538
660
  count, and `mneme lint` reports no critical issues.
539
661
 
540
- ### 6.6 Pre-submission readiness check before sending to a notified body
662
+ ### 6.6 Close the V-model by linking DDS to codebase and tests
663
+
664
+ The user has just handed you one or more repositories. Your job is to
665
+ connect every DDS page to the implementing source file(s) and the
666
+ verifying test file(s) so `mneme trace show` walks end-to-end from a
667
+ user need / hazard all the way to the exact line of code and the exact
668
+ test that exercises it.
669
+
670
+ ```
671
+ 1. mneme profile show # sanity check
672
+ 2. mneme trace matrix <client> # baseline — which DDS exist?
673
+ 3. For each repo the user passes:
674
+ a. mneme scan-repo <repo-path> <client> # surface module gaps
675
+ b. Read the repo tree and README yourself.
676
+ Build a mapping: DDS ID -> [source files]
677
+ DDS ID -> [test files]
678
+ Prefer explicit evidence (comments referencing the DDS ID,
679
+ module/function names that mirror the DDS title, docstrings
680
+ that cite the requirement). When evidence is weak, flag the
681
+ DDS as ambiguous and surface it — do not guess.
682
+ 4. For each confident (DDS, file) pair:
683
+ mneme trace add <client>/<dds-slug> "<repo-url-or-path>/<file>" implemented-in
684
+ mneme trace add <client>/<dds-slug> "<repo-url-or-path>/<test-file>" verified-by
685
+ Batch these in a shell loop — there is no bulk-trace-add subcommand.
686
+ 5. mneme trace gaps <client> # should trend to zero
687
+ 6. mneme trace show <client>/un-001 # spot-check: full chain
688
+ from UN to test file?
689
+ 7. mneme trace matrix <client> --csv --out trace-matrix.csv
690
+ # DHF-ready export
691
+ ```
692
+
693
+ Stop conditions: (a) every DDS page either has both `implemented-in`
694
+ and `verified-by` trace links OR is explicitly flagged ambiguous in a
695
+ report to the user, AND (b) `trace gaps` reports zero open chains.
696
+
697
+ Hard rules:
698
+ - Do not fabricate file paths. If the repo has no file matching a DDS,
699
+ report the gap and stop — the user must either point you at another
700
+ repo or add the link manually.
701
+ - Trace targets for external files are opaque strings. Use a stable
702
+ form the team can resolve later (a git URL with a pinned commit is
703
+ ideal; a bare relative path is fine when the repo lives alongside
704
+ the workspace).
705
+ - Never rewrite a DDS page's body to embed the code link. The link
706
+ lives in `schema/traceability.json` only. Wiki pages stay prose.
707
+
708
+ ### 6.7 Pre-submission readiness check before sending to a notified body
541
709
 
542
710
  ```
543
711
  1. mneme profile show # confirm active profile
@@ -4,6 +4,51 @@ All notable changes to this project are documented here.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.5.2] - 2026-04-14
8
+
9
+ ### Changed
10
+
11
+ - **`ingest-dir --preserve-structure` is now the default.** The wiki now
12
+ mirrors the source directory layout unless you pass `--flat`. This avoids
13
+ silent same-basename collisions (e.g. multiple `INSTRUCTIONS.md` files from
14
+ different source directories overwriting each other). Closes suggestion #15.
15
+ - **`mneme ingest` (single-file) also mirrors by default.** When the source
16
+ lives under `sources/<client>/`, its relative position becomes a wiki
17
+ subpath automatically. Pass `--flat` to opt out.
18
+
19
+ ### Fixed
20
+
21
+ - **`mneme profile list`** now discovers profiles correctly. Previously it
22
+ filtered files by `.json` (wrong extension — profiles are markdown) and
23
+ only checked the bundled directory, which meant the shipped `eu-mdr.md`
24
+ and `iso-13485.md` profiles appeared as "No profiles found". Now unions
25
+ workspace + bundled, marks origin, and flags shadowed bundled profiles.
26
+ Closes suggestion #25 discovery bug.
27
+
28
+ ### Added
29
+
30
+ - **`ingest-dir --flat`** — explicit opt-out for the new preserve-structure
31
+ default.
32
+ - **`ingest --flat`** — opt-out for the single-file command.
33
+ - **xlsx support is now built-in.** `openpyxl` moved from
34
+ `[project.optional-dependencies].xlsx` to `dependencies`. The `[xlsx]`
35
+ extra is kept for backwards compatibility but is no longer required.
36
+
37
+ ### Documentation
38
+
39
+ - **README**: expanded the agent end-to-end example. Step 3 now covers
40
+ bulk tagging (`tags bulk-suggest` + `bulk-apply`), Step 3b adds entity
41
+ typing (`entity suggest` + `bulk-apply`), and Step 3c walks the full
42
+ V-model trace chain (UN→REQ→DDS and RMA→REQ→DDS, terminating at code
43
+ and tests).
44
+ - **AGENTS.md**: new section 3.9 "TRACE — linking the full V-model
45
+ chain" documents the `implemented-in` / `verified-by` relationships
46
+ and the DDS-to-codebase linking agents must perform when the user
47
+ passes repositories. New task template 6.6 "Close the V-model by
48
+ linking DDS to codebase and tests" gives the exact procedure, stop
49
+ conditions, and hard rules (no fabricated paths, trace targets are
50
+ opaque strings, never embed code links in page bodies).
51
+
7
52
  ## [0.5.0] - 2026-04-13
8
53
 
9
54
  ### Breaking Changes
@@ -58,6 +103,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
58
103
  - Chunking logic (`chunk_body`, `MAX_CHUNK_SIZE`, frame management).
59
104
  - Tantivy-reserved-word query sanitizer (FTS5 has different syntax).
60
105
 
106
+ ## [0.5.1] - 2026-04-14
107
+
108
+ ### Added
109
+ - **`mneme entity suggest` / `entity apply` / `entity bulk-apply`** — agent-driven
110
+ entity classification (same packet pattern as `tags suggest`). Mneme builds a
111
+ packet of unclassified entities + the workspace type taxonomy + example pages;
112
+ the LLM agent classifies; mneme writes the types back atomically.
113
+ - **`mneme tags bulk-suggest` / `tags bulk-apply`** — operate on many pages at
114
+ once. `bulk-suggest --client X --filter req- --limit 50` packets up to 50
115
+ matching pages; agent returns one JSON file; `bulk-apply` runs all the changes
116
+ with per-page error tolerance. Critical for tagging workspaces of hundreds of
117
+ pages.
118
+ - **`mneme home --client <slug>` / `--all-clients`** — generates a `HOME.md`
119
+ navigation hub with Obsidian Dataview queries (group by type, by ID prefix
120
+ like REQ-*/DDS-*, top tags) plus a plain-markdown `<details>` fallback for
121
+ non-Obsidian viewers.
122
+ - **`mneme ingest-dir --preserve-structure`** — mirrors source directory
123
+ hierarchy into wiki subdirectories. `sources/client/REQUIREMENTS/req-001.md`
124
+ becomes `wiki/client/requirements/req-001.md` instead of flattening. Also
125
+ resolves same-basename-different-directory collisions naturally.
126
+ - **`mneme resync` auto-detects subpath** from a source's location under
127
+ `sources/<client>/`, so resyncs of preserve-structure ingests target the
128
+ correct nested wiki page instead of creating a duplicate flat one.
129
+ - **Progress bar** for `ingest-dir` and `ingest-csv` long loops. TTY-aware
130
+ (in-place updates) with non-TTY fallback (periodic line output) so CI logs
131
+ stay readable.
132
+
133
+ ### Fixed
134
+ - `mneme status` crashed with `UnboundLocalError` because a local `status` in
135
+ the `agent show` branch shadowed the function name throughout `main()`.
136
+ - `wiki/HOME.md` and `wiki/<client>/HOME.md` are now skipped during HOME
137
+ generation so re-running is idempotent.
138
+
61
139
  ## [Unreleased]
62
140
 
63
141
  ### Added
@@ -1,4 +1,4 @@
1
- # Mnemosyne - Wiki Protocol
1
+ # mneme - Wiki Protocol
2
2
 
3
3
  > **If you are an LLM agent driving mneme**, read [AGENTS.md](AGENTS.md) **first**. It is the canonical agent protocol: the agent loop, the standard task templates, the sub-agent spawning patterns, and the hard rules you must never violate. CLAUDE.md (this file) describes the wiki layer; AGENTS.md describes the agent's job.
4
4
 
@@ -1,4 +1,4 @@
1
- # CODER.md - Developer Guide for Mnemosyne
1
+ # CODER.md - Developer Guide for mneme
2
2
 
3
3
  This is the engineering reference for anyone building on or extending mneme. Read this before writing code.
4
4
 
@@ -1,4 +1,4 @@
1
- # EXAMPLES.md - Mnemosyne Usage Guide
1
+ # EXAMPLES.md - mneme Usage Guide
2
2
 
3
3
  Real-world workflows, core concepts, and entity types used in mneme.
4
4
 
@@ -256,7 +256,7 @@ cp ~/old-qms/*.pdf inbox/
256
256
  # Let tornado figure it out
257
257
  mneme tornado --client cardio-monitor
258
258
 
259
- # === Mnemosyne Tornado ===
259
+ # === mneme Tornado ===
260
260
  #
261
261
  # Scanning inbox/... found 50 files
262
262
  #
@@ -1,4 +1,4 @@
1
- # Mnemosyne - Feature Roadmap
1
+ # mneme - Feature Roadmap
2
2
 
3
3
  ## Current Features (v0.4.0)
4
4
 
@@ -34,6 +34,13 @@
34
34
  | `mneme tags merge` | Merge one tag into another across all pages |
35
35
  | `mneme tags suggest <page>` | Build a *tag packet* for an LLM agent (page content + taxonomy + prompt) |
36
36
  | `mneme tags apply <page> --add t1,t2 --remove t3` | Atomic tag update: rewrites frontmatter, updates schema/tags.json, re-syncs FTS5 index |
37
+ | `mneme tags bulk-suggest --client X --filter req- --limit 50` | Bulk tag packet for many pages in one round-trip |
38
+ | `mneme tags bulk-apply response.json` | Apply tag changes from an agent JSON response (per-page error tolerance) |
39
+ | `mneme entity suggest --client X` | Agent-driven entity-classification packet (entities + taxonomy + example pages) |
40
+ | `mneme entity apply --id <id> --type <type>` | Set one entity's type atomically |
41
+ | `mneme entity bulk-apply classifications.json` | Bulk classify entities from a JSON file |
42
+ | `mneme home --client X` / `--all-clients` | Generate a `HOME.md` navigation hub with Dataview queries and plain-markdown fallback |
43
+ | `mneme ingest-dir --preserve-structure` | Mirror source directory hierarchy into wiki subdirectories (resync auto-detects matching subpath) |
37
44
  | `mneme diff` | Git-aware diff for a wiki page |
38
45
  | `mneme snapshot` | Versioned zip archive of a client + git tag |
39
46
  | `mneme dedupe` | Detect near-duplicate wiki pages |
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mneme-cli
3
- Version: 0.5.0
4
- Summary: Mnemosyne - CLI tool that turns documents into a searchable second brain. Ingest once, query forever.
3
+ Version: 0.5.2
4
+ Summary: mneme - CLI tool that turns documents into a searchable second brain. Ingest once, query forever.
5
5
  Author-email: Tolis Moustaklis <apostolos.moustaklis@gmail.com>
6
6
  License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/tolism/mneme
@@ -29,20 +29,20 @@ Requires-Python: >=3.9
29
29
  Description-Content-Type: text/markdown
30
30
  License-File: LICENSE
31
31
  Requires-Dist: portalocker>=2.0.0
32
+ Requires-Dist: openpyxl>=3.1.0
32
33
  Provides-Extra: pdf
33
34
  Requires-Dist: pymupdf>=1.23.0; extra == "pdf"
34
35
  Provides-Extra: xlsx
35
36
  Requires-Dist: openpyxl>=3.1.0; extra == "xlsx"
36
37
  Provides-Extra: all
37
38
  Requires-Dist: pymupdf>=1.23.0; extra == "all"
38
- Requires-Dist: openpyxl>=3.1.0; extra == "all"
39
39
  Provides-Extra: release
40
40
  Requires-Dist: build>=1.0.0; extra == "release"
41
41
  Requires-Dist: twine>=5.0.0; extra == "release"
42
42
  Dynamic: license-file
43
43
 
44
44
  <p align="center">
45
- <img src="https://raw.githubusercontent.com/tolism/mneme/main/assets/logo.png" alt="Mnemosyne" width="400">
45
+ <img src="https://raw.githubusercontent.com/tolism/mneme/main/assets/logo.png" alt="mneme" width="400">
46
46
  </p>
47
47
 
48
48
  <h1 align="center"></h1>
@@ -167,6 +167,13 @@ One installed CLI serves many projects — each workspace is just a directory.
167
167
  | `mneme validate writing-style <page>` | Build a *review packet* for an LLM agent to grade a page |
168
168
  | `mneme tags suggest <page>` | Build a *tag packet* for an LLM agent to choose tags |
169
169
  | `mneme tags apply <page> --add t1,t2 --remove t3` | Atomic tag update (frontmatter + schema + search index) |
170
+ | `mneme tags bulk-suggest --client X --filter req- --limit 50` | Build one *bulk packet* covering many pages |
171
+ | `mneme tags bulk-apply response.json` | Apply tag changes from an agent JSON response |
172
+ | `mneme entity suggest --client X` | Build an *entity-classification packet* for an LLM agent |
173
+ | `mneme entity apply --id <id> --type <type>` | Set one entity's type atomically |
174
+ | `mneme entity bulk-apply classifications.json` | Bulk classify many entities |
175
+ | `mneme home --client X` / `--all-clients` | Generate a `HOME.md` navigation hub (Dataview + fallback) |
176
+ | `mneme ingest-dir --recursive --preserve-structure` | Mirror source directory hierarchy into the wiki |
170
177
  | `mneme agent plan --goal "..." --doc-type <t> --client <c>` | Generate a deterministic TODO plan from the active profile |
171
178
  | `mneme agent next-task` | Return the next ready task in the active plan |
172
179
  | `mneme agent task-done <id>` | Mark a task as done |
@@ -176,7 +183,7 @@ One installed CLI serves many projects — each workspace is just a directory.
176
183
  | `mneme stats` | Health overview |
177
184
  | `mneme repair` | Fix corrupted archives |
178
185
 
179
- **Formats:** `.md`, `.txt`, `.pdf`, `.xlsx` (with `pip install "mneme-cli[xlsx]"`)
186
+ **Formats:** `.md`, `.txt`, `.pdf`, `.xlsx` (built-in), plus `.csv` via `mneme ingest-csv`
180
187
 
181
188
  ---
182
189
 
@@ -231,38 +238,115 @@ Creates the workspace tree, sets the EU MDR writing-style profile, and initializ
231
238
  cp -r ~/Downloads/parkinson-research/* inbox/
232
239
  mneme tornado --client parkiwatch
233
240
 
234
- # Or ingest individual files
241
+ # Or ingest individual files (auto-mirrors sources/<client>/ layout into wiki/)
235
242
  mneme ingest research-paper.pdf parkiwatch
236
- mneme ingest-csv risk-register.csv parkiwatch --mapping risk-register
237
243
  mneme ingest spec-table.xlsx parkiwatch # .xlsx renders sheets as markdown tables
238
- mneme ingest-dir docs/ parkiwatch --recursive # walk subdirectories
244
+ mneme ingest-dir docs/ parkiwatch --recursive # walk subdirectories, preserve structure
245
+
246
+ # Structured CSV ingestion — one row becomes one wiki page + trace links.
247
+ # Mappings live in <workspace>/profiles/mappings/ or are auto-detected.
248
+ mneme ingest-csv user-needs.csv parkiwatch --mapping parkiwatch-user-needs
249
+ mneme ingest-csv requirements.csv parkiwatch --mapping parkiwatch-req
250
+ mneme ingest-csv design-specs.csv parkiwatch --mapping parkiwatch-dds
251
+ mneme ingest-csv risk-register.csv parkiwatch --mapping parkiwatch-rma
239
252
  ```
240
253
 
241
- What happens per ingest: source file → wiki page in `wiki/parkiwatch/` → frontmatter with auto-extracted entities → entry in `index.md` → row in the FTS5 search DB → log entry.
254
+ What happens per ingest: source file → wiki page in `wiki/parkiwatch/<mirrored-subpath>/` → frontmatter with auto-extracted proper-noun entities → entry in `index.md` → row in the FTS5 search DB → log entry. CSV ingests additionally create trace links (e.g. UN→REQ `implemented-by`, REQ→DDS `detailed-in`) in `schema/traceability.json`.
242
255
 
243
- ### Step 3 — Tag the new pages (LLM agent)
256
+ ### Step 3 — Tag many pages at once (LLM agent, bulk)
244
257
 
245
- The new pages have only the auto-applied `parkiwatch` client tag. The agent now adds meaningful tags:
258
+ New pages have only the auto-applied `parkiwatch` client tag. The agent tags them in batches:
246
259
 
247
260
  ```bash
248
- # For each new page, the agent runs:
249
- mneme tags suggest parkiwatch/research-paper > /tmp/packet.md
261
+ # 1. Pack up to 30 untagged pages into a single review packet.
262
+ # --filter scopes by wiki_path substring; omit for everything.
263
+ mneme tags bulk-suggest --filter indicators --limit 30 \
264
+ --json --out /tmp/tag-packet.json
250
265
  ```
251
266
 
252
- The packet contains the page body, the current tag taxonomy (every tag in the workspace + usage counts), and a ready-to-paste prompt. **The LLM reads the packet** — it understands the content and decides on tags, preferring existing taxonomy entries when they fit. The LLM's response is JSON:
267
+ The packet contains, for each page: wiki_path, title, current tags, body excerpt, and the existing taxonomy with usage counts. **The LLM reads the packet** and returns a response JSON:
253
268
 
254
269
  ```json
255
- {"tags": ["clinical-trial", "iso-13485"], "new_tags": ["bradykinesia-detection"]}
270
+ {
271
+ "pages": [
272
+ {"wiki_path": "parkiwatch/indicators/bda_algorithm_description.md",
273
+ "add": ["bradykinesia", "algorithm", "imu", "medical-device"]},
274
+ {"wiki_path": "parkiwatch/indicators/tremor_indicator_dataflow.md",
275
+ "add": ["tremor", "dataflow", "imu", "algorithm"]}
276
+ ]
277
+ }
256
278
  ```
257
279
 
258
- The agent then runs:
280
+ ```bash
281
+ # 2. Apply all decisions in one atomic call
282
+ mneme tags bulk-apply /tmp/tag-response.json
283
+ # → Pages updated: 9 Tags added: 42 Tags removed: 0
284
+ ```
285
+
286
+ Each application rewrites the wiki page frontmatter, updates `schema/tags.json`, re-indexes the page in FTS5, and appends a log entry. Subsequent packets reuse the growing taxonomy, so the vocabulary converges.
287
+
288
+ For single pages use `mneme tags suggest <slug>` + `mneme tags apply <slug> --add a,b,c`.
289
+
290
+ ### Step 3b — Classify entities by type (LLM agent)
291
+
292
+ Ingest auto-extracts capitalized proper nouns (e.g. "Parkiwatch", "IEC 62304") into `schema/entities.json` with `type: unknown`. Typing is an LLM judgement call, handled the same packet way as tags:
259
293
 
260
294
  ```bash
261
- mneme tags apply parkiwatch/research-paper \
262
- --add clinical-trial,iso-13485,bradykinesia-detection
295
+ # 1. Build an entity-classification packet (up to 50 unclassified entities)
296
+ mneme entity suggest --client parkiwatch --limit 50 \
297
+ --json --out /tmp/entity-packet.json
298
+
299
+ # 2. LLM reads the packet and returns classifications:
300
+ # [{"id": "iec-62304", "type": "standard"},
301
+ # {"id": "notified-body", "type": "organization"},
302
+ # {"id": "bradykinesia", "type": "concept"}, ...]
303
+
304
+ # 3. Apply atomically
305
+ mneme entity bulk-apply /tmp/entity-response.json
306
+ # → Entities typed: 47 Errors: 0
307
+ ```
308
+
309
+ Supported types include `standard`, `organization`, `person`, `concept`, `technology`, `regulation`, or any custom type the profile defines. Typed entities power filtered search and the knowledge graph.
310
+
311
+ ### Step 3c — Verify the trace chain (human, on demand)
312
+
313
+ The CSV ingests in Step 2 created two parallel trace chains. Both converge at a requirement, drill into design specs, and finally terminate at **code** and **tests** — the complete QMS traceability an auditor expects:
314
+
315
+ ```
316
+ Chain A: UN ─┐
317
+ ├─> REQ ──> DDS ──┬─> codebase (via `implemented-in`)
318
+ Chain B: RMA ┘ └─> tests (via `verified-by`)
263
319
  ```
264
320
 
265
- Atomic operation: rewrites the wiki page frontmatter, updates `schema/tags.json`, re-indexes the page in FTS5 (so search picks up the new tags immediately), appends a log entry. **Repeat for every page** the taxonomy grows, and subsequent pages tend to reuse existing tags (consistency).
321
+ Each arrow is a trace-link relationship type (`implemented-by`, `mitigated-by`, `detailed-in`, `implemented-in`, `verified-by`). The DDS→codebase link is stored as a frontmatter field on each DDS page (e.g. a git URL pointing at the implementing module). The DDS→tests link is a standard trace relationship added either by CSV ingest or by `mneme trace add`.
322
+
323
+ Walk either chain from any root page:
324
+
325
+ ```bash
326
+ # Chain A — from a user need forward to the specs that implement it
327
+ mneme trace show parkiwatch/un-001
328
+ # → UN.001 (secure sign-in)
329
+ # implemented-by -> REQ.SYS.001 (User Authentication)
330
+ # detailed-in -> DDS.CYB.001 (Strong Password Policy)
331
+ # detailed-in -> DDS.CYB.002 (Multi-Factor Authentication)
332
+ # ...
333
+
334
+ # Chain B — from a hazard forward to the specs that mitigate it
335
+ mneme trace show parkiwatch/rma-cyb-002
336
+ # → RMA.CYB.002 (Unauthorized access -- weak passwords)
337
+ # mitigated-by -> REQ.SYS.001 (User Authentication)
338
+ # detailed-in -> DDS.CYB.001, DDS.CYB.002, ...
339
+ # implemented-in -> src/auth/password_policy.py (codebase)
340
+ # verified-by -> TEST.AUTH.001 (tests)
341
+
342
+ # Trace gaps for a notified body audit
343
+ mneme trace gaps parkiwatch
344
+ # → Hazards with no mitigation: ...
345
+ # User needs with no requirements: ...
346
+
347
+ # Export the full traceability matrix for the DHF
348
+ mneme trace matrix parkiwatch --csv --out trace-matrix.csv
349
+ ```
266
350
 
267
351
  ### Step 4 — Search the knowledge base (anyone)
268
352