ltcai 11.7.0 → 12.0.0

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 (174) hide show
  1. package/README.md +100 -76
  2. package/docs/BENCHMARKS.md +9 -2
  3. package/docs/CHANGELOG.md +249 -0
  4. package/docs/CI_AND_RELEASE_GATES.md +126 -41
  5. package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
  6. package/docs/DEVELOPMENT.md +271 -103
  7. package/docs/ENTERPRISE.md +1 -1
  8. package/docs/LEGACY_COMPATIBILITY.md +10 -6
  9. package/docs/MULTI_AGENT_RUNTIME.md +4 -4
  10. package/docs/ONBOARDING.md +16 -4
  11. package/docs/OPERATIONS.md +14 -1
  12. package/docs/PERMISSION_MODE.md +14 -9
  13. package/docs/REALTIME_COLLABORATION.md +1 -1
  14. package/docs/ROADMAP.md +113 -0
  15. package/docs/TRUST_MODEL.md +28 -7
  16. package/docs/USABILITY_AUDIT.md +5 -0
  17. package/docs/WHY_LATTICE.md +13 -5
  18. package/docs/WORKFLOW_DESIGNER.md +2 -2
  19. package/docs/kg-schema.md +57 -7
  20. package/docs/mcp-tools.md +93 -82
  21. package/docs/security-model.md +6 -3
  22. package/lattice_brain/__init__.py +1 -1
  23. package/lattice_brain/graph/_kg_common/__init__.py +1 -54
  24. package/lattice_brain/graph/_kg_common/extraction.py +459 -105
  25. package/lattice_brain/graph/_kg_common/normalize.py +305 -0
  26. package/lattice_brain/graph/_kg_common/patterns.py +275 -0
  27. package/lattice_brain/graph/_kg_common/relations.py +12 -3
  28. package/lattice_brain/graph/_kg_common/sections.py +107 -0
  29. package/lattice_brain/graph/_kg_common/text.py +14 -450
  30. package/lattice_brain/graph/_kg_constants.py +7 -0
  31. package/lattice_brain/ingestion/__init__.py +6 -3
  32. package/lattice_brain/multimodal/__init__.py +9 -3
  33. package/latticeai/__init__.py +1 -1
  34. package/latticeai/api/agent_worker_seam.py +44 -1
  35. package/latticeai/api/models.py +18 -110
  36. package/latticeai/api/search.py +7 -30
  37. package/latticeai/api/worker_compute.py +127 -106
  38. package/latticeai/api/worker_seams.py +17 -2
  39. package/latticeai/core/embedding_providers/__init__.py +16 -0
  40. package/latticeai/core/embedding_providers/autodetect.py +302 -0
  41. package/latticeai/core/embedding_providers/base.py +25 -0
  42. package/latticeai/core/embedding_providers/profiles.py +44 -0
  43. package/latticeai/core/embedding_providers/text.py +74 -8
  44. package/latticeai/core/http_origin.py +3 -3
  45. package/latticeai/core/messages.py +0 -5
  46. package/latticeai/core/policy.py +1 -6
  47. package/latticeai/core/quiet.py +1 -20
  48. package/latticeai/core/security.py +29 -83
  49. package/latticeai/core/sessions.py +95 -4
  50. package/latticeai/core/users.py +0 -38
  51. package/latticeai/core/vector_index/__init__.py +61 -0
  52. package/latticeai/core/vector_index/hnsw.py +383 -0
  53. package/latticeai/core/vector_index/sidecar.py +329 -0
  54. package/latticeai/models/router/catalog.py +2 -2
  55. package/latticeai/models/router/generation.py +176 -30
  56. package/latticeai/models/router/loading.py +150 -9
  57. package/latticeai/runtime/access_runtime.py +7 -4
  58. package/latticeai/runtime/brain_runtime.py +43 -9
  59. package/latticeai/runtime/build_phases/features.py +8 -31
  60. package/latticeai/runtime/build_phases/foundation.py +7 -16
  61. package/latticeai/runtime/build_phases/web.py +3 -3
  62. package/latticeai/runtime/build_phases/worker_profile.py +29 -27
  63. package/latticeai/runtime/runtime_context.py +0 -2
  64. package/latticeai/services/architecture_readiness.py +18 -19
  65. package/latticeai/services/process_audit.py +1 -22
  66. package/latticeai/services/product_readiness.py +39 -12
  67. package/latticeai/services/search_service.py +7 -0
  68. package/latticeai/services/voice_capture.py +8 -28
  69. package/latticeai/tools/__init__.py +12 -47
  70. package/latticeai/tools/commands.py +9 -15
  71. package/latticeai/tools/documents.py +12 -0
  72. package/latticeai/tools/knowledge.py +0 -6
  73. package/latticeai/tools/markup.py +152 -0
  74. package/package.json +4 -5
  75. package/requirements.txt +0 -1
  76. package/scripts/check_current_release_docs.mjs +1 -1
  77. package/scripts/check_openapi_drift.mjs +3 -2
  78. package/scripts/check_server_i18n.mjs +5 -4
  79. package/scripts/compose_openapi.py +4 -1
  80. package/scripts/export_openapi.py +5 -4
  81. package/scripts/gen_worker_allowlist_fixture.py +2 -2
  82. package/scripts/openapi_route_families.json +19 -74
  83. package/scripts/publish_release.mjs +157 -0
  84. package/scripts/release_screen_claims.json +144 -28
  85. package/src-tauri/Cargo.lock +45 -10
  86. package/src-tauri/Cargo.toml +1 -1
  87. package/src-tauri/tauri.conf.json +1 -1
  88. package/static/app/asset-manifest.json +47 -41
  89. package/static/app/assets/Act-Cf1L2709.js +2 -0
  90. package/static/app/assets/AdminConsole-DPAbLTYV.js +1 -0
  91. package/static/app/assets/Brain-DqamGrj-.js +2 -0
  92. package/static/app/assets/BrainHome-MHe2_RYs.js +2 -0
  93. package/static/app/assets/BrainSignals-CQPPfyyH.js +1 -0
  94. package/static/app/assets/Capture-DGdIH_Zc.js +1 -0
  95. package/static/app/assets/Chronicle-C-UlCJoJ.js +1 -0
  96. package/static/app/assets/CommandPalette-WNT4EqUX.js +1 -0
  97. package/static/app/assets/DigitalBrainExplorer-CEBH5Cwc.js +321 -0
  98. package/static/app/assets/Library-C6xd1dlf.js +1 -0
  99. package/static/app/assets/LivingBrain-BEk-0ohw.js +1 -0
  100. package/static/app/assets/ProductFlow-CZLm5iXh.js +1 -0
  101. package/static/app/assets/QueryClientProvider-B3OjqSyJ.js +1 -0
  102. package/static/app/assets/{ReviewCard-HXRle3qq.js → ReviewCard-CEHG6evf.js} +2 -2
  103. package/static/app/assets/RunsListPanel-CLtEJSRW.js +1 -0
  104. package/static/app/assets/System-CAxwBUXw.js +1 -0
  105. package/static/app/assets/WorkflowGraph-Dj10RuGE.js +1 -0
  106. package/static/app/assets/WorkflowsPanel-Kyeh_LIT.js +2 -0
  107. package/static/app/assets/actHelpers-CtSmK9Dw.js +1 -0
  108. package/static/app/assets/arrow-left-CRl5EO4D.js +1 -0
  109. package/static/app/assets/{bot-Cn8bWRuq.js → bot-DhUGRel2.js} +1 -1
  110. package/static/app/assets/brain-CLkhHsHF.js +1 -0
  111. package/static/app/assets/button-CmaEqG1T.js +1 -0
  112. package/static/app/assets/circle-check-CFgejkOS.js +1 -0
  113. package/static/app/assets/{circle-pause-CmzC_apg.js → circle-pause-l96izbxj.js} +1 -1
  114. package/static/app/assets/{circle-play-D8mW2aQ7.js → circle-play-CrZa25_q.js} +1 -1
  115. package/static/app/assets/{cpu-DZcdd0PZ.js → cpu-BaXudqwl.js} +1 -1
  116. package/static/app/assets/{download-bv1KEPGQ.js → download-hCVFPiyc.js} +1 -1
  117. package/static/app/assets/{folder-open-d-Pip5gr.js → folder-open-CHL82Yp7.js} +1 -1
  118. package/static/app/assets/{hard-drive-D20iavUb.js → hard-drive-DDzET7lk.js} +1 -1
  119. package/static/app/assets/index-CB93CZWW.css +2 -0
  120. package/static/app/assets/index-D2H-wSl6.js +13 -0
  121. package/static/app/assets/input-Df1CAY_I.js +1 -0
  122. package/static/app/assets/jsx-runtime-bzQ4Vb5N.js +1 -0
  123. package/static/app/assets/{link-2-BPJOFlAy.js → link-2-xNnTIX1_.js} +1 -1
  124. package/static/app/assets/{permissionCopy-ChdJd493.js → permissionCopy-D3aWHco-.js} +1 -1
  125. package/static/app/assets/primitives-BioD2slS.js +1 -0
  126. package/static/app/assets/search-BzBw8YcW.js +1 -0
  127. package/static/app/assets/{share-2-YNX_NtMU.js → share-2-FkzGf8Df.js} +1 -1
  128. package/static/app/assets/{shield-alert-DuQ3zrVL.js → shield-alert-B3dwzik4.js} +1 -1
  129. package/static/app/assets/sourceMeta-DQSY_tah.js +1 -0
  130. package/static/app/assets/textarea-P8o6pvOP.js +1 -0
  131. package/static/app/assets/useFocusTrap-hswOIkXE.js +1 -0
  132. package/static/app/assets/useMutation-OJLrYSRA.js +1 -0
  133. package/static/app/assets/workspace-BCuk3Ku9.js +1 -0
  134. package/static/app/index.html +4 -4
  135. package/static/sw.js +1 -1
  136. package/lattice_brain/ingestion/pipeline.py +0 -108
  137. package/latticeai/api/local_files.py +0 -44
  138. package/latticeai/api/tools.py +0 -126
  139. package/latticeai/api/voice_capture.py +0 -32
  140. package/latticeai/core/agent_permission.py +0 -85
  141. package/scripts/agent_eval.py +0 -34
  142. package/scripts/brain_quality_eval.py +0 -37
  143. package/scripts/check_legacy_debt.mjs +0 -91
  144. package/scripts/check_python.py +0 -100
  145. package/scripts/chunking_parity_corpus.py +0 -449
  146. package/scripts/generate_agent_parity_fixtures.py +0 -771
  147. package/scripts/generate_chunking_parity_fixtures.py +0 -259
  148. package/static/app/assets/Act-BPcVAbOL.js +0 -1
  149. package/static/app/assets/AdminConsole-Bw1ATQL0.js +0 -1
  150. package/static/app/assets/Brain-CT92Kos0.js +0 -321
  151. package/static/app/assets/BrainHome-CFBkt1K_.js +0 -2
  152. package/static/app/assets/BrainSignals-ReLWF2H8.js +0 -1
  153. package/static/app/assets/Capture-BsTokYkk.js +0 -1
  154. package/static/app/assets/Chronicle-B6f0T9id.js +0 -1
  155. package/static/app/assets/CommandPalette-CuvjTv1u.js +0 -1
  156. package/static/app/assets/Library-BGJbG9Hd.js +0 -1
  157. package/static/app/assets/LivingBrain-DGYK_Jsa.js +0 -1
  158. package/static/app/assets/ProductFlow-DXBC6brE.js +0 -1
  159. package/static/app/assets/System-CMHSO9qM.js +0 -1
  160. package/static/app/assets/arrow-left-BfmkskWx.js +0 -1
  161. package/static/app/assets/brain-CQJberbE.js +0 -1
  162. package/static/app/assets/button-Ct9f2_oT.js +0 -1
  163. package/static/app/assets/circle-check-DruOxB-4.js +0 -1
  164. package/static/app/assets/index-D9x-kSNy.css +0 -2
  165. package/static/app/assets/index-Do83hDzJ.js +0 -10
  166. package/static/app/assets/input-BLXVNmj1.js +0 -1
  167. package/static/app/assets/primitives-Cv5tbZBY.js +0 -1
  168. package/static/app/assets/search-CT9aho2j.js +0 -1
  169. package/static/app/assets/textarea-DqwLnli4.js +0 -1
  170. package/static/app/assets/useFocusTrap-ZVI98jaW.js +0 -1
  171. package/static/app/assets/useMutation-CVC4qv_D.js +0 -1
  172. package/static/app/assets/useQuery-C7BeG4HU.js +0 -1
  173. package/static/app/assets/utils-CiFtIdZq.js +0 -4
  174. package/static/app/assets/workspace-DQz9vIId.js +0 -1
@@ -0,0 +1,113 @@
1
+ # Lattice AI gap roadmap
2
+
3
+ > **Status: reference** — point-in-time inventory, redated at v12.0.0. Not a
4
+ > canonical current-release document; version gates do not bind it.
5
+
6
+ As of **2026-08-18**, against the 12.0.0 — Open House tree. The rows below
7
+ were gathered against 11.9.0 and re-checked when 12.0.0 shipped; what that
8
+ release closed is marked closed rather than deleted, so the ledger still
9
+ shows what was owed.
10
+
11
+ The owner's v12.0.0 priority was complexity management. The crate maps that
12
+ landed with that work are
13
+ [`rust/lattice-agent/ARCHITECTURE.md`](../rust/lattice-agent/ARCHITECTURE.md)
14
+ and
15
+ [`rust/lattice-platform/ARCHITECTURE.md`](../rust/lattice-platform/ARCHITECTURE.md);
16
+ the contributor path is [DEVELOPMENT.md](DEVELOPMENT.md). This page is the
17
+ honest leftover list, gathered from
18
+ [FEATURE_STATUS.md](../FEATURE_STATUS.md) Known Limitations and the §정직한
19
+ 고지 sections of
20
+ [RELEASE_NOTES_v11.9.0.md](../RELEASE_NOTES_v11.9.0.md) and
21
+ [RELEASE_NOTES_v12.0.0.md](../RELEASE_NOTES_v12.0.0.md).
22
+
23
+ Four items those ledgers named **closed in 12.0.0**. They are kept below so
24
+ they are not re-opened as work. Everything else is still open.
25
+
26
+ Difficulty: **S** one focused change · **M** a vertical slice · **L** a
27
+ program (credentials, a model harness, or an index format).
28
+
29
+ ## Closed in 12.0.0 — do not treat as open
30
+
31
+ | 무엇 | 어떻게 닫혔나 | 11.9.0 장부에 적혀 있던 말 |
32
+ | --- | --- | --- |
33
+ | Restore-then-read in a long-lived process | **Closed.** The store carries a generation epoch: a restore bumps it, connections opened under the old generation are stale at their next checkout, and the next read sees restored bytes. No restart. | 복원 뒤 커넥션이 재활용되기 전까지 복원 전 바이트를 줄 수 있다. |
34
+ | brew / pip setup items | **Closed, without turning into automation.** `/setup/install` runs brew/pip/uv for an item the request names *and* the server-derived allowlist contains; anything else is refused by name, and the default path is still manual. | 설계상 수동. |
35
+ | `POST /mcp` outside the OpenAPI product contract | **Closed.** Declared in the mount table as one JSON-RPC envelope operation, so it generates into the spec; natively mounted, so it is never proxied to the worker. | 계약 밖은 설계. |
36
+ | Pointer tools undeclared | **Closed.** `pip install "ltcai[pointer]"` is a named extra. A stock install still answers `pointer_tools=false` — the gap was the undeclared capability, not the default. | 재고 설치에서는 unavailable. |
37
+
38
+ Two more moved a long way without closing, and their rows below say so
39
+ rather than being deleted: the small-model harness (P1) and the HNSW index
40
+ (P2).
41
+
42
+ ## P1 — default path is wrong or the headline lies
43
+
44
+ | 무엇 | 왜 남았나 | 난이도 | 우선순위 | 제안 경로 |
45
+ | --- | --- | --- | --- | --- |
46
+ | **Small-model agent-run content quality** | **Half closed in 12.0.0.** The mechanical half is done: the `guided` profile stops asking for JSON, the dial is chosen by a measured probe, a run that produces nothing demotes itself downward mid-run, and a 0.5B model reached `DONE` in 3.9s with a real file. The half still open is the *writing* — a weak summary fails the critic and the run ends `FAILED` / `NEEDS_REVIEW`. The cross-model matrix is improving from 11 of 18. | L | **P1** — still the voice the product ships on 8GB, and still the reason a first run can end in a review state. | Keep measuring with the loop's own parser, not a second harness. New answers go under new fixture keys (`agent_loop` `*_extended`); do not rewrite frozen rows. The remaining lever is content, not format: better plan→content prompting and a critic that says *what* was thin, per-model hacks still forbidden. |
47
+ | **Real-embedding default rollout** | **Narrowed in 12.0.0, not closed.** Auto-detection now adopts a real downloaded embedding model when one is present, the hash model is labelled `fallback` rather than presented as semantic, and vector identity is filtered by `(model, dim)` so two spaces cannot mix. What is still true: on a machine that has downloaded nothing, the default remains `lattice-local-hash-v1` (blake2 bag-of-features), and "semantic" recall is then a hash of tokens. | M | **P1** — recall is the product. Hash as a labelled fallback is fine; hash as the silent default is not. | Make the first-run flow offer the embedding model the way it offers a chat model, and keep the switch honest: drain the backlog through `lattice-jobs` so a change of embedder is a reindex, and report `stale_embedder` until the queue is empty. |
48
+ | **Worker-side batch embed** | **Mostly closed in 12.0.0 on the drain path**: embedding moved ahead of the write transaction, so the writer no longer holds a lock while a model runs — ~66 → ~1,300 items/s, and a 991-item backlog drains in 15.3s instead of ~40 minutes. What remains is the ingest-time door: it batches only when `(model_id, dim)` already agrees, and the hash path still embeds inline, one node at a time. | M | **P1** — the backlog path is fast now; a real-embed default still needs the inline door not to serialise against the single MLX executor. | Make `GraphWriter::write_vectors_with` + one `/worker/embed` call the ingest-time path whenever a provider is bound. Keep the drain planner as the backlog path. Do not open a second embedder inside `lattice-core`. |
49
+
50
+ ## P2 — real, but the product still works without them
51
+
52
+ | 무엇 | 왜 남았나 | 난이도 | 우선순위 | 제안 경로 |
53
+ | --- | --- | --- | --- | --- |
54
+ | **HNSW whole-rebuild** | **Closed in 12.0.0; the default is deliberately unchanged.** The sidecar appends incrementally instead of being invalidated by every write, and the index is now used in real search: `hnsw+rescore` fetches `k * 8` candidate ids (cap 200) from `POST /worker/vector/query` and rescores exactly those rows natively, so recall is approximate and ordering is exact. Failures fall back to the exact scan carrying their reason. | L | **P2 → resolved for scale; the default stays `brute`.** | Nothing to build. The remaining decision is when to flip the default, and that needs recall@10 re-measured against the exact scan on a Brain that has been ingesting continuously — not a synthetic corpus. |
55
+ | **Unsigned DMG** | `Lattice AI_12.0.0_aarch64.dmg` is ad-hoc signed (= unsigned). First launch needs the Gatekeeper bypass. `npm run release:validate` checks names and presence, not a Developer ID. | M | **P2** — first-run tax on desktop, not a Brain bug. Needs an Apple identity. | Developer ID Application + notarization in the release path. Exact artifact name stays `dist/…` / `src-tauri/target/release/bundle/dmg/Lattice AI_X.Y.Z_aarch64.dmg`. Credentials stay off the tree. |
56
+ | **`api_key` cloud path is mock-only** | Contract-tested against a mock server. Never live-called — no billing budget. Live E2E is `cli_oauth` (`agy` / `grok`) at zero API billing. | S | **P2** — the supported cloud path already works. This is the paid-key twin. | One live contract test against a real OpenAI-compatible endpoint once a budget exists. Do not call the mock path "verified" in FEATURE_STATUS. Keep `local_only` winning on the request. |
57
+ | **Vault-watch full-resync** | **Largely closed in 12.0.0**: the ingest fingerprint (size + mtime + content sha256) is on the watch path, so an unchanged note is not re-read, re-chunked or re-embedded. The pass itself still runs once through the bridge, because link edges need node ids only a completed ingest has. Cap is still 2,000 notes/run (`truncated: true`), still off by default. | M | **P2** — the wasteful part is gone; the shape of the pass is unchanged. | Attach links from the ids that already landed so the bridge does not need a whole pass at all. Keep the 2,000 cap and the `truncated` flag. Inline `#tags` stay out of scope. Watch still never deletes — cleanup is the confirmed prune door. |
58
+ | **Self-Model has no screen** | Writes were restored in 11.7.0. `GET/POST/DELETE /api/memory/self-model*` and Review Center proposals work. `/app` has no profile view — "Brain이 나에 대해 뭐라고 생각하나" is an API call. | M | **P2** — the data path is real; the reader cannot see it. | A panel under `frontend/src/features/brain/` + `frontend/src/i18n/brain/`, reading the existing API. No new writer. Vitest 100% `all: true`. |
59
+
60
+ ## P3 — honesty leftovers that should not grow
61
+
62
+ | 무엇 | 왜 남았나 | 난이도 | 우선순위 | 제안 경로 |
63
+ | --- | --- | --- | --- | --- |
64
+ | **API 오류 영어 리터럴** | FEATURE_STATUS carried a 10.9.0 inventory (17 of 50 *Python* routers) until 12.0.0 corrected it. After 11.6.0 the product routers are Rust. The live ratchet (`scripts/check_server_i18n.mjs`) locks **4** worker routers and reports **2** unclaimed (`health`, `search`). The larger leftover is native Rust `detail` strings that never entered `latticeai/core/messages.py`. | M | **P3** — the everyday SPA path is Korean. This is the remaining API/error English. | Finish the two worker routers (add them to `LOCALIZED`). Then a Rust-side catalog + a ratchet over `lattice-platform` / `lattice-auth` refusals. The 10.9.0 sentence is gone from FEATURE_STATUS as of 12.0.0; do not reintroduce it. |
65
+ | **Image evidence does not keep the original** | An `Image` citation shows the 96px inline `data:` thumbnail stored at ingest, capped at 24 KB. Serving the real file would need a new static route over the user's disk or a reuse of `/local/serve` (every read passes an explicit approval). | M | **P3** — the thumbnail is an honest preview, not a fake original. Missing the file is a proof gap, not a crash. | Approval-gated `/local/serve` (or a content-addressed blob route that still requires consent). Keep the `data:` thumbnail as the no-approval preview. Do not add an ungated static mount. |
66
+
67
+ ## Other leftovers — named, not dropped
68
+
69
+ These stay on the honesty ledger through 12.0.0. They are not P1. Do not
70
+ quietly delete the row.
71
+
72
+ | 무엇 | 왜 남았나 | 난이도 | 우선순위 | 제안 경로 |
73
+ | --- | --- | --- | --- | --- |
74
+ | Self-Model extraction is a phrase table; no `refiner` is wired | First-person ko/en patterns only. Survivable because every candidate is a proposal. | M | P3 | Optional model `refiner` behind a flag; keep proposal-first. |
75
+ | Self-Model `open_keys` accepts `pending` only | Python also accepted `snoozed`. Port narrowed on purpose. | S | P3 | Add `snoozed` only with a fixture row, not a silent widening. |
76
+ | `delete_node` leaves the `PART_OF` edge | Same as Python. 12.0.0's prune door sidesteps it by using `delete_document_tree` (both directions, zero dangling); the primitive itself is unchanged. | S | P3 | Decide whether to cascade; do not "fix" it in one crate only. |
77
+ | `POST /knowledge-graph/ingest` is text-only | Contract, not a missing parser. Binary ingest is `/upload/document` → `/worker/parse`. | — | — | Keep. Document, do not "open it up". |
78
+ | Review mutation is two store cycles | One writer, two transactions. | M | P3 | Collapse only if a single txn can carry both without a second `workspace_os.json` writer. |
79
+ | Review events silent without an installed owner | Standalone retrieval process has no owner to attribute. | S | P3 | Fail closed to "unsigned event", never invent an owner. |
80
+ | Long download is not cancellable | Closing the tab leaves the pull running on its worker thread. | M | P3 | Cooperative cancel on `POST /models/load` / `prepare-model`. |
81
+ | Quantized vector backend: no memory win, ~2.2× slower | int8 codes are 8× smaller; peak RSS barely moves because SQLite rows dominate. | L | P3 | Hold as the representation a disk-resident index would need. Do not recommend it. |
82
+ | No vision or speech model ships; video needs `ffmpeg` | Runtime refusals, honestly labelled. | — | — | Keep. Nothing is fabricated to fill those fields. |
83
+ | Image/video observation functions have no HTTP door | 11.8.0 deleted the only route; it wrapped a native ingest that was never built. | M | P3 | Do not restore a door nobody calls. Ingest-time observation stays in Brain Core under unit test. |
84
+ | Text→image fusion needs a shared-space vision model | Off by default; the response says so when the tower is missing. | M | P3 | Keep the honesty. Do not return text-only ranking as if fusion ran. |
85
+ | Interop bridges read exports, never a vendor API | Notion zip, local git, local `.eml`/`.ics`. No IMAP, no Notion API. | L | P3 | Stay "point me at what you exported". |
86
+ | Reorganization is one topic level and has no one-click undo | `topics/<주제>/`; no delete path; putting files back is a new proposal. | M | P3 | A reverse proposal at apply-time if undo is wanted. |
87
+ | Browser extension language follows the browser | Separate origin; cannot read `lattice.language`. | M | P3 | Server-side language preference, then both clients read it. |
88
+ | No real-model CI runner | `agent-smoke.yml` was deleted because hosted runners have no MLX and the job failed open. | L | P3 | Restore only on a runner that actually loads a model. A fail-open job is worse than none. |
89
+ | Conversation artifact ledger is process-local | Minutes, not days. After restart, retrieval covers it. | S | P3 | Persist only if a test shows a user-visible hole after reboot. |
90
+
91
+ ## Design boundaries — not a close-me
92
+
93
+ These were removed or scoped on purpose. A roadmap item that "restores
94
+ Telegram" or "turns hash embeddings back into the only story" is a product
95
+ decision, not a bug.
96
+
97
+ - Telegram bridge and SSO/OIDC login/callback — removed in 11.6.0 with the
98
+ platform code that became the worker. Password login is native; the SSO
99
+ *configuration* surface remains.
100
+ - Python coverage gate is a **line floor of 90** (11.8.0). Measured coverage
101
+ is much higher; the enforced claim is the floor.
102
+ - Frozen HTTP / agent / retrieval goldens keep keys for surfaces that no
103
+ longer exist. That is the point of a frozen record. Do not rewrite them to
104
+ match today's tree.
105
+
106
+ ## How to use this
107
+
108
+ Close a row by changing the code, then moving the row into a release note
109
+ — not by editing this file ahead of the work. 12.0.0 shipped, so the four
110
+ rows it closed are marked closed above and the rows it moved say how far;
111
+ FEATURE_STATUS and the release notes carry the same statements. This
112
+ reference page is redated at each release, not silently rewritten to look
113
+ current.
@@ -1,6 +1,6 @@
1
1
  # Lattice AI Trust Model
2
2
 
3
- Current release: **11.7.0 — Clean Sweep**.
3
+ Current release: **12.0.0 — Open House**.
4
4
 
5
5
  Lattice AI is local-first, explicit about external communication, and honest
6
6
  when a capability is unavailable.
@@ -24,10 +24,18 @@ Local data can include:
24
24
 
25
25
  External communication requires configuration plus a user/admin action:
26
26
 
27
- - cloud model calls after keys are configured and a cloud model is selected;
27
+ - cloud model calls after credentials resolve (`cloud_provider.json` / env
28
+ key / locally OAuth-authenticated `agy` or `grok`) and the escalation
29
+ policy — or an explicit `/cloud` prefix — uses them. Every such turn
30
+ writes a shape-only egress audit (provider / model / reason, never
31
+ content) and stages extracted knowledge as a Review Center proposal;
28
32
  - model downloads from registries after install consent;
29
- - Telegram bridge after the integration is enabled, the chat is allowlisted,
30
- and a dedicated server session bearer is configured;
33
+ - package installs from `/setup/install` (brew / pip / uv) — only for an item
34
+ the request names that the **server-derived** allowlist also contains, with
35
+ the command taken from the server's own plan rather than from the request;
36
+ the default path remains manual;
37
+ - Telegram bridge — removed in 11.6.0 with the platform code that became
38
+ the AI worker; nothing replaces it;
31
39
  - Brain Network peer actions after pairing;
32
40
  - Docker/Postgres setup after opt-in scale configuration;
33
41
  - update checks only when enabled;
@@ -51,9 +59,19 @@ Lattice AI should fail closed or show an unavailable state for:
51
59
  - no graph/context evidence available;
52
60
  - unavailable external integration;
53
61
  - unknown or unreadable Knowledge Graph workspace scope;
54
- - missing Telegram chat allowlist or dedicated server session token;
62
+ - Telegram inbound (the bridge was removed in 11.6.0; nothing replaces it);
55
63
  - wrong archive passphrase;
56
- - archive tampering, unsupported archive versions, or path traversal.
64
+ - archive tampering, unsupported archive versions, or path traversal;
65
+ - a hash-fallback embedder standing in for a real one — it is labelled
66
+ `fallback`, never presented as semantic recall;
67
+ - an opted-in approximate vector index that cannot answer — the search falls
68
+ back to the exact scan and carries the reason rather than returning a
69
+ shorter list;
70
+ - a model that cannot produce a tool call — the run is guided through numbered
71
+ choices under the same gates, and an unverifiable result is still
72
+ `NEEDS_REVIEW`;
73
+ - deleting knowledge — a vanished file is reported and only a confirmed prune
74
+ removes its subtree.
57
75
 
58
76
  ## Product Boundary
59
77
 
@@ -67,7 +85,10 @@ does not mean secrets should appear in clear text.
67
85
  - Local files are only as protected as the user's machine, OS account, backups,
68
86
  and disk encryption.
69
87
  - Cloud model prompts follow the selected provider's policy once the user
70
- explicitly chooses that provider.
88
+ explicitly chooses that provider (or the `auto`/`always` escalation
89
+ policy does, behind `cloud_allowed`). The `api_key` path is
90
+ mock-verified only in this release; live OAuth used `cli_oauth` at
91
+ zero billing. Extracted cloud knowledge is proposal-first.
71
92
  - A local admin can inspect local files and process memory outside Lattice AI.
72
93
  - Marketplace and model registries are third-party services when explicitly
73
94
  contacted.
@@ -86,6 +86,11 @@ Heuristics:
86
86
 
87
87
  ## Journey 4 — Brain hierarchy
88
88
 
89
+ > **Dated snapshot (2026-07-21).** `DepthEmergence.tsx` was deleted in v11.8.0
90
+ > when the Brain home was redesigned; the depth-tiered reveal it describes is no
91
+ > longer how the home discloses structure. The findings below are kept as the
92
+ > record of what was evaluated at the time, not as current-truth surface notes.
93
+
89
94
  Surface: `frontend/src/features/brain/DepthEmergence.tsx`,
90
95
  `.../BrainMemoryLayer.tsx`.
91
96
 
@@ -1,6 +1,6 @@
1
1
  # Why Lattice AI Exists
2
2
 
3
- Current release: **11.7.0 — Clean Sweep**.
3
+ Current release: **12.0.0 — Open House**.
4
4
 
5
5
  **Lattice AI is a local-first Digital Brain that keeps your knowledge durable
6
6
  across any AI model.**
@@ -25,8 +25,9 @@ material. That breaks down for real work:
25
25
  ## The Lattice Answer
26
26
 
27
27
  Lattice AI keeps conversations, documents, memories, decisions, relationships,
28
- and source provenance in a private local Brain. Models can be local, cloud,
29
- current, or future. The Brain remains.
28
+ and source provenance in a private local Brain. Models can be local, or an
29
+ optional cloud worker you hire (OAuth CLI or an API key). Default is local.
30
+ The Brain remains.
30
31
 
31
32
  The graph matters as visible proof, but a graph editor is not the product
32
33
  identity. The product identity is a local-first Digital Brain: the user talks or
@@ -48,10 +49,17 @@ secondary.
48
49
  - Ask what the team decided and see the source.
49
50
  - Add documents and build a searchable private memory.
50
51
  - Prepare from old notes, project decisions, and files.
51
- - Preserve context when moving between models.
52
+ - Preserve context when moving between models. Cloud is optional; default
53
+ is local.
52
54
  - Export or restore the Brain as an encrypted `.latticebrain` archive.
53
- - Use Korean or English without changing the underlying Brain.
55
+ - Use Korean or English without changing the underlying Brain. Korean queries
56
+ are read as Korean, particles and all, rather than as strings that happen to
57
+ share a prefix.
54
58
  - Avoid fake answers when no model or evidence is available.
59
+ - Run on the model your machine can actually hold. The loop measures what a
60
+ model can produce and adapts to it — a model too small to emit a tool call is
61
+ walked through numbered choices instead of being told it failed — with the
62
+ same permission gates and safeguards on every path.
55
63
 
56
64
  ## What Lattice AI Is Not
57
65
 
@@ -8,9 +8,9 @@ node to an injected *runner* that calls the real tool registry, skill registry,
8
8
  plugin registry, or multi-agent orchestrator.
9
9
 
10
10
  The execution model lives in
11
- [`rust/lattice-platform/src/workflow_designer/definition.rs`](../rust/lattice-platform/src/workflow_designer/definition.rs)
11
+ [`rust/lattice-platform/src/governance/workflow_designer/definition.rs`](../rust/lattice-platform/src/governance/workflow_designer/definition.rs)
12
12
  (pure logic with injected runners) and the HTTP surface lives in
13
- [`rust/lattice-platform/src/workflow_designer/handlers.rs`](../rust/lattice-platform/src/workflow_designer/handlers.rs).
13
+ [`rust/lattice-platform/src/governance/workflow_designer/handlers.rs`](../rust/lattice-platform/src/governance/workflow_designer/handlers.rs).
14
14
  Both moved from Python in 11.6.0.
15
15
  Persistence reuses the existing `WorkspaceOSStore`, so pre-2.0 workflow history
16
16
  is preserved.
package/docs/kg-schema.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Knowledge Graph Schema
2
2
 
3
- Current release: **11.7.0 — Clean Sweep**.
3
+ Current release: **12.0.0 — Open House**.
4
4
 
5
5
  명세 출처: `lattice_ai_full_spec.pptx` 슬라이드 20·21·22
6
6
  구현: `lattice_brain/graph/schema.py`
@@ -106,6 +106,7 @@ Edge {
106
106
  | `ORGANIZATION` | 조직 / 회사 / 팀 | `domain`, `members[]` |
107
107
  | `WORKFLOW` | 워크플로우 정의/실행 | `workflow_id`, `status` |
108
108
  | `AGENT` | 에이전트(역할/실행 주체) | `role`, `model_id` |
109
+ | `SECTION` | 문서의 한 절 (제목 하나가 덮는 범위) | `heading_path`, `depth`, `document` — v12.0.0부터 실제로 쓰인다 |
109
110
 
110
111
  ### 추가 엣지 타입
111
112
 
@@ -115,11 +116,48 @@ Edge {
115
116
  | `MODIFIED_BY` | ANY → `PERSON` | 마지막 수정자 |
116
117
  | `BELONGS_TO_PROJECT` | ANY → `PROJECT` | 프로젝트 귀속 |
117
118
  | `PART_OF` | ANY → ANY | 구성요소 관계 |
119
+ | `HAS_CHUNK` | `SECTION` → `CHUNK` | 이 절에 속한 텍스트 |
120
+ | `CONTRADICTS` | ANY ↔ ANY | 두 진술이 서로 상충함 |
118
121
  | `DISCUSSED_IN` | `CONCEPT`·`DECISION` → `MEETING`·`CHAT` | 어디에서 논의됨 |
119
122
  | `DECIDED_BY` | `DECISION` → `PERSON` | 결정 주체 |
120
123
  | `GENERATED_BY` | ANY → `AGENT`·`MODEL`·`WORKFLOW` | 생성 주체 |
121
124
  | `USED_BY_AGENT` | ANY → `AGENT` | 에이전트가 사용함 |
122
125
 
126
+ ### 섹션 트리 (v12.0.0)
127
+
128
+ `Section` 노드 타입과 `PART_OF` / `HAS_CHUNK` 엣지는 이전부터 분류 체계에
129
+ 있었지만 **쓰는 사람이 없었다**. v12.0.0부터 타입드 청커의 `heading_path`
130
+ (`" > "`로 이어 붙인 제목 자취, 예: `아키텍처 > 저장소`)가 청크 메타데이터
131
+ 문자열에서 멈추지 않고 그래프의 나무가 된다:
132
+
133
+ ```
134
+ Document ──◄PART_OF── Section(아키텍처) ──◄PART_OF── Section(아키텍처 > 저장소)
135
+ │
136
+ HAS_CHUNK
137
+ ▼
138
+ Chunk
139
+ ```
140
+
141
+ | 요소 | 규칙 |
142
+ |------|------|
143
+ | `Section` 노드 | `label`은 그 절의 제목(마지막 마디), 전체 자취는 `attrs`에. id는 (문서, 제목 자취)의 결정적 해시라 재수집이 멱등이다 |
144
+ | `Section —PART_OF→ Section`·`Document` | 목차의 등뼈. 부모가 없는 최상위 절은 문서에 직접 붙는다 |
145
+ | `Section —HAS_CHUNK→ Chunk` | 어느 텍스트가 이 제목 아래 있는가 |
146
+ | 제목이 없는 문서 | **섹션을 만들지 않는다.** 파일마다 "제목 없는 절"을 하나씩 지어내면, 저자가 쓴 적 없는 것의 이름을 그래프에 넣는 셈이다 |
147
+ | 쓰기 경로 | 문서가 먼저 착지한 뒤 공개 `GraphWriter::upsert_nodes` / `upsert_edges` 문으로만 — 스키마는 넓어지지 않는다 |
148
+
149
+ 이로써 「이 사실은 어느 절에서 나왔나」와 「그 절에 또 뭐가 있나」가 둘 다
150
+ 답 가능한 질문이 된다. 릴리스 코퍼스 실측: 트리플 **555개 중 549개**가
151
+ 섹션 출처를 가진다.
152
+
153
+ ### 상충 관계와 근거 분류 (v12.0.0)
154
+
155
+ `CONTRADICTS`도 어휘에만 있던 타입이었다. v12.0.0부터 추출이 `PART_OF`와
156
+ `CONTRADICTS`를 **실제로 생산**하고, 엣지는 방향과 타입을 갖고 쓰이며,
157
+ `evidence`는 그 관계가 동사에서 왔는지 공기(co-occurrence)에서 왔는지로
158
+ 분류되어 저장된다. 상충 자체는 자동으로 해소되지 않는다 — Review Center
159
+ 제안으로 올라가고, 사람이 승인해야 `valid_from`/`valid_to`가 찍힌다.
160
+
123
161
  ### 통합 수집 형태 (Unified Ingestion)
124
162
 
125
163
  모든 출처는 동일한 형태로 그래프에 들어온다:
@@ -142,8 +180,12 @@ provenance(source_type, source_uri, content_hash, captured_at, modified_at,
142
180
  범위 없는 로컬 폴더는 개인 Brain으로 재투영하되 기존 노드 ID는 보존하며,
143
181
  같은 폴더를 다른 워크스페이스로 조용히 재할당하지 않는다.
144
182
 
145
- 구현: `lattice_brain/ingestion/` (`IngestionPipeline`) 가 단일 진입점이며,
146
- 파일/로컬폴더/URL/브라우저 탭/텍스트를 모두 이 형태로 정규화한다.
183
+ 구현: 단일 진입점은 v11.6.0부터 Rust의 네이티브 ingest 문
184
+ (`lattice-ingest` → `lattice_core::graph_write`)이며, 파일/로컬폴더/URL/
185
+ 브라우저 탭/텍스트를 모두 이 형태로 정규화한다. `lattice_brain/ingestion/`은
186
+ 양쪽이 공유하는 어휘 — 라우팅 상수, DTO, 콘텐츠 해시, 추출 품질 점수 — 만
187
+ 남았고, v11.8.0이 마지막 잔재였던 `IngestionPipeline` 능력 프로브 클래스를
188
+ 그 유일한 호출 라우트와 함께 삭제했다.
147
189
 
148
190
  ---
149
191
 
@@ -224,10 +266,18 @@ v2 로 백필한다. 기존 `nodes` / `edges` 테이블은 삭제하지 않는
224
266
 
225
267
  - 차원: 환경 변수 `LATTICEAI_EMBED_DIM` (기본 `1024`)
226
268
  - 저장: SQLite `BLOB` 컬럼, `struct.pack('<{n}f', …)` 직렬화
227
- - 검색: `knowledge_graph.KnowledgeGraphStore.vector_search` — 순수 Python
228
- 코사인 (sqlite-vec/ANN 인덱스는 아직 없음). 기본 임베더는 해시 기반
229
- 폴백(`grade='fallback'`)이며, 실제 임베딩 모델은 setup wizard 를 통해
230
- 사용자 동의 하에 프로비저닝한다.
269
+ - 검색: 기본은 **정확 스캔(`brute`)** 코사인이다. v12.0.0부터
270
+ `LATTICEAI_VECTOR_INDEX=hnsw`를 켜면 워커 사이드카
271
+ (`POST /worker/vector/query`)가 `k * 8`개(최대 200) 후보 id를 주고,
272
+ 네이티브 쪽이 **브루트와 같은 코사인으로 그 행들을 다시 채점**한다 —
273
+ 근사 리콜, 정확 순서, 이름은 `hnsw+rescore`. 사이드카가 답하지 못하면
274
+ 사유를 실은 채 정확 스캔으로 떨어진다. `.hnsw` 사이드카는 증분
275
+ append이므로 쓰기 한 번이 인덱스 전체를 무효화하지 않는다.
276
+ - 임베더: v12.0.0부터 **자동 감지**한다 — 다운로드된 실제 임베딩 모델이
277
+ 있으면 채택하고, 없으면 해시 기반 폴백(`grade='fallback'`)을 **폴백이라고
278
+ 표기한 채** 쓴다. 해시를 의미 벡터로 부르지 않는다. 벡터 정체성은
279
+ `(model, dim)`으로 필터되므로 서로 다른 임베딩 공간이 조용히 섞이지
280
+ 않는다.
231
281
  - 키워드 검색: v4 부터 FTS5 trigram 인덱스(`node_fts`) 가 LIKE 스캔을
232
282
  대체한다 (한국어 부분 문자열 리콜 유지). FTS5/trigram 이 없는 SQLite
233
283
  빌드에서는 LIKE 경로가 그대로 동작하며 `index_status().storage.fts_enabled`
package/docs/mcp-tools.md CHANGED
@@ -4,7 +4,11 @@ Lattice AI는 MCP(Model Context Protocol) 서버로 동작하여 Claude Desktop,
4
4
 
5
5
  ## 연결 설정
6
6
 
7
- `claude_desktop_config.json` 또는 Cursor MCP 설정:
7
+ The MCP surface is **streamable HTTP JSON-RPC** at `POST /mcp` on the
8
+ loopback gateway (default `http://localhost:4825`). There is no separate
9
+ stdio or SSE transport.
10
+
11
+ `claude_desktop_config.json` or Cursor MCP settings:
8
12
 
9
13
  ```json
10
14
  {
@@ -16,112 +20,119 @@ Lattice AI는 MCP(Model Context Protocol) 서버로 동작하여 Claude Desktop,
16
20
  }
17
21
  ```
18
22
 
19
- ## 도구 목록
20
-
21
- ### 파일 시스템
22
-
23
- | 도구 | 설명 | 위험도 |
24
- |------|------|--------|
25
- | `read_file` | 파일 읽기 (라인 번호, offset/limit 지원) | 낮음 |
26
- | `edit_file` | 정밀 diff 편집 (`old_string` 유일성 검증) | 중간 |
27
- | `list_dir` | 디렉토리 목록 | 낮음 |
28
- | `grep` | 정규식 검색, glob 필터, context_lines | 낮음 |
29
-
30
- ### 실행
23
+ Auth is the same session gate as every other product route:
24
+
25
+ - Loopback install with authentication off → the anonymous local owner (this
26
+ is what a localhost client such as Claude Desktop uses).
27
+ - Authentication on → send the `session_token` cookie or
28
+ `Authorization: Bearer <token>`.
29
+
30
+ Supported JSON-RPC methods: `initialize`, `notifications/initialized`,
31
+ `tools/list`, `tools/call`. Unknown methods return `-32601`. Notifications
32
+ have no result body (`202`).
33
+
34
+ Every native tool call goes through the existing tool governor. A governance
35
+ refusal is a JSON-RPC error (`-32001`), not a successful tool result.
36
+
37
+ **Since v12.0.0 `POST /mcp` is inside the OpenAPI product contract.** It is
38
+ declared in the gateway's mount table as a **single JSON-RPC envelope
39
+ operation** — one path, one method, one request/response shape, with the
40
+ method vocabulary above carried in the body rather than in the URL. Through
41
+ v11.9.0 it sat outside the contract by design; being outside a contract is not
42
+ the same as being safe to leave undescribed, so it is now generated into the
43
+ spec like every other product route. Two consequences worth knowing:
44
+
45
+ - The route is **natively mounted**, so it is answered in-process and never
46
+ proxied to the Python worker — the worker's committed allowlist does not
47
+ carry it, and the gateway forwards nothing that is not on that list.
48
+ - The agent loop reaches the same governance. A run's unified tool catalog
49
+ exposes `mcp.<tool>` beside native tools and skills, and dispatching one
50
+ runs the very governance check this endpoint runs. A name the run already
51
+ governs takes the stricter native path instead, so the MCP prefix can never
52
+ be the quieter way to call the same tool.
31
53
 
32
- | 도구 | 설명 | 위험도 |
33
- |------|------|--------|
34
- | `run_command` | shell 없이 고정 read-only 명령 allowlist 실행 | 높음 |
35
- | `run_terminal_command` | 터미널 명령 (별칭) | 높음 |
36
-
37
- ### 작업 관리
54
+ ## 도구 목록
38
55
 
39
- | 도구 | 설명 | 위험도 |
40
- |------|------|--------|
41
- | `todo_write` | TODO 항목 생성/업데이트 | 낮음 |
42
- | `todo_read` | TODO 목록 조회 | 낮음 |
56
+ MCP exposes a **curated, read-oriented** subset of Lattice native tools,
57
+ plus each installed skill as a prompt asset. Writes, shell, desktop control,
58
+ and remote-install tools are **not** on this surface — use the REST `/tools/*`
59
+ routes (with their own approval gates) for those.
43
60
 
44
- ### 시스템
61
+ ### Native (governed)
45
62
 
46
63
  | 도구 | 설명 | 위험도 |
47
64
  |------|------|--------|
48
- | `computer_screenshot` | 화면 캡처 (desktop-control capability 및 정책 승인 필요) | 높음 |
49
- | `computer_status` | 데스크톱 제어 상태 조회 (동일 capability/policy 적용) | 중간 |
50
- | `computer_open_app` | 앱 실행 | 중간 |
51
- | `computer_open_url` | URL 열기 | 낮음 |
52
- | `network_status` | IP, Wi-Fi 정보 (인증 및 ToolRegistry 정책 적용) | 중간 |
65
+ | `list_dir` | 워크스페이스 디렉터리 목록 (sandbox) | 낮음 |
66
+ | `read_file` | 워크스페이스 UTF-8 파일 읽기 (offset/limit) | 낮음 |
67
+ | `workspace_tree` | 재귀 트리 (깊이 제한) | 낮음 |
68
+ | `grep` | 워크스페이스 정규식 검색 | 낮음 |
69
+ | `knowledge_search` | 지식 정원 검색 (workspace scope, 승인 정책 적용) | 낮음 |
70
+ | `knowledge_tree` | 지식 정원 파일 목록 (동일 정책) | 낮음 |
71
+ | `git_status` | 워크스페이스 안 read-only `git status` | 낮음 |
53
72
 
54
- ### 문서
73
+ ### Skills (prompt assets)
55
74
 
56
- | 도구 | 설명 | 위험도 |
57
- |------|------|--------|
58
- | `pdf_to_text` | PDF → 텍스트 변환 | 낮음 |
59
- | `pdf_pages` | PDF 페이지 수 조회 | 낮음 |
60
- | `read_docx` | Word 문서 읽기 | 낮음 |
61
- | `read_xlsx` | Excel 파일 읽기 | 낮음 |
62
- | `read_pptx` | PowerPoint 읽기 | 낮음 |
75
+ Installed skills from the skills directory appear as `skill.<name>`
76
+ (for example `skill.code_review`). `tools/list` serves the parsed
77
+ `schema.json` input schema. `tools/call` returns the `SKILL.md` body plus
78
+ the input echo — skills are not executables.
63
79
 
64
- ### 지식 정원 (P-Reinforce)
80
+ Typical names when the repo `skills/` tree is installed:
65
81
 
66
- | 도구 | 설명 | 위험도 |
67
- |------|------|--------|
68
- | `garden_save` | 지식 정원에 저장 | 낮음 |
69
- | `garden_tree` | 지식 트리 조회 | 낮음 |
70
- | `garden_read` | 정원 파일 읽기 | 낮음 |
82
+ - `skill.code_review`
83
+ - `skill.data_analysis`
84
+ - `skill.file_edit`
85
+ - `skill.meeting_notes`
86
+ - `skill.summarize_document`
87
+ - `skill.web_search`
88
+ - `skill.weekly_review`
71
89
 
72
- ## REST API 직접 호출
90
+ ## REST API
73
91
 
74
- MCP 대신 REST API로도 동일한 도구를 호출할 수 있습니다:
92
+ The same governed subset is also reachable at `POST /mcp/call`
93
+ (`{"action": "...", "args": {}}`) and the existing `/tools/*` routes.
75
94
 
76
95
  ```bash
77
- # read_file
78
- curl -b "session=<token>" \
79
- "http://localhost:4825/tools/read_file?path=server.py"
96
+ # MCP JSON-RPC initialize
97
+ curl -s -X POST http://localhost:4825/mcp \
98
+ -H "Content-Type: application/json" \
99
+ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'
80
100
 
81
- # edit_file
82
- curl -b "session=<token>" -X POST \
83
- http://localhost:4825/tools/edit_file \
101
+ # MCP tools/call
102
+ curl -s -b "session_token=<token>" -X POST http://localhost:4825/mcp \
84
103
  -H "Content-Type: application/json" \
85
- -d '{"path": "server.py", "old_string": "old code", "new_string": "new code"}'
104
+ -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_dir","arguments":{"path":"."}}}'
86
105
 
87
- # grep
88
- curl -b "session=<token>" \
89
- "http://localhost:4825/tools/grep?pattern=def%20main&glob=*.py"
106
+ # REST sibling (same dispatch)
107
+ curl -s -b "session_token=<token>" -X POST http://localhost:4825/mcp/call \
108
+ -H "Content-Type: application/json" \
109
+ -d '{"action":"list_dir","args":{"path":"."}}'
90
110
 
91
- # run_command
92
- curl -b "session=<token>" -X POST \
93
- http://localhost:4825/tools/run_command \
111
+ # Full write/exec surface (not on MCP)
112
+ curl -s -b "session_token=<token>" -X POST http://localhost:4825/tools/edit_file \
94
113
  -H "Content-Type: application/json" \
95
- -d '{"command": "rg TODO ."}'
114
+ -d '{"path": "server.py", "old_string": "old code", "new_string": "new code"}'
96
115
  ```
97
116
 
98
- `run_command`는 `pwd`, `ls`, `find`, `cat`, `head`, `tail`, `wc`, `rg`만 허용합니다.
99
- Python/Node/npm/npx/sed, shell operator, 실행 파일 경로, 절대 경로, `..` traversal,
100
- workspace 밖 symlink, `rg --pre`, `find -exec/-delete`는 거부됩니다. 빌드와 테스트는
101
- 별도의 허용된 project-script 도구를 사용합니다.
117
+ `run_command` remains a REST-only admin tool. It allows `pwd`, `ls`, `find`,
118
+ `cat`, `head`, `tail`, `wc`, `rg` only. Python/Node/npm/npx/sed, shell
119
+ operators, executable paths, absolute paths, `..` traversal, workspace-outside
120
+ symlinks, `rg --pre`, and `find -exec/-delete` are refused.
102
121
 
103
122
  ## 도구 카탈로그 조회
104
123
 
105
124
  ```bash
106
- curl -b "session=<token>" http://localhost:4825/mcp/tools
125
+ curl -b "session_token=<token>" http://localhost:4825/mcp/tools
107
126
  ```
108
127
 
109
- 응답:
110
- ```json
111
- {
112
- "tools": [
113
- {
114
- "name": "edit_file",
115
- "description": "정밀 diff 편집. old_string이 파일에 유일해야만 성공.",
116
- "risk": "medium",
117
- "parameters": { ... }
118
- },
119
- ...
120
- ]
121
- }
122
- ```
128
+ `GET /mcp/tools` lists Lattice's native tool catalog (names, descriptions,
129
+ governance). `tools/list` on `POST /mcp` is the MCP-shaped list with JSON
130
+ Schemas for the curated subset plus skills.
131
+
132
+ `POST /mcp/install` enables a skill or plugin Lattice can actually flip in
133
+ the workspace registry. Remote npm/pip/connector entries return
134
+ `{"status":"manual_required", ...}` instead of a blank 404.
123
135
 
124
- 도구 카탈로그는 인증이 필요하며 서버의 절대 `AGENT_ROOT`를 반환하지 않습니다.
125
- MCP/plugin dispatch도 각 도구의 사용자·workspace·capability·승인 정책을 우회할
126
- 수 없습니다. knowledge/Obsidian 계열 읽기는 명시적 사용자 동의와 scope를
127
- 사용합니다.
136
+ The catalogs require authentication and do not return the absolute
137
+ `AGENT_ROOT`. MCP/plugin dispatch cannot bypass user, workspace, capability,
138
+ or approval policy. Knowledge-garden reads use explicit user/workspace scope.
@@ -88,9 +88,12 @@ MAGIC_NUMBERS = {
88
88
 
89
89
  ## 수집 & 그래프 포터빌리티 보안 (v3.6.0)
90
90
 
91
- - **수집 라이프사이클**: 모든 수집은 `IngestionPipeline.ingest` → `dispatch_tool`
92
- 를 거쳐 `pre_tool`/`post_tool` 훅이 발화됩니다. `pre_tool`이 차단하면 수집은
93
- 정직하게 `status="blocked"`로 거부됩니다(권한 게이트·민감정보 가드 적용).
91
+ - **수집 라이프사이클**: 모든 수집은 네이티브 ingest 문(`lattice-ingest` →
92
+ `lattice_core::graph_write`) → 도구 디스패치를 거쳐 `pre_tool`/`post_tool`
93
+ 훅이 발화됩니다. `pre_tool`이 차단하면 수집은 정직하게 `status="blocked"`로
94
+ 거부됩니다(권한 게이트·민감정보 가드 적용). v3.6.0에 이 계약을 세운 것은
95
+ Python `IngestionPipeline.ingest`였고, v11.6.0이 문을 Rust로 옮기면서 계약은
96
+ 그대로 유지했습니다.
94
97
  - **웹 URL 읽기**(`/api/browser/read-url`): `http(s)`만 허용하고 DNS의 모든 결과에서
95
98
  loopback/private/link-local/multicast/reserved 주소를 거부합니다. 검증한 IP에 연결을
96
99
  고정해 DNS rebinding을 막고, redirect마다 재검증하며 환경 proxy를 사용하지
@@ -31,7 +31,7 @@ from .multimodal import (
31
31
  transcribe_audio,
32
32
  )
33
33
 
34
- __version__ = "11.7.0"
34
+ __version__ = "12.0.0"
35
35
 
36
36
  __all__ = [
37
37
  "AudioFacts",