ltcai 3.6.0 → 4.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 (169) hide show
  1. package/README.md +11 -7
  2. package/docs/V4_BRAIN_ARCHITECTURE.md +322 -0
  3. package/docs/V4_DIGITAL_BRAIN_RECOVERY.md +509 -0
  4. package/docs/V4_IMPLEMENTATION_PLAN.md +470 -0
  5. package/docs/kg-schema.md +47 -53
  6. package/kg_schema.py +93 -10
  7. package/knowledge_graph.py +362 -33
  8. package/knowledge_graph_api.py +11 -127
  9. package/latticeai/__init__.py +1 -1
  10. package/latticeai/api/admin.py +1 -1
  11. package/latticeai/api/agents.py +7 -1
  12. package/latticeai/api/auth.py +27 -4
  13. package/latticeai/api/chat.py +112 -76
  14. package/latticeai/api/health.py +1 -1
  15. package/latticeai/api/hooks.py +1 -1
  16. package/latticeai/api/knowledge_graph.py +146 -0
  17. package/latticeai/api/local_files.py +1 -1
  18. package/latticeai/api/mcp.py +23 -11
  19. package/latticeai/api/memory.py +1 -1
  20. package/latticeai/api/models.py +1 -1
  21. package/latticeai/api/network.py +81 -0
  22. package/latticeai/api/realtime.py +1 -1
  23. package/latticeai/api/search.py +26 -2
  24. package/latticeai/api/security_dashboard.py +2 -3
  25. package/latticeai/api/setup.py +2 -2
  26. package/latticeai/api/static_routes.py +2 -4
  27. package/latticeai/api/tools.py +3 -0
  28. package/latticeai/api/workflow_designer.py +46 -0
  29. package/latticeai/api/workspace.py +71 -49
  30. package/latticeai/app_factory.py +1710 -0
  31. package/latticeai/brain/__init__.py +18 -0
  32. package/latticeai/brain/context.py +213 -0
  33. package/latticeai/brain/conversations.py +236 -0
  34. package/latticeai/brain/identity.py +175 -0
  35. package/latticeai/brain/memory.py +102 -0
  36. package/latticeai/brain/network.py +205 -0
  37. package/latticeai/core/agent.py +31 -7
  38. package/latticeai/core/audit.py +0 -7
  39. package/latticeai/core/config.py +1 -1
  40. package/latticeai/core/context_builder.py +1 -2
  41. package/latticeai/core/enterprise.py +1 -1
  42. package/latticeai/core/graph_curator.py +2 -2
  43. package/latticeai/core/marketplace.py +1 -1
  44. package/latticeai/core/mcp_registry.py +791 -0
  45. package/latticeai/core/model_compat.py +1 -1
  46. package/latticeai/core/model_resolution.py +0 -1
  47. package/latticeai/core/multi_agent.py +238 -4
  48. package/latticeai/core/security.py +1 -1
  49. package/latticeai/core/sessions.py +37 -7
  50. package/latticeai/core/workflow_engine.py +114 -2
  51. package/latticeai/core/workspace_os.py +58 -10
  52. package/latticeai/models/__init__.py +7 -0
  53. package/latticeai/models/router.py +779 -0
  54. package/latticeai/server_app.py +29 -1536
  55. package/latticeai/services/agent_runtime.py +1 -0
  56. package/latticeai/services/app_context.py +75 -14
  57. package/latticeai/services/ingestion.py +47 -0
  58. package/latticeai/services/kg_portability.py +33 -3
  59. package/latticeai/services/memory_service.py +39 -11
  60. package/latticeai/services/model_runtime.py +2 -5
  61. package/latticeai/services/platform_runtime.py +100 -23
  62. package/latticeai/services/search_service.py +17 -8
  63. package/latticeai/services/tool_dispatch.py +12 -2
  64. package/latticeai/services/triggers.py +241 -0
  65. package/latticeai/services/upload_service.py +37 -12
  66. package/latticeai/services/workspace_service.py +31 -0
  67. package/llm_router.py +29 -772
  68. package/ltcai_cli.py +1 -2
  69. package/mcp_registry.py +25 -788
  70. package/p_reinforce.py +124 -14
  71. package/package.json +9 -7
  72. package/scripts/bump_version.py +99 -0
  73. package/scripts/generate_diagrams.py +0 -1
  74. package/scripts/lint_v3.mjs +82 -18
  75. package/scripts/validate_release_artifacts.py +0 -1
  76. package/scripts/wheel_smoke.py +142 -0
  77. package/server.py +11 -7
  78. package/setup_wizard.py +1142 -0
  79. package/static/account.html +2 -4
  80. package/static/admin.html +3 -5
  81. package/static/chat.html +3 -6
  82. package/static/graph.html +2 -4
  83. package/static/sw.js +81 -52
  84. package/static/v3/asset-manifest.json +20 -19
  85. package/static/v3/css/{lattice.base.e4cdd05d.css → lattice.base.49deefb5.css} +1 -1
  86. package/static/v3/css/lattice.base.css +1 -1
  87. package/static/v3/css/{lattice.components.9b49d614.css → lattice.components.cde18231.css} +1 -1
  88. package/static/v3/css/lattice.components.css +1 -1
  89. package/static/v3/css/{lattice.shell.8fcc9d33.css → lattice.shell.29d36d85.css} +1 -1
  90. package/static/v3/css/lattice.shell.css +1 -1
  91. package/static/v3/css/{lattice.tokens.e7018963.css → lattice.tokens.304cbc40.css} +3 -0
  92. package/static/v3/css/lattice.tokens.css +3 -0
  93. package/static/v3/css/{lattice.views.22f69117.css → lattice.views.0a18b6c5.css} +2 -2
  94. package/static/v3/css/lattice.views.css +2 -2
  95. package/static/v3/index.html +3 -4
  96. package/static/v3/js/{app.c541f955.js → app.356e6452.js} +1 -1
  97. package/static/v3/js/core/{api.33d6320e.js → api.7a308b89.js} +1 -1
  98. package/static/v3/js/core/{routes.2ce3815a.js → routes.7222343d.js} +22 -22
  99. package/static/v3/js/core/routes.js +22 -22
  100. package/static/v3/js/core/{shell.8c163e0e.js → shell.a1657f20.js} +4 -4
  101. package/static/v3/js/core/shell.js +1 -1
  102. package/static/v3/js/core/{store.34ebd5e6.js → store.204a08b2.js} +1 -1
  103. package/static/v3/js/core/store.js +1 -1
  104. package/static/v3/js/views/graph-canvas.17c15d65.js +509 -0
  105. package/static/v3/js/views/graph-canvas.js +509 -0
  106. package/static/v3/js/views/{hybrid-search.b22b97e0.js → hybrid-search.2fb63ed9.js} +1 -2
  107. package/static/v3/js/views/hybrid-search.js +1 -2
  108. package/static/v3/js/views/{knowledge-graph.a96040a5.js → knowledge-graph.5e40cbeb.js} +33 -37
  109. package/static/v3/js/views/knowledge-graph.js +33 -37
  110. package/static/vendor/chart.umd.min.js +20 -0
  111. package/static/vendor/fonts/inter-latin-300-normal.woff2 +0 -0
  112. package/static/vendor/fonts/inter-latin-400-normal.woff2 +0 -0
  113. package/static/vendor/fonts/inter-latin-500-normal.woff2 +0 -0
  114. package/static/vendor/fonts/inter-latin-600-normal.woff2 +0 -0
  115. package/static/vendor/fonts/inter-latin-700-normal.woff2 +0 -0
  116. package/static/vendor/fonts/inter-latin-800-normal.woff2 +0 -0
  117. package/static/vendor/fonts/inter.css +44 -0
  118. package/static/vendor/icons/tabler-icons.min.css +4 -0
  119. package/static/vendor/icons/tabler-icons.woff2 +0 -0
  120. package/static/vendor/marked.min.js +69 -0
  121. package/static/workspace.html +2 -2
  122. package/telegram_bot.py +1 -2
  123. package/tools/commands.py +4 -2
  124. package/tools/computer.py +1 -1
  125. package/tools/documents.py +1 -3
  126. package/tools/filesystem.py +0 -4
  127. package/tools/knowledge.py +1 -3
  128. package/tools/network.py +1 -3
  129. package/codex_telegram_bot.py +0 -195
  130. package/docs/assets/v3.4.0/agent-run.png +0 -0
  131. package/docs/assets/v3.4.0/agents.png +0 -0
  132. package/docs/assets/v3.4.0/before/chat-before.png +0 -0
  133. package/docs/assets/v3.4.0/before/files-before.png +0 -0
  134. package/docs/assets/v3.4.0/chat.png +0 -0
  135. package/docs/assets/v3.4.0/connect-folder.png +0 -0
  136. package/docs/assets/v3.4.0/files.png +0 -0
  137. package/docs/assets/v3.4.0/home.png +0 -0
  138. package/docs/assets/v3.4.0/hooks-dispatch.png +0 -0
  139. package/docs/assets/v3.4.0/knowledge-graph.png +0 -0
  140. package/docs/assets/v3.4.0/local-agent.png +0 -0
  141. package/docs/assets/v3.4.0/memory.png +0 -0
  142. package/docs/assets/v3.4.0/settings.png +0 -0
  143. package/docs/assets/v3.4.0/vision-input.png +0 -0
  144. package/docs/assets/v3.4.0/workflows.png +0 -0
  145. package/docs/assets/v3.4.1/e2e_runtime_log.txt +0 -42
  146. package/docs/assets/v3.4.1/hooks-dispatch.png +0 -0
  147. package/docs/assets/v3.4.1/local-agent.png +0 -0
  148. package/docs/images/admin-dashboard.png +0 -0
  149. package/docs/images/architecture.png +0 -0
  150. package/docs/images/enterprise.png +0 -0
  151. package/docs/images/graph.png +0 -0
  152. package/docs/images/hero.gif +0 -0
  153. package/docs/images/knowledge-graph.png +0 -0
  154. package/docs/images/lattice-ai-demo.gif +0 -0
  155. package/docs/images/lattice-ai-hero.png +0 -0
  156. package/docs/images/logo.svg +0 -33
  157. package/docs/images/mobile-responsive.png +0 -0
  158. package/docs/images/model-recommendation.png +0 -0
  159. package/docs/images/onboarding.png +0 -0
  160. package/docs/images/organization.png +0 -0
  161. package/docs/images/pipeline.png +0 -0
  162. package/docs/images/screenshot-admin.png +0 -0
  163. package/docs/images/screenshot-chat.png +0 -0
  164. package/docs/images/screenshot-graph.png +0 -0
  165. package/docs/images/skills.png +0 -0
  166. package/docs/images/workspace-dark.png +0 -0
  167. package/docs/images/workspace-light.png +0 -0
  168. package/docs/images/workspace.png +0 -0
  169. package/requirements.txt +0 -16
package/README.md CHANGED
@@ -56,8 +56,10 @@ workspace around the work itself:
56
56
  LM Studio; nothing leaves your machine unless you opt in.
57
57
  - **Use cloud models only when you choose** — bring an API key for cloud LLMs
58
58
  when you want them, not by default.
59
- - **Automate with agents you can inspect** — workflows leave behind plans,
60
- reviews, retries, and results you can replay.
59
+ - **Inspect every agent run** — the built-in runner persists plans, reviews,
60
+ retries, and results as replayable run records. Today that runner is
61
+ deterministic and does not call a model; LLM-driven execution is the v4
62
+ runtime, in progress.
61
63
 
62
64
  Lattice AI is not a clone of ChatGPT, Claude, Cursor, Obsidian, or Notion. It
63
65
  sits in a different place: a **workspace** that ties local/self-hosted AI, your
@@ -73,8 +75,8 @@ and workflows together — and runs on your own hardware.
73
75
  Knowledge Graph.
74
76
  - Run local models through MLX, Ollama, or LM Studio, and use cloud LLMs only when
75
77
  you want to.
76
- - Create repeatable agent workflows for research, coding, analysis, and
77
- documentation.
78
+ - Define agent workflows and replay their run records step by step (execution
79
+ is deterministic scaffolding today — it does not yet call a model).
78
80
  - Separate personal work from organization work.
79
81
  - Switch between Basic, Advanced, and Admin modes depending on your role.
80
82
 
@@ -108,12 +110,14 @@ chat and hybrid search.
108
110
  The Knowledge Graph shows how files, decisions, conversations, and entities
109
111
  connect — context that stays useful even when you switch models.
110
112
 
111
- ### Run agent workflows
113
+ ### Inspect agent run records
112
114
 
113
115
  ![Lattice AI agent run with roles, logs, review, and retry](docs/assets/v3.4.0/agent-run.png)
114
116
 
115
- Agents turn a goal into an inspectable run — roles, logs, review, and retry — that
116
- you can read back step by step.
117
+ The agent runner turns a goal into an inspectable, replayable run record — roles,
118
+ logs, review, and retry — that you can read back step by step. The runner shown
119
+ here is deterministic and LLM-free; real model-driven execution is the v4
120
+ runtime, currently in progress.
117
121
 
118
122
  ### Extend with hooks and the local runtime
119
123
 
@@ -0,0 +1,322 @@
1
+ # Lattice AI v4.0.0 — Brain Architecture Proposal
2
+
3
+ Status: Phase B proposal (post 8-dimension audit, pre-implementation review)
4
+ Audit evidence: `docs/v4-audit/*.json` · Program state: `docs/V4_DIGITAL_BRAIN_RECOVERY.md`
5
+
6
+ ---
7
+
8
+ ## 1. The one-sentence architecture
9
+
10
+ **There is exactly one brain: a workspace-scoped, provenance-stamped knowledge
11
+ substrate in SQLite, with a single write door (the Ingestion Pipeline), a single
12
+ read discipline (scoped, scored, honest retrieval), and replaceable everything
13
+ else (models, agents, UI).**
14
+
15
+ v3.6.0 already *claims* this ("every source converges into the graph — no
16
+ silos"). The audit proves the claim false today in four ways:
17
+
18
+ 1. A second brain exists (`~/.ltcai-brain` markdown vault, `p_reinforce.py`)
19
+ with its own retrieval path injected into every chat.
20
+ 2. The Ingestion Pipeline covers 1 of 4 write paths (browser only); chat,
21
+ uploads, and MCP write to the graph directly, without provenance.
22
+ 3. Conversations — the richest episodic source — are capped at 50 messages in a
23
+ JSON file and then destroyed.
24
+ 4. The graph is machine-global: workspace isolation excludes the actual brain
25
+ (`SHARED_GLOBAL_AREAS = ('graph', 'skills')`).
26
+
27
+ v4 makes the claim true. That is the release.
28
+
29
+ ## 2. Identity
30
+
31
+ - **Product**: *Lattice — the local-first Digital Brain Platform.* The phrase
32
+ "AI workspace" is retired from every shipped artifact (PROJECT_PRINCIPLES,
33
+ pyproject, package.json, vscode-extension, EDITION_STRATEGY, SPA copy).
34
+ - **Honesty is the brand.** FEATURE_STATUS.md's WORKING/PARTIAL/PLACEHOLDER
35
+ ledger is institutionalized: README claims must trace to ledger entries; runs
36
+ that simulate must say so *in the persisted record*, not just in docs.
37
+ - **Naming**: brand "Lattice AI"; packages stay `ltcai` (renaming published
38
+ pip/npm packages is churn without user value). CLI: `ltcai` is canonical,
39
+ `LTCAI` retained as deprecated alias. Env: `LATTICEAI_*` canonical;
40
+ existing `LATTICE_*` vars read as fallback aliases. Data home stays `~/.ltcai`
41
+ (a data migration of every user's brain for a nicer folder name violates
42
+ "knowledge is durable"). `~/.ltcai-brain` is absorbed and retired (§4.2).
43
+ - Concept renames in UI/docs: "Workspace OS" → internal term only; the user
44
+ sees **Brain** (graph+memory), **Capture** (ingestion), **Ask** (chat),
45
+ **Act** (agents/workflows/tools), **Library** (models/skills/plugins),
46
+ **System** (settings/admin).
47
+
48
+ ## 3. The Brain Core model
49
+
50
+ All durable state converges on the existing SQLite graph store, extended — not
51
+ replaced (additive migration, the v3 store keeps working).
52
+
53
+ ### 3.1 Knowledge System — v2 becomes the authoritative store
54
+ The half-finished strangler-fig migration is **finished in v4**, not deferred:
55
+
56
+ - **Write-mastering flips to the normalized v2 schema.** All write paths write
57
+ canonical `kg_schema.NodeType`/`EdgeType` enums natively (no new Korean
58
+ free-string types are ever minted again) and populate the columns that
59
+ justify v2's existence: `owner_id`, `workspace_id` (new), `visibility`,
60
+ `created_by`, `evidence`, confidence.
61
+ - **Migration strategy** (additive, reversible, backup-first):
62
+ 1. automatic pre-migration binary backup via the existing
63
+ `kg_portability` backup machinery;
64
+ 2. one-time migrator normalizes legacy rows through the existing
65
+ `from_legacy()` mapping (the same logic the projection uses today),
66
+ preserving original strings in `legacy_type` — nothing is lost;
67
+ 3. legacy `nodes`/`edges` tables become a *read-compatibility projection*
68
+ (the exact inverse of today), regenerated on write for one deprecation
69
+ release, then dropped;
70
+ 4. the existing `test_kg_v2_read_equivalence.py` suite is extended to prove
71
+ byte-equivalent reads before and after the flip.
72
+ - **Retrieval upgrade**: an FTS5 index over titles/summaries/chunk text
73
+ replaces `LIKE '%q%'` scans; `sqlite-vec` is integrated as an optional
74
+ extra (`ltcai[ann]`) with the brute-force cosine path remaining as the
75
+ honest, capability-reported fallback. The default embedder stays honestly
76
+ labeled `grade='fallback'`; a *real* local embedding model is provisioned
77
+ through the setup wizard **with explicit user consent** (a silent
78
+ multi-hundred-MB download at install would violate privacy-first — this is
79
+ the only "default" we refuse on principle, not effort).
80
+ - **Temporal dimension**: edges gain `observed_at` occurrence records so
81
+ repeated observations no longer collapse silently (`weight=max` losing
82
+ history); nodes gain `superseded_by` for revision chains.
83
+
84
+ ### 3.2 Memory System (new, on the same substrate)
85
+ Four first-class record kinds, stored as typed nodes with provenance:
86
+ - **Episodic** — immutable, timestamped: conversation turns, tool runs,
87
+ ingestion events. Source: the new durable conversation store + agent runs.
88
+ - **Semantic** — consolidated facts/preferences/working-style. Today's
89
+ `MEMORY_KINDS` workspace memories become readable at inference (they are
90
+ written today but never read by the model — audit: memory-context critical).
91
+ - **Experience** — completed agent/workflow runs promoted into the graph
92
+ (plan, outcome, retries) — only *real* runs; simulations are labeled and
93
+ never enter the brain as experience.
94
+ - **Decision** — explicit decision records (already a node type in the schema,
95
+ never populated; v4 populates it from agent plan approvals and user-saved
96
+ decisions).
97
+
98
+ ### 3.3 Conversation store (new; kills the 50-message cap)
99
+ `conversations`/`messages` tables in the brain DB family: unbounded, per-user,
100
+ per-conversation, redaction applied on write, source of the chat UI and of
101
+ episodic memory. `chat_history.json` becomes a render cache at most.
102
+
103
+ ### 3.4 Context System (new: the ContextAssembler)
104
+ One pipeline replaces the ad-hoc string concatenation in `api/chat.py:365-418`:
105
+ ordered, token-budgeted sections (system → semantic memories → hybrid-search
106
+ knowledge → episodic recency → attachments), each with provenance (`why is
107
+ this in my context?` is answerable). It uses the *existing, tested*
108
+ `SearchService.hybrid_search` — fixing the absurdity that the product's search
109
+ engine is never used by its own chat. The recall scoring bug
110
+ (`results` vs `matches`) and the fabricated constant scores die here.
111
+
112
+ ### 3.5 Relationship System (exists)
113
+ The graph's edges, plus evidence/confidence threading from the extractors
114
+ (already produced, currently discarded in projection).
115
+
116
+ ## 4. One door in: the Ingestion Pipeline
117
+
118
+ ### 4.1 Coverage goes 1 of 5 → 5 of 5
119
+ `services/ingestion.py` becomes the only KG write door: alongside the
120
+ already-covered browser/web path, chat messages, document uploads, MCP
121
+ messages, and workspace events are converted to `IngestionItem`s (new source
122
+ types), giving every node provenance and the full pre/post hook lifecycle.
123
+ The direct `ingest_message`/`ingest_document` call sites are rewired.
124
+
125
+ ### 4.2 The garden is absorbed — as a living source, not a snapshot
126
+ `p_reinforce` vault content enters the brain through the pipeline
127
+ (source_type=note): an initial idempotent import (content-hash dedup), after
128
+ which the vault directory is registered as a **watched knowledge source**
129
+ using the existing discovery/watch machinery — Obsidian-style edits keep
130
+ flowing into the brain continuously. Notes created through the API are
131
+ written to the brain (authoritative) *and* mirrored as markdown into the
132
+ vault, which remains the user-readable, user-owned artifact. The `/garden`
133
+ API and chat-context injection are re-implemented as views/queries over the
134
+ brain; the O(n) vault rglob at chat time dies. Imported vault notes carry
135
+ legacy-global scope (NULL workspace), matching their pre-v4 visibility.
136
+ **No capability is removed** — notes, classification, Obsidian
137
+ interoperability, and "relevant context in chat" all survive with strictly
138
+ better retrieval.
139
+
140
+ ## 5. Personal Brain / Organization Brain
141
+
142
+ The workspace layer stops being a veneer:
143
+ - Graph writes carry `workspace_id` + `owner_id` (from the already-resolved
144
+ `WorkspaceService` scope); reads (`search`, `graph`, `traverse`,
145
+ `vector_search`, context assembly) filter by resolved scope. Personal brains
146
+ are private by construction; organization workspaces share an org brain.
147
+ Pre-v4 rows have no workspace (NULL = legacy-global, readable by all members
148
+ of the machine as today — honest, documented compatibility).
149
+ - The by-id authorization bypasses (snapshots get/area/export/compare, memory
150
+ delete, `/workspace/os` registry leak) are closed.
151
+ - Chat context no longer leaks other users' messages (the
152
+ `role=="assistant"` filter bug).
153
+ - **Identity is unified**: every user gets a stable UUID (assigned by
154
+ non-destructive migration on first load, email becomes a mutable
155
+ attribute); memberships, memories, sessions, and audit entries key on it.
156
+ The three role vocabularies collapse into one policy module
157
+ (`latticeai/core/policy.py`) that defines role→capability mappings and is
158
+ *actually enforced* at the router layer — retiring the false
159
+ "`_ROLE_CAPS` is the real access policy" claim by making it true.
160
+ Organization membership gains a real invitation flow (invite record with
161
+ token + expiry, accept endpoint) instead of freeform member-id strings.
162
+ - **Workspace state becomes transactional**: the single unlocked
163
+ `workspace_os.json` (lost updates, silent `[-200:]`/`[-500:]` truncation)
164
+ is replaced by SQLite-backed workspace state in the brain DB family, with
165
+ a one-time importer for existing JSON state. Truncation caps are removed —
166
+ "knowledge is durable" applies to memories and timelines too.
167
+
168
+ ## 6. Act: real runtimes — executing, durable, cancellable
169
+
170
+ - **Agent runtime**: orchestrator roles get an LLM-backed runner built on the
171
+ *real* single-agent runtime (`core/agent.py`) + `llm_router` prompts
172
+ (PLANNER/CRITIC already exist in `agent_prompts.py`). When no model is
173
+ loaded, runs still work deterministically **but the run record persists
174
+ `mode: "simulation"`** and simulated runs never write Experience records
175
+ into the brain. The fabricated-provenance pathway dies. `AgentRegistry`
176
+ entries become executable: a registered agent carries model id, system
177
+ prompt, and a tool allowlist that the runtime actually loads — custom
178
+ agents stop being a UI illusion.
179
+ - **Workflow runtime**: tool/skill nodes execute for real through
180
+ `dispatch_tool` under the existing governance registry. Non-auto-approve
181
+ tools produce an explicit `awaiting_approval` pause — never a silent
182
+ `{recorded: true}` success.
183
+ - **Durable async execution** (in scope, not a gap): runs are persisted
184
+ records (`queued → running → awaiting_approval → succeeded | failed |
185
+ cancelled | interrupted`) executed as asyncio tasks on the server loop
186
+ (synchronous tool/orchestrator work bridged via `asyncio.to_thread`;
187
+ cross-thread bus publishes via `loop.call_soon_threadsafe` — the
188
+ `RealtimeBus` is made thread-safe as part of this work). `stop()` performs
189
+ real cooperative cancellation, checked between steps/tool calls — it
190
+ cannot interrupt an in-flight MLX `generate()`, and agent generation
191
+ serializes with interactive chat on the single inference thread; both
192
+ limits are documented, surfaced honestly, never papered over. Progress
193
+ streams over the existing `/realtime/stream` SSE endpoint (the
194
+ `/agents/.../events` JSON snapshot remains as-is). On startup, any run
195
+ left non-terminal by a crash/restart is reconciled to `interrupted` with
196
+ reason + timestamp — no phantom "running" state survives a restart.
197
+ - **Per-tool approval gate**: when a run hits a non-auto-approve tool it
198
+ pauses into `awaiting_approval`, surfaces the pending decision through the
199
+ API/UI, and resumes (or aborts) on the recorded human decision —
200
+ generalizing the proven `human_in_loop` plan-approval mechanism in
201
+ `api/chat.py`. `approve()` stops auto-approving unconditionally.
202
+ - **Trigger system**: beyond `manual` — (a) interval/cron scheduling via a
203
+ supervised scheduler loop; (b) **brain-event triggers**: workflows subscribe
204
+ to ingestion lifecycle events through the existing hooks bus ("when a new
205
+ document enters the brain, run this workflow"). Trigger firings create
206
+ normal durable runs with provenance pointing at the triggering event.
207
+
208
+ ## 7. Sovereignty: portability + Brain Network
209
+
210
+ - **Device identity**: per-installation Ed25519 keypair (`cryptography`, file
211
+ + keyring storage). Every export and every peer interaction is attributable
212
+ to a device the user controls.
213
+ - **Signed brain bundles**: exports (already sha256-manifested) gain a
214
+ detached signature + device public key; imports verify and record origin
215
+ provenance. Per-workspace export ("take your brain with you") joins the
216
+ existing admin-global export. A bundle is a file — sneakernet is a fully
217
+ supported transport.
218
+ - **Brain Network v1 (Knowledge Exchange)** — implemented, not just
219
+ documented: explicit peer registry (name, base URL, trusted Ed25519 public
220
+ key) with a deliberate pairing step; push/pull of signed workspace bundles
221
+ between Lattice instances over plain HTTP (designed for LAN/tailnet —
222
+ local-first, no cloud rendezvous, no relay service); the receiving brain
223
+ verifies the signature against the *paired* key, imports through the normal
224
+ ingestion/import path, and records origin-device provenance on every
225
+ imported node. Peer requests authenticate independently of user sessions:
226
+ each request carries an Ed25519 signature over (body digest + timestamp),
227
+ verified against the paired key, with a freshness window + seen-nonce check
228
+ for replay protection. Nothing is shared implicitly: exchange is
229
+ per-workspace, per-request, owner-initiated. Identity-aware sync/merge
230
+ conflict resolution beyond idempotent content-hash dedup is v1's documented
231
+ boundary.
232
+ - **Compatibility policy for unsigned artifacts**: pre-v4 export bundles and
233
+ backups have no signatures — local file imports/restores of them are
234
+ accepted and recorded with provenance `origin='unsigned-legacy'`.
235
+ Signatures are mandatory only on the Brain Network peer path. A v3.6
236
+ export must always import into a v4 brain.
237
+ - **Agent collaboration across brains** inherits this substrate: an agent's
238
+ Experience records travel inside bundles like any other knowledge, with
239
+ provenance intact.
240
+
241
+ ## 8. Surfaces
242
+
243
+ - **One frontend.** The v3 `/app` SPA is the product; legacy pages
244
+ (`/chat`, `/graph`, `/workspace`, `/admin`, …) 308-redirect into `/app`
245
+ routes. Login flows into `/app`. Legacy HTML/JS/CSS is deleted from the
246
+ shipping set (kept in git history).
247
+ - **Brain-first IA**: nav regrouped (Brain · Ask · Capture · Act · Library ·
248
+ System); the Knowledge Graph view is the post-login landing surface.
249
+ - **A real graph**: the force-directed canvas (drag/zoom/physics — already
250
+ written in legacy `graph.js`) is ported into the v3 explorer, replacing the
251
+ static SVG spiral.
252
+ - **Privacy honesty**: fonts/icons vendored locally; no CDN calls from a
253
+ product that promises "nothing leaves your machine". Service worker
254
+ precaches the v3 bundle, not the deleted legacy one. The hardcoded
255
+ fusion-score meters in hybrid-search view are removed (real scores or no
256
+ meters).
257
+ - **Login joins the design system**: the auth surface is rebuilt token-native,
258
+ dropping its ~8,300 lines of legacy reference CSS.
259
+ - **i18n (en/ko)**: SPA strings externalized into a dictionary module with
260
+ browser-locale default — formalizing the bilingual reality the legacy chat
261
+ already proved demand for, instead of the current ko/en patchwork.
262
+
263
+ ## 9. Backend shape: the brain gets a package
264
+
265
+ The dependency inversion (clean `latticeai/` importing dirty root modules)
266
+ ends:
267
+
268
+ - **`latticeai/brain/`** — the 4,633-line `knowledge_graph.py` single class is
269
+ decomposed along its existing seams: `store.py` (authoritative v2 SQLite
270
+ store), `extraction.py` (concept/triple extraction, LLM + rules),
271
+ `documents.py` (pdf/pptx/docx/xlsx structure), `discovery.py` (local roots,
272
+ audit, watch), `conversations.py` (durable conversation store, new),
273
+ `memory.py` (memory-type model, new), `context.py` (ContextAssembler, new),
274
+ `identity.py` (device keypair, new), `network.py` (peer exchange, new).
275
+ A root `knowledge_graph.py` shim re-exports the public surface during the
276
+ deprecation window so nothing external breaks.
277
+ - **Root modules are absorbed or deleted**: `setup.py` → `setup_wizard.py`
278
+ (fixes both the broken wheel and the setuptools collision); `llm_router.py`,
279
+ `mcp_registry.py`, `kg_schema.py` move under `latticeai/`;
280
+ `telegram_bot` decouples from `api/chat.py` by subscribing to the
281
+ `RealtimeBus` instead of being imported unconditionally; dead modules
282
+ (`codex_telegram_bot.py`, `perm_monitor.py`) are deleted (git history
283
+ preserves them). `knowledge_graph_api.py` is **live, not dead** (it serves
284
+ the `/knowledge-graph/*` data endpoints the v3 SPA uses): its data router
285
+ migrates into `latticeai/api/` with endpoint-parity tests; its legacy page
286
+ routes join the frontend redirect work.
287
+ - **`create_app(config)` factory**: `server_app.py`'s import-time singleton
288
+ construction and GPU side effects move into an explicit factory that builds
289
+ the dormant `AppContext` dataclass and hands it to router factories —
290
+ replacing 25-30-kwarg closure wiring with one typed context.
291
+
292
+ ## 10. Platform / release engineering
293
+
294
+ - **Fix the broken wheel** (`setup.py` rename above) + an installed-wheel
295
+ smoke test in CI: build, install into a clean venv, import, hit `/health` —
296
+ from a non-repo cwd, so the class of "works in `pip install -e .` only"
297
+ failures dies.
298
+ - ruff (lint) baseline + CI gate; bounded dependency constraints + lockfile;
299
+ single `scripts/bump_version.py` writing all version copies (kept honest by
300
+ the existing consistency test).
301
+ - npm tarball slimmed (no docs images / bots).
302
+ - `.gitignore` covers tarballs/logs/venvs; the 15MB tracked pptx is deleted
303
+ at HEAD (stops the bleeding for new objects).
304
+
305
+ ## 11. The only two exclusions, and why they are real blockers
306
+
307
+ Everything previously marked "foundation only" or "documented gap" is now in
308
+ scope (§3.1 v2 flip, §6 async/triggers/approvals, §5 identity+invitations+
309
+ transactional state, §7 Brain Network transport, §9 decomposition). Two items
310
+ remain excluded because they have *true* blockers, not effort blockers:
311
+
312
+ 1. **Git history rewrite** (purging the pptx from past commits): requires
313
+ force-pushing rewritten history to the shared remote — an irreversible,
314
+ collaboration-breaking action that is reserved for the repository owner's
315
+ explicit decision at RC review. v4 deletes the file at HEAD.
316
+ 2. **Downloading a production embedding model silently at install**: violates
317
+ privacy-first consent. The capability ships, but provisioning happens
318
+ through the setup wizard with explicit user opt-in; until then the
319
+ fallback embedder remains and reports itself honestly as
320
+ `grade='fallback'`.
321
+
322
+ Neither exclusion hides behind fake UI: both are visible, labeled states.