ltcai 4.4.0 → 4.5.1

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 (61) hide show
  1. package/README.md +46 -18
  2. package/docs/CHANGELOG.md +85 -0
  3. package/docs/V4_5_0_GEMMA_RUNTIME_COMPATIBILITY_REPORT.md +49 -0
  4. package/docs/V4_5_0_GRAPH_UX_REPORT.md +34 -0
  5. package/docs/V4_5_0_MODEL_RUNTIME_UX_REPORT.md +40 -0
  6. package/docs/V4_5_0_ONBOARDING_REPORT.md +31 -0
  7. package/docs/V4_5_0_PRODUCT_EXPERIENCE_RECOVERY_REPORT.md +49 -0
  8. package/docs/V4_5_0_VALIDATION_REPORT.md +60 -0
  9. package/docs/V4_5_1_GRAPH_EXPERIENCE_REPORT.md +33 -0
  10. package/docs/V4_5_1_MODEL_EXPERIENCE_REPORT.md +37 -0
  11. package/docs/V4_5_1_NAVIGATION_REPORT.md +37 -0
  12. package/docs/V4_5_1_ONBOARDING_REPORT.md +29 -0
  13. package/docs/V4_5_1_PRODUCT_REIMAGINING_REPORT.md +61 -0
  14. package/docs/V4_5_1_RC_ARTIFACTS.md +44 -0
  15. package/docs/V4_5_1_UX_REPORT.md +45 -0
  16. package/docs/V4_5_1_VALIDATION_REPORT.md +54 -0
  17. package/docs/V4_5_1_VISUAL_DESIGN_REPORT.md +30 -0
  18. package/docs/V4_DIGITAL_BRAIN_RECOVERY.md +16 -16
  19. package/docs/architecture.md +8 -4
  20. package/frontend/src/App.tsx +152 -91
  21. package/frontend/src/api/client.ts +83 -1
  22. package/frontend/src/components/FirstRunGuide.tsx +99 -0
  23. package/frontend/src/components/primitives.tsx +131 -25
  24. package/frontend/src/components/ui/badge.tsx +2 -2
  25. package/frontend/src/components/ui/button.tsx +7 -7
  26. package/frontend/src/components/ui/card.tsx +5 -5
  27. package/frontend/src/components/ui/input.tsx +1 -1
  28. package/frontend/src/components/ui/textarea.tsx +1 -1
  29. package/frontend/src/pages/Act.tsx +58 -28
  30. package/frontend/src/pages/Ask.tsx +51 -19
  31. package/frontend/src/pages/Brain.tsx +60 -42
  32. package/frontend/src/pages/Capture.tsx +24 -24
  33. package/frontend/src/pages/Library.tsx +222 -32
  34. package/frontend/src/pages/System.tsx +56 -34
  35. package/frontend/src/routes.ts +15 -13
  36. package/frontend/src/store/appStore.ts +8 -1
  37. package/frontend/src/styles.css +666 -36
  38. package/lattice_brain/__init__.py +1 -1
  39. package/lattice_brain/runtime/multi_agent.py +1 -1
  40. package/latticeai/__init__.py +1 -1
  41. package/latticeai/api/models.py +107 -18
  42. package/latticeai/core/marketplace.py +1 -1
  43. package/latticeai/core/model_compat.py +250 -0
  44. package/latticeai/core/workspace_os.py +1 -1
  45. package/latticeai/models/router.py +136 -32
  46. package/latticeai/services/model_catalog.py +2 -2
  47. package/latticeai/services/model_recommendation.py +8 -1
  48. package/latticeai/services/model_runtime.py +18 -3
  49. package/package.json +1 -1
  50. package/scripts/build_frontend_assets.mjs +12 -1
  51. package/src-tauri/Cargo.lock +1 -1
  52. package/src-tauri/Cargo.toml +1 -1
  53. package/src-tauri/tauri.conf.json +1 -1
  54. package/static/app/asset-manifest.json +5 -5
  55. package/static/app/assets/index-3G8qcrIS.js +336 -0
  56. package/static/app/assets/index-3G8qcrIS.js.map +1 -0
  57. package/static/app/assets/index-C0wYZp7k.css +2 -0
  58. package/static/app/index.html +2 -2
  59. package/static/app/assets/index-CHHal8Zl.css +0 -2
  60. package/static/app/assets/index-pdzil9ac.js +0 -333
  61. package/static/app/assets/index-pdzil9ac.js.map +0 -1
@@ -0,0 +1,61 @@
1
+ # v4.5.1 Product Reimagining Report
2
+
3
+ Release date: 2026-06-13
4
+
5
+ ## Objective
6
+
7
+ v4.5.1 treats the previous desktop product surface as non-authoritative. The
8
+ goal was not to polish the v4.5.0 recovery UI; it was to relaunch Lattice AI as
9
+ a premium local-first Digital Brain while preserving all capabilities,
10
+ workflows, data contracts, storage, FastAPI APIs, Tauri shell behavior, Brain
11
+ Core, model runtimes, backup/restore, and portability.
12
+
13
+ ## Product Decision
14
+
15
+ The product is now organized around six user-facing rooms:
16
+
17
+ - Home: the living shape of what Lattice knows.
18
+ - Ask: thinking with remembered context.
19
+ - Add: files, folders, and pages entering memory.
20
+ - Automate: supervised goals, runs, workflows, approvals, hooks, and tools.
21
+ - Library: models, skills, marketplace, and tool connections.
22
+ - Care: account, spaces, backups, devices, settings, and admin safety.
23
+
24
+ Legacy hash routes still resolve into the SPA, but they no longer dictate the
25
+ visible product model.
26
+
27
+ ## What Changed
28
+
29
+ - Replaced the fixed left rail with compact desktop chrome and a centered
30
+ navigation dock.
31
+ - Added a command palette and responsive mobile drawer.
32
+ - Added an ambient brain canvas so the first viewport reads as a thinking
33
+ environment rather than a dashboard.
34
+ - Replaced the first-run checklist with a first-session journey.
35
+ - Reworked route labels and page hero copy across Brain, Ask, Capture, Act,
36
+ Library, and System.
37
+ - Rebuilt global styling around calmer surfaces, fixed responsive type sizes,
38
+ and restrained accents.
39
+
40
+ ## What Was Preserved
41
+
42
+ - FastAPI and generated OpenAPI client.
43
+ - Tauri desktop shell and sidecar behavior.
44
+ - `lattice_brain` package boundary.
45
+ - StorageEngine, SQLite default, optional PostgreSQL scale mode.
46
+ - Backup/restore and `.latticebrain` portability.
47
+ - Model recommendation, prepare/load stream, and consent-gated downloads.
48
+ - Knowledge graph, hybrid search, chat, capture, workflow, agent, system, and
49
+ admin APIs.
50
+
51
+ ## Self Review
52
+
53
+ The redesigned first viewport immediately reads as a different product:
54
+ Lattice branding, Home/Ask/Add/Automate/Library/Care navigation, first-session
55
+ journey, and premium desktop chrome replace the old dashboard hierarchy.
56
+
57
+ ## Evidence
58
+
59
+ - Desktop screenshot: `output/audits/v4.5.1-reimagining/screenshots/home-desktop.png`
60
+ - Mobile screenshot: `output/audits/v4.5.1-reimagining/screenshots/home-mobile.png`
61
+ - Walkthrough GIF: `output/audits/v4.5.1-reimagining/gifs/v4.5.1-reimagining-walkthrough.gif`
@@ -0,0 +1,44 @@
1
+ # v4.5.1 RC Artifact Manifest
2
+
3
+ Release date: 2026-06-13
4
+
5
+ ## Screenshots
6
+
7
+ - `output/audits/v4.5.1-reimagining/screenshots/home-desktop.png`
8
+ - `output/audits/v4.5.1-reimagining/screenshots/home-mobile.png`
9
+ - `output/audits/v4.5.1-reimagining/screenshots/memory-map.png`
10
+ - `output/audits/v4.5.1-reimagining/screenshots/library-models.png`
11
+
12
+ ## GIFs
13
+
14
+ - `output/audits/v4.5.1-reimagining/gifs/v4.5.1-reimagining-walkthrough.gif`
15
+
16
+ ## Release Artifacts
17
+
18
+ - `dist/ltcai-4.5.1-py3-none-any.whl`
19
+ - `dist/ltcai-4.5.1.tar.gz`
20
+ - `ltcai-4.5.1.tgz`
21
+ - `dist/ltcai-4.5.1.vsix`
22
+ - `src-tauri/target/release/bundle/dmg/Lattice AI_4.5.1_aarch64.dmg`
23
+
24
+ ## SHA-256
25
+
26
+ | Artifact | SHA-256 |
27
+ | --- | --- |
28
+ | `dist/ltcai-4.5.1-py3-none-any.whl` | `3d5ce1a0a85f7aba1f78587cd7e4a66c63dd5c03ddde7cee57624ec3f487899b` |
29
+ | `dist/ltcai-4.5.1.tar.gz` | `62f0e05ff32554cf599b76678de3136bc02e5af4775144e7347182eed0fb4675` |
30
+ | `ltcai-4.5.1.tgz` | `e755f40f87484d8a6e3f6bc95f48f0f78e1d0fcde3af8b14c709cf7fa71b2e4b` |
31
+ | `dist/ltcai-4.5.1.vsix` | `3badc5915dc31425fa383d5946f78e0914497aa9e523cb7fbdc81a295b8f4a2f` |
32
+ | `src-tauri/target/release/bundle/dmg/Lattice AI_4.5.1_aarch64.dmg` | `689ffc9553facf3987a5d57016dfd24fc3872f9c0810e28621f96b340ca38ce0` |
33
+
34
+ ## Validation
35
+
36
+ `npm run release:validate` passed for the exact v4.5.1 artifact set. Historical
37
+ files remain in `dist/` for prior releases, so all publish or upload steps must
38
+ use exact v4.5.1 filenames only.
39
+
40
+ ## Notes
41
+
42
+ The artifact list is exact-version only. Publishing remains out of scope for
43
+ this RC unless the repository owner explicitly performs the manual registry
44
+ publish steps.
@@ -0,0 +1,45 @@
1
+ # v4.5.1 UX Report
2
+
3
+ ## UX Principle
4
+
5
+ v4.5.1 designs for non-technical users who should understand what Lattice AI is,
6
+ what to do next, how to add knowledge, how to use the brain, how to install a
7
+ model, and how to automate work without reading the README.
8
+
9
+ ## Primary Flow
10
+
11
+ The first-session journey is:
12
+
13
+ 1. Make it yours.
14
+ 2. Choose a space.
15
+ 3. Meet your Mac.
16
+ 4. Pick a brain.
17
+ 5. Install locally.
18
+ 6. Try a question.
19
+ 7. Set the pace.
20
+ 8. Explore memory.
21
+
22
+ This replaces implementation-facing setup labels with user outcomes while still
23
+ driving the same account, workspace, model recommendation, model setup, mode,
24
+ and graph routes.
25
+
26
+ ## Screen Inventory Decision
27
+
28
+ - Brain became Home, emphasizing the shape of work rather than a graph tool.
29
+ - Capture became Add, emphasizing the act of feeding memory.
30
+ - Act became Automate, emphasizing supervised work instead of an agent console.
31
+ - System became Care, emphasizing trust, portability, and maintenance.
32
+ - Ask and Library survived because their user intent is direct and legible.
33
+
34
+ ## Interaction Notes
35
+
36
+ - Command palette remains available with Cmd/Ctrl+K.
37
+ - Mode switching is visible as Calm, Deep, and Admin instead of Basic,
38
+ Advanced, and Admin in the first viewport.
39
+ - Mobile navigation opens as a room chooser and preserves no-horizontal-overflow
40
+ behavior at 390px width.
41
+
42
+ ## Evidence
43
+
44
+ - Playwright visual coverage: `tests/visual/v3.spec.js`
45
+ - Screenshots: `output/audits/v4.5.1-reimagining/screenshots/`
@@ -0,0 +1,54 @@
1
+ # v4.5.1 Validation Report
2
+
3
+ Release date: 2026-06-13
4
+
5
+ ## Scope
6
+
7
+ Validation covers the v4.5.1 product reimagining, version sync, frontend visual
8
+ changes, release artifacts, and compatibility preservation.
9
+
10
+ ## Command Matrix
11
+
12
+ | Check | Result |
13
+ | --- | --- |
14
+ | Python compile | PASS: `npm run check:python` compiled 775 modules |
15
+ | Ruff | PASS: `node scripts/run_python.mjs -m ruff check .` |
16
+ | Unit tests | PASS: `npm run test:unit` - 616 passed, 2 warnings |
17
+ | Integration tests | PASS: `LTCAI_TEST_BASE_URL=http://127.0.0.1:4932 npm run test:integration` - 9 passed, 1 skipped |
18
+ | Frontend lint | PASS: `npm run lint` |
19
+ | TypeScript typecheck | PASS: `npm run typecheck` and `npm run typecheck:frontend` |
20
+ | Playwright | PASS: `npm run test:visual` - 14 passed |
21
+ | Tauri check/build | PASS: `npm run desktop:tauri:check`; PASS via `npm run release:artifacts` for the Tauri app and DMG build |
22
+ | Release artifact validation | PASS: `npm run release:validate` |
23
+ | Wheel smoke | PASS: `node scripts/run_python.mjs scripts/wheel_smoke.py --wheel dist/ltcai-4.5.1-py3-none-any.whl` |
24
+ | npm pack dry-run | PASS: `npm pack --dry-run` |
25
+
26
+ ## Browser Evidence
27
+
28
+ - Desktop screenshot: `output/audits/v4.5.1-reimagining/screenshots/home-desktop.png`
29
+ - Mobile screenshot: `output/audits/v4.5.1-reimagining/screenshots/home-mobile.png`
30
+ - Walkthrough GIF: `output/audits/v4.5.1-reimagining/gifs/v4.5.1-reimagining-walkthrough.gif`
31
+
32
+ ## RC Artifacts
33
+
34
+ Expected exact-version artifacts:
35
+
36
+ - `dist/ltcai-4.5.1-py3-none-any.whl`
37
+ - `dist/ltcai-4.5.1.tar.gz`
38
+ - `ltcai-4.5.1.tgz`
39
+ - `dist/ltcai-4.5.1.vsix`
40
+ - `src-tauri/target/release/bundle/dmg/Lattice AI_4.5.1_aarch64.dmg`
41
+
42
+ ## Artifact Hashes
43
+
44
+ | Artifact | SHA-256 |
45
+ | --- | --- |
46
+ | `dist/ltcai-4.5.1-py3-none-any.whl` | `3d5ce1a0a85f7aba1f78587cd7e4a66c63dd5c03ddde7cee57624ec3f487899b` |
47
+ | `dist/ltcai-4.5.1.tar.gz` | `62f0e05ff32554cf599b76678de3136bc02e5af4775144e7347182eed0fb4675` |
48
+ | `ltcai-4.5.1.tgz` | `e755f40f87484d8a6e3f6bc95f48f0f78e1d0fcde3af8b14c709cf7fa71b2e4b` |
49
+ | `dist/ltcai-4.5.1.vsix` | `3badc5915dc31425fa383d5946f78e0914497aa9e523cb7fbdc81a295b8f4a2f` |
50
+ | `src-tauri/target/release/bundle/dmg/Lattice AI_4.5.1_aarch64.dmg` | `689ffc9553facf3987a5d57016dfd24fc3872f9c0810e28621f96b340ca38ce0` |
51
+
52
+ `npm run release:validate` confirmed all exact-version RC artifacts are present.
53
+ It also warned that historical artifacts remain in `dist/`, so publish commands
54
+ must continue to use explicit v4.5.1 filenames rather than a `dist/*` glob.
@@ -0,0 +1,30 @@
1
+ # v4.5.1 Visual Design Report
2
+
3
+ ## Direction
4
+
5
+ The visual language targets a calm premium desktop product rather than a
6
+ developer/admin dashboard. The palette uses a carbon and warm-white base with
7
+ jade, amber, violet, blue, and coral accents so the UI is not dominated by a
8
+ single hue family.
9
+
10
+ ## System Changes
11
+
12
+ - New sticky desktop chrome and centered dock.
13
+ - Ambient brain canvas built from grid, line, and tile motifs.
14
+ - Fixed responsive typography with media-query breakpoints, avoiding viewport
15
+ width font scaling.
16
+ - Cards remain at 8px radius or less.
17
+ - Shared buttons and badges were tightened for stable sizing and text fit.
18
+ - Light theme retains the same hierarchy with warmer surfaces.
19
+
20
+ ## Accessibility And Layout
21
+
22
+ - Primary navigation has an explicit `Primary navigation` label.
23
+ - The command palette exposes a dialog label.
24
+ - Mode switch has `Experience mode` semantics and pressed states.
25
+ - Mobile layout was checked at 390x780 with zero horizontal overflow.
26
+
27
+ ## Evidence
28
+
29
+ - Desktop visual pass: `output/audits/v4.5.1-reimagining/screenshots/home-desktop.png`
30
+ - Mobile visual pass: `output/audits/v4.5.1-reimagining/screenshots/home-mobile.png`
@@ -5,21 +5,21 @@
5
5
  > completed analysis. **Update this file before ending any phase and before any
6
6
  > likely session/context/usage limit.**
7
7
  >
8
- > Last updated: 2026-06-13 — v4.3.3 Dead-Code Cleanup Release; Remaining Gaps remain empty
8
+ > Last updated: 2026-06-13 — v4.5.1 Product Reimagining RC; Remaining Gaps remain empty
9
9
 
10
10
  ---
11
11
 
12
- ## 0. RELEASE STATUS (v4.3.3)
13
-
14
- **v4.3.3 promotes the post-cleanup main tree after the independent dead-code,
15
- architecture, and runtime audit without redesigning the Digital Brain frontend,
16
- Brain Core, storage, or agent/workflow architecture.** Latest implementation
17
- milestone: v4.3.2 product polish plus post-audit cleanup, architecture
18
- documentation correction, Vercel/static-docs readiness, README badge
19
- restoration, and exact-current-main release artifacts.
20
- The v4.3.3 process creates a GitHub Release from locally validated artifacts.
21
- PyPI, npm Registry, VS Code Marketplace, Open VSX, and production deployments
22
- remain owner-only external publishing steps.
12
+ ## 0. RELEASE STATUS (v4.5.1)
13
+
14
+ **v4.5.1 reimagines the desktop product surface after the v4.5.0 capability
15
+ recovery without changing Brain Core, storage, API, model runtime, backup,
16
+ portability, or agent/workflow behavior.** Current implementation milestone:
17
+ new Home/Ask/Add/Automate/Library/Care navigation, compact desktop chrome,
18
+ first-session journey, command palette, responsive mobile drawer, and refreshed
19
+ Digital Brain visual system.
20
+ The v4.5.1 RC process builds locally validated artifacts only. Tagging, GitHub
21
+ Release creation, PyPI, npm Registry, VS Code Marketplace, Open VSX, and
22
+ production deployments remain out of scope for this RC.
23
23
  Remaining implementation gaps: **none**.
24
24
  Owner-only blockers: pptx history rewrite (requires force-push/owner decision)
25
25
  and consent-gated production embedder provisioning (silent default download is
@@ -27,11 +27,11 @@ not permitted).
27
27
 
28
28
  ## Remaining Gaps
29
29
 
30
- None. v4.3.3 preserves the already-empty v4.3.2 gap list and promotes the
31
- post-cleanup tree: Brain graph exploration remains real and API-backed, raw
32
- product JSON dumps remain replaced with readable state, archive import/restore
30
+ None. v4.5.1 preserves the already-empty v4.3.2/v4.3.3/v4.5.0 gap list and
31
+ promotes the product-reimagining tree: Brain graph exploration remains real and
32
+ API-backed, readable product state remains in place, archive import/restore
33
33
  flows remain exposed through existing APIs, desktop sidecar behavior remains
34
- validated, and exact v4.3.3 release artifacts are the release target.
34
+ validated, and exact v4.5.1 RC artifacts are the validation target.
35
35
  Owner-only blockers above are intentionally not implementation gaps.
36
36
 
37
37
  ## 1. Program Charter (from the user's v4.0.0 directive)
@@ -88,13 +88,17 @@ work on them.
88
88
 
89
89
  Local recommended models must be multimodal. The v2.2 local model workflow policy is:
90
90
 
91
- - macOS Apple Silicon: MLX-VLM first
91
+ - macOS Apple Silicon: MLX-VLM first, with MLX-LM retained as a Gemma 4 text
92
+ fallback only for standard Gemma 4 metadata. Gemma 4 12B `gemma4_unified`
93
+ requires an MLX-VLM runtime that includes `mlx_vlm.models.gemma4_unified`.
92
94
  - Windows: llama.cpp multimodal path, with LM Studio as a user-friendly option
93
95
  - Linux: llama.cpp or vLLM multimodal path depending on GPU support
94
96
  - Ollama: kept as an option, not the default priority
95
97
 
96
- The removed path is the old text-only MLX-LM recommendation route. Low-spec
97
- machines use smaller or quantized multimodal models.
98
+ The removed path is the old text-only MLX-LM recommendation lane for ordinary
99
+ model selection. MLX-LM remains available as a targeted recovery path for
100
+ standard Gemma 4 metadata, but it is not used for `gemma4_unified`.
101
+ Low-spec machines use smaller or quantized multimodal models.
98
102
 
99
103
  ## Model Source Disclosure
100
104
 
@@ -140,7 +144,7 @@ Basic mode and advanced mode have the same feature access.
140
144
  | `latticeai/services/model_catalog.py` | Multimodal model catalog, source metadata, aliases |
141
145
  | `latticeai/services/model_recommendation.py` | Hardware-aware multimodal recommendation |
142
146
  | `latticeai/services/model_runtime.py` | Download, load, server, and model workflow orchestration |
143
- | `llm_router.py` | MLX-VLM and OpenAI-compatible model routing |
147
+ | `llm_router.py` | MLX-VLM/MLX-LM and OpenAI-compatible model routing |
144
148
  | `knowledge_graph.py` | Graph storage, extraction, local folder knowledge graph context |
145
149
  | `latticeai/core/context_builder.py` | Graph context for generation |
146
150
  | `latticeai/core/workspace_os.py` | Workspace state, timeline, snapshots, durable context |
@@ -1,10 +1,11 @@
1
1
  import * as React from "react";
2
2
  import { useQuery } from "@tanstack/react-query";
3
- import { Command, Menu, Moon, Search, Sun, X } from "lucide-react";
3
+ import { BrainCircuit, CheckCircle2, Command, Menu, Moon, Search, Sparkles, Sun, X } from "lucide-react";
4
4
  import { latticeApi } from "@/api/client";
5
5
  import { Button } from "@/components/ui/button";
6
6
  import { Input } from "@/components/ui/input";
7
- import { useAppStore } from "@/store/appStore";
7
+ import { FirstRunGuide } from "@/components/FirstRunGuide";
8
+ import { useAppStore, WorkspaceMode } from "@/store/appStore";
8
9
  import { commandRoutes, go, parseHash, primaryRoutes, PrimaryRoute } from "@/routes";
9
10
  import { BrainPage } from "@/pages/Brain";
10
11
  import { AskPage } from "@/pages/Ask";
@@ -14,6 +15,12 @@ import { LibraryPage } from "@/pages/Library";
14
15
  import { SystemPage } from "@/pages/System";
15
16
  import { cn } from "@/lib/utils";
16
17
 
18
+ const modes: Array<{ id: WorkspaceMode; label: string }> = [
19
+ { id: "basic", label: "Calm" },
20
+ { id: "advanced", label: "Deep" },
21
+ { id: "admin", label: "Admin" },
22
+ ];
23
+
17
24
  function useRoute() {
18
25
  const [route, setRoute] = React.useState(parseHash);
19
26
  React.useEffect(() => {
@@ -33,9 +40,26 @@ function Page({ primary, tab }: { primary: PrimaryRoute; tab?: string }) {
33
40
  return <BrainPage initialTab={tab} />;
34
41
  }
35
42
 
43
+ function AmbientBrain() {
44
+ return (
45
+ <div className="ambient-brain" aria-hidden="true">
46
+ <span className="signal-line signal-line-a" />
47
+ <span className="signal-line signal-line-b" />
48
+ <span className="signal-line signal-line-c" />
49
+ <span className="signal-tile signal-tile-a" />
50
+ <span className="signal-tile signal-tile-b" />
51
+ <span className="signal-tile signal-tile-c" />
52
+ </div>
53
+ );
54
+ }
55
+
36
56
  function CommandPalette({ open, onClose }: { open: boolean; onClose: () => void }) {
37
57
  const [query, setQuery] = React.useState("");
38
- const matches = commandRoutes.filter((route) => route.label.toLowerCase().includes(query.toLowerCase()) || route.key.includes(query.toLowerCase()));
58
+ const normalized = query.trim().toLowerCase();
59
+ const matches = commandRoutes.filter((route) => (
60
+ route.label.toLowerCase().includes(normalized) || route.key.includes(normalized)
61
+ ));
62
+
39
63
  React.useEffect(() => {
40
64
  if (!open) return;
41
65
  const onKey = (event: KeyboardEvent) => {
@@ -44,16 +68,17 @@ function CommandPalette({ open, onClose }: { open: boolean; onClose: () => void
44
68
  window.addEventListener("keydown", onKey);
45
69
  return () => window.removeEventListener("keydown", onKey);
46
70
  }, [open, onClose]);
71
+
47
72
  if (!open) return null;
48
73
  return (
49
- <div className="fixed inset-0 z-50 bg-background/80 p-4 backdrop-blur-sm" role="dialog" aria-modal="true">
50
- <div className="mx-auto mt-16 max-w-xl rounded-lg border border-border bg-card shadow-xl">
51
- <div className="flex items-center gap-2 border-b border-border p-3">
74
+ <div className="command-scrim" role="dialog" aria-modal="true" aria-label="Lattice command palette">
75
+ <div className="command-panel">
76
+ <div className="command-search">
52
77
  <Search className="h-4 w-4 text-muted-foreground" />
53
- <Input value={query} onChange={(e) => setQuery(e.target.value)} autoFocus placeholder="Jump to a capability" />
54
- <Button variant="ghost" size="icon" onClick={onClose}><X className="h-4 w-4" /></Button>
78
+ <Input value={query} onChange={(event) => setQuery(event.target.value)} autoFocus placeholder="Jump to anything in Lattice" />
79
+ <Button variant="ghost" size="icon" onClick={onClose} aria-label="Close command palette"><X className="h-4 w-4" /></Button>
55
80
  </div>
56
- <div className="max-h-96 overflow-auto p-2">
81
+ <div className="command-list soft-scrollbar">
57
82
  {matches.map((route) => {
58
83
  const Icon = route.icon;
59
84
  return (
@@ -63,10 +88,13 @@ function CommandPalette({ open, onClose }: { open: boolean; onClose: () => void
63
88
  go(route.key);
64
89
  onClose();
65
90
  }}
66
- className="flex w-full items-center gap-3 rounded-md px-3 py-2 text-left text-sm hover:bg-muted"
91
+ className="command-row"
67
92
  >
68
- <Icon className="h-4 w-4 text-primary" />
69
- {route.label}
93
+ <span className="command-icon"><Icon className="h-4 w-4" /></span>
94
+ <span>
95
+ <span className="block text-sm font-semibold">{route.label}</span>
96
+ <span className="block text-xs text-muted-foreground">Open {route.key.replace(/[-/]/g, " ")}</span>
97
+ </span>
70
98
  </button>
71
99
  );
72
100
  })}
@@ -76,6 +104,48 @@ function CommandPalette({ open, onClose }: { open: boolean; onClose: () => void
76
104
  );
77
105
  }
78
106
 
107
+ function PrimaryDock({ active, onNavigate }: { active: PrimaryRoute; onNavigate?: () => void }) {
108
+ return (
109
+ <nav className="primary-dock" aria-label="Primary navigation">
110
+ {primaryRoutes.map((item) => {
111
+ const Icon = item.icon;
112
+ const selected = active === item.id;
113
+ return (
114
+ <button
115
+ key={item.id}
116
+ className={cn("dock-button", selected && "is-active")}
117
+ onClick={() => {
118
+ go(item.id);
119
+ onNavigate?.();
120
+ }}
121
+ aria-current={selected ? "page" : undefined}
122
+ >
123
+ <Icon className="h-4 w-4" />
124
+ <span>{item.label}</span>
125
+ </button>
126
+ );
127
+ })}
128
+ </nav>
129
+ );
130
+ }
131
+
132
+ function ModeSwitch({ mode, setMode }: { mode: WorkspaceMode; setMode: (mode: WorkspaceMode) => void }) {
133
+ return (
134
+ <div className="mode-switch" aria-label="Experience mode">
135
+ {modes.map((item) => (
136
+ <button
137
+ key={item.id}
138
+ className={cn(mode === item.id && "is-active")}
139
+ onClick={() => setMode(item.id)}
140
+ aria-pressed={mode === item.id}
141
+ >
142
+ {item.label}
143
+ </button>
144
+ ))}
145
+ </div>
146
+ );
147
+ }
148
+
79
149
  export default function App() {
80
150
  const route = useRoute();
81
151
  const { theme, setTheme, mode, setMode } = useAppStore();
@@ -93,6 +163,7 @@ export default function App() {
93
163
  React.useEffect(() => {
94
164
  document.documentElement.dataset.theme = theme;
95
165
  }, [theme]);
166
+
96
167
  React.useEffect(() => {
97
168
  const onKey = (event: KeyboardEvent) => {
98
169
  if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") {
@@ -105,94 +176,84 @@ export default function App() {
105
176
  }, []);
106
177
 
107
178
  const healthData = (health.data?.data || {}) as Record<string, unknown>;
108
- const appVersion = typeof healthData.version === "string" ? healthData.version : null;
179
+ const workspaceData = (workspace.data?.data || {}) as Record<string, unknown>;
109
180
  const desktopData = (desktop.data?.data || {}) as Record<string, unknown>;
110
- const desktopError = typeof desktopData.last_error === "string" ? desktopData.last_error : desktop.data?.error;
111
-
112
- const rail = (
113
- <aside className="flex h-full w-64 shrink-0 flex-col border-r border-border bg-card">
114
- <div className="flex h-16 items-center gap-3 border-b border-border px-4">
115
- <div className="grid h-9 w-9 place-items-center rounded-md bg-primary text-primary-foreground font-bold">LA</div>
116
- <div>
117
- <div className="font-semibold">Lattice AI</div>
118
- <div className="text-xs text-muted-foreground">Digital Brain Desktop</div>
119
- </div>
120
- </div>
121
- <nav className="flex-1 space-y-1 overflow-auto p-3">
122
- {primaryRoutes.map((item) => {
123
- const Icon = item.icon;
124
- const active = route.primary === item.id;
125
- return (
126
- <button
127
- key={item.id}
128
- onClick={() => {
129
- go(item.id);
130
- setDrawer(false);
131
- }}
132
- className={cn(
133
- "flex min-h-14 w-full items-center gap-3 rounded-md px-3 py-2 text-left transition",
134
- active ? "bg-primary/14 text-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground",
135
- )}
136
- >
137
- <Icon className="h-5 w-5" />
138
- <span>
139
- <span className="block text-sm font-medium">{item.label}</span>
140
- <span className="block text-xs">{item.description}</span>
141
- </span>
142
- </button>
143
- );
144
- })}
145
- </nav>
146
- <div className="border-t border-border p-3 text-xs text-muted-foreground">
147
- <div>Server: {health.data?.ok ? "online" : "unavailable"}</div>
148
- {window.__TAURI_INTERNALS__ ? (
149
- <div>Sidecar: {desktopData.running ? "running" : desktopError ? `unavailable (${desktopError})` : "starting"}</div>
150
- ) : null}
151
- <div>Workspace: {String((workspace.data?.data as Record<string, unknown>)?.active_workspace || "local")}</div>
152
- </div>
153
- </aside>
154
- );
181
+ const appVersion = typeof healthData.version === "string" ? healthData.version : null;
182
+ const activeRoute = primaryRoutes.find((item) => item.id === route.primary);
183
+ const workspaceName = String(workspaceData.active_workspace || "Personal space");
184
+ const backendReady = Boolean(health.data?.ok);
185
+ const desktopReady = !window.__TAURI_INTERNALS__ || Boolean(desktopData.running);
155
186
 
156
187
  return (
157
- <div className="min-h-screen bg-background text-foreground">
188
+ <div className="app-backdrop min-h-screen text-foreground">
189
+ <AmbientBrain />
158
190
  <CommandPalette open={palette} onClose={() => setPalette(false)} />
159
- <div className="hidden lg:fixed lg:inset-y-0 lg:left-0 lg:block">{rail}</div>
191
+
192
+ <header className="app-chrome">
193
+ <div className="brand-lockup">
194
+ <button className="mobile-menu" onClick={() => setDrawer(true)} aria-label="Open navigation"><Menu className="h-5 w-5" /></button>
195
+ <button className="brand-mark" onClick={() => go("brain")} aria-label="Open Lattice home">
196
+ <BrainCircuit className="h-5 w-5" />
197
+ </button>
198
+ <div className="brand-copy">
199
+ <div className="brand-name">Lattice</div>
200
+ <div className="brand-subtitle">Digital Brain</div>
201
+ </div>
202
+ </div>
203
+
204
+ <div className="desktop-dock">
205
+ <PrimaryDock active={route.primary} />
206
+ </div>
207
+
208
+ <div className="chrome-actions">
209
+ <button className="status-chip" onClick={() => go("settings")}>
210
+ <span className={cn("status-light", backendReady && desktopReady ? "is-ready" : "is-waiting")} />
211
+ <span>{backendReady && desktopReady ? "Ready" : "Starting"}</span>
212
+ </button>
213
+ <Button variant="outline" onClick={() => setPalette(true)}><Command className="h-4 w-4" /> Find</Button>
214
+ <Button variant="outline" size="icon" onClick={() => setTheme(theme === "dark" ? "light" : "dark")} aria-label="Toggle theme">
215
+ {theme === "dark" ? <Sun className="h-4 w-4" /> : <Moon className="h-4 w-4" />}
216
+ </Button>
217
+ </div>
218
+ </header>
219
+
160
220
  {drawer ? (
161
- <div className="fixed inset-0 z-40 lg:hidden">
162
- <button className="absolute inset-0 bg-background/70" aria-label="Close navigation" onClick={() => setDrawer(false)} />
163
- <div className="relative h-full">{rail}</div>
221
+ <div className="mobile-drawer">
222
+ <button className="drawer-scrim" aria-label="Close navigation" onClick={() => setDrawer(false)} />
223
+ <div className="drawer-panel">
224
+ <div className="drawer-header">
225
+ <div>
226
+ <div className="font-semibold">Lattice</div>
227
+ <div className="text-xs text-muted-foreground">Choose a room</div>
228
+ </div>
229
+ <Button variant="ghost" size="icon" onClick={() => setDrawer(false)} aria-label="Close navigation"><X className="h-4 w-4" /></Button>
230
+ </div>
231
+ <PrimaryDock active={route.primary} onNavigate={() => setDrawer(false)} />
232
+ </div>
164
233
  </div>
165
234
  ) : null}
166
- <div className="lg:pl-64">
167
- <header className="sticky top-0 z-30 flex h-16 items-center justify-between gap-3 border-b border-border bg-background/95 px-4 backdrop-blur">
168
- <div className="flex min-w-0 items-center gap-2">
169
- <Button variant="ghost" size="icon" className="lg:hidden" onClick={() => setDrawer(true)}><Menu className="h-5 w-5" /></Button>
170
- <div className="min-w-0">
171
- <div className="truncate text-sm text-muted-foreground">{appVersion ? `v${appVersion}` : "Version unavailable"}</div>
172
- <div className="truncate font-medium">{primaryRoutes.find((item) => item.id === route.primary)?.label}</div>
173
- </div>
235
+
236
+ <main className="page-shell">
237
+ <section className="workspace-ribbon" aria-label="Current workspace">
238
+ <div className="min-w-0">
239
+ <div className="ribbon-kicker"><Sparkles className="h-4 w-4" /> {activeRoute?.label || "Home"}</div>
240
+ <h1>{activeRoute?.description || "A calm place to think with your knowledge."}</h1>
174
241
  </div>
175
- <div className="flex items-center gap-2">
176
- <Button variant="outline" onClick={() => setPalette(true)}><Command className="h-4 w-4" /> Search</Button>
177
- <select
178
- value={mode}
179
- onChange={(e) => setMode(e.target.value as "basic" | "advanced" | "admin")}
180
- className="h-9 rounded-md border border-border bg-background px-2 text-sm"
181
- aria-label="Workspace mode"
182
- >
183
- <option value="basic">Basic</option>
184
- <option value="advanced">Advanced</option>
185
- <option value="admin">Admin</option>
186
- </select>
187
- <Button variant="outline" size="icon" onClick={() => setTheme(theme === "dark" ? "light" : "dark")} aria-label="Toggle theme">
188
- {theme === "dark" ? <Sun className="h-4 w-4" /> : <Moon className="h-4 w-4" />}
189
- </Button>
242
+ <div className="ribbon-meta">
243
+ <div className="meta-card">
244
+ <CheckCircle2 className="h-4 w-4 text-primary" />
245
+ <span>{workspaceName}</span>
246
+ </div>
247
+ <div className="meta-card">
248
+ <span>{appVersion ? `v${appVersion}` : "Version checking"}</span>
249
+ </div>
250
+ <ModeSwitch mode={mode} setMode={setMode} />
190
251
  </div>
191
- </header>
192
- <main className="p-4 lg:p-6">
193
- <Page primary={route.primary} tab={route.tab} />
194
- </main>
195
- </div>
252
+ </section>
253
+
254
+ <FirstRunGuide />
255
+ <Page primary={route.primary} tab={route.tab} />
256
+ </main>
196
257
  </div>
197
258
  );
198
259
  }