@cryptiklemur/lattice 1.16.2 → 1.16.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CLAUDE.md CHANGED
@@ -1,35 +1,52 @@
1
- # Lattice — Project Rules
1
+ # CLAUDE.md
2
2
 
3
- ## Icons
4
- - Use `lucide-react` for ALL icons. Never write custom/inline SVG icons.
5
- - Import icons individually: `import { Settings, Moon, Sun } from "lucide-react"`
3
+ This file provides guidance to Claude Code when working with code in this repository.
4
+
5
+ ## Project Structure
6
+ Bun monorepo with three workspaces:
7
+ - `shared/` — TypeScript types and constants (no build, imported directly)
8
+ - `server/` — Bun daemon serving WebSocket API + static client assets on port 7654
9
+ - `client/` — React 19 + Vite + Tailwind + daisyUI web app
10
+
11
+ ## Commands
12
+ - `bun run dev` — starts server (--watch) + Vite dev server, hot reloads both
13
+ - `bun run build` — builds all workspaces (only client produces output)
14
+ - `bun run typecheck` — runs tsc across all workspaces
15
+ - `bunx playwright test` — runs Playwright tests (server must be running on :7654)
16
+ - Single test: `bunx playwright test tests/session-flow.spec.ts`
6
17
 
7
18
  ## Coding Standards
8
- - Use `var` instead of `const`/`let`. No arrow functions.
9
- - Server-side: ESM with Bun. Client-side: ESM with Vite + React.
10
- - No emojis for icons or in UI.
19
+ - Use `const`/`let` (not `var`). Use named function declarations, not arrow functions — except for anonymous callbacks where arrows are fine.
20
+ - No emojis for icons or in UI. Use `lucide-react` for all icons.
11
21
  - No section separator comments or organizational comments.
12
- - One class per file.
13
22
  - Follow .editorconfig (2-space indent, LF, UTF-8).
23
+ - Server: ESM with Bun. Client: ESM with Vite + React.
14
24
 
15
25
  ## Git
16
26
  - Never add "Co-Authored-By" lines mentioning Claude/AI.
17
- - Commit messages follow Angular Commit Convention.
27
+ - Commit messages follow Angular Commit Convention (feat/fix/refactor/etc).
18
28
  - Only commit when explicitly asked.
29
+ - Releases are automated via semantic-release on push to main.
19
30
 
20
- ## Development
21
- - Use `bun run dev` to start the development server — it hot reloads both the server and the web app automatically. No manual restart needed after code changes.
31
+ ## Design
32
+ See `.impeccable.md` for comprehensive design guidelines. Key constraints:
33
+ - Dark-first with 23 base16 themes via OKLCH CSS variables
34
+ - Tailwind + daisyUI component framework
35
+ - Typography: JetBrains Mono (headings/code), IBM Plex Sans (body)
36
+ - Three surface tiers: Chrome (base-200), Stage (base-100 + dot-grid), Elevated (base-300 + shadow)
37
+ - Never hardcode colors — always use CSS variables/theme tokens
38
+ - WCAG AA contrast, prefers-reduced-motion, keyboard-first
22
39
 
23
40
  ## Pre-existing Errors
24
- - DO NOT EVER LEAVE PRE-EXISTING ERRORS, FIX THEM.
25
-
26
- ## Design Context
27
- See `.impeccable.md` for comprehensive design guidelines. Key principles:
28
- - **Personality**: Precise, Technical, Calm quiet authority, no fluff
29
- - **Emotions**: Control & Mastery, Trust & Reliability
30
- - **Dark-first** with 23 base16 themes via OKLCH color space
31
- - **Typography**: JetBrains Mono (headings/code), IBM Plex Sans (body)
32
- - **Three surface tiers**: Chrome (base-200), Stage (base-100 + dot-grid), Elevated (base-300 + shadow)
33
- - **Design principles**: Earn every pixel, quiet confidence, state is sacred, dense but breathable, theme-native
34
- - **Accessibility**: WCAG AA, reduced motion, high contrast, color blind safe, mobile/responsive, keyboard-first
35
- - **Anti-patterns**: No gratuitous animation, no emoji icons, no hardcoded colors, no "AI slop" aesthetics
41
+ DO NOT EVER LEAVE PRE-EXISTING ERRORS. FIX THEM.
42
+
43
+ ## Environment
44
+ - ANTHROPIC_API_KEY is optional — server uses the token from `claude setup-token` if not set.
45
+ - Server binds to 0.0.0.0:7654 (WSL2 compatible).
46
+ - Client dev server runs on :5173 but production serves from server via client/dist/.
47
+
48
+ ## Testing
49
+ - Playwright tests live in `tests/` at the project root.
50
+ - Tests require the server running on localhost:7654.
51
+ - Screenshots on failure go to `test-results/`.
52
+ - Use Playwright MCP for visual verification. Save screenshots to `.playwright-mcp/`.
package/README.md CHANGED
@@ -1,23 +1,52 @@
1
1
  # Lattice
2
2
 
3
- Multi-machine agentic dashboard for Claude Code. Monitor sessions, manage MCP servers and skills, orchestrate across mesh-networked nodes.
3
+ Multi-machine agentic dashboard for Claude Code. Monitor sessions, manage projects, track costs, and orchestrate across mesh-networked nodes.
4
4
 
5
5
  > **Alpha** — Lattice is under active development. APIs and features may change.
6
6
 
7
+ ![Dashboard](docs/screenshots/dashboard.png)
8
+
7
9
  ## What is Lattice?
8
10
 
9
- Lattice is a web dashboard that sits alongside your Claude Code sessions. It gives you a unified view across projects, machines, and sessions — with real-time monitoring, configuration management, and a skill marketplace.
11
+ Lattice is a web dashboard that sits alongside your Claude Code sessions. It gives you a unified view across projects, machines, and sessions — with real-time monitoring, cost tracking, and configuration management.
12
+
13
+ ### Core Features
14
+
15
+ - **Multi-project dashboard** — Fleet overview with node status, session counts, cost stats, and recent activity across all projects
16
+ - **Real-time chat** — Send messages, approve tool use, monitor context window usage and costs with per-message token counts
17
+ - **Session management** — Browse, rename, delete, search, and resume sessions with date range filtering and hover previews
18
+ - **Analytics** — Cost over time, token flow, cache efficiency, session complexity, activity calendar, and 15+ chart types
19
+ - **Cost budget** — Daily spend tracking with configurable enforcement (warning, confirm, or hard block)
20
+ - **Theme system** — 23 base16 themes (12 dark, 11 light) with OKLCH color space for perceptual consistency
21
+
22
+ ![Chat View](docs/screenshots/chat-view.png)
23
+
24
+ ### Productivity
25
+
26
+ - **Session tabs** — Open multiple sessions as tabs, switch between them, split-pane via right-click
27
+ - **Message bookmarks** — Pin important messages, jump between bookmarks, global bookmarks view across all sessions
28
+ - **Keyboard shortcuts** — Press `?` to see all shortcuts, `Ctrl+K` for command palette
29
+ - **Message actions** — Copy messages (raw markdown or plain text), start new sessions from any message
30
+ - **Auto-titling** — Sessions automatically get descriptive titles from the first exchange
31
+ - **Session hover previews** — Hover any session to see cost, duration, message count, model, and last message
10
32
 
11
- ### Features
33
+ ![Analytics](docs/screenshots/analytics.png)
12
34
 
13
- - **Multi-project dashboard** — See recent sessions across all projects at a glance, jump back into any conversation
14
- - **MCP server management** — Add, edit, and remove MCP servers at global or project level through a visual editor
15
- - **Skill marketplace** — Search and install skills from [skills.sh](https://skills.sh), manage installed skills with rendered markdown previews
16
- - **Mesh networking** — Connect multiple machines into a mesh network, see node status and project distribution
17
- - **Session management** — Browse, rename, delete, and resume Claude Code sessions per project
18
- - **Real-time chat** — Send messages, approve tool use, monitor context usage and costs
19
- - **Theme system** — 23 base16 themes (dark and light) with OKLCH color space
35
+ ### Infrastructure
36
+
37
+ - **MCP server management** — Add, edit, and remove MCP servers at global or project level
38
+ - **Skill marketplace** — Search and install skills from [skills.sh](https://skills.sh)
39
+ - **Mesh networking** — Connect multiple machines, proxy sessions across nodes with automatic discovery
20
40
  - **Configuration editor** — Edit CLAUDE.md, environment variables, rules, and permissions through the UI
41
+ - **Memory management** — View and edit Claude's project memories with frontmatter metadata
42
+
43
+ ![Settings](docs/screenshots/settings.png)
44
+
45
+ ### Mobile Support
46
+
47
+ Responsive design with touch targets, swipe-to-open sidebar, and optimized layouts for mobile devices.
48
+
49
+ <img src="docs/screenshots/mobile-chat.png" width="300" alt="Mobile chat view" />
21
50
 
22
51
  ## Quick Start
23
52
 
@@ -48,17 +77,43 @@ bun install
48
77
  bun run dev
49
78
  ```
50
79
 
80
+ The dev server hot-reloads both the Bun server and the Vite client automatically.
81
+
51
82
  ## Architecture
52
83
 
53
- Lattice is a monorepo with three packages:
84
+ Lattice is a Bun monorepo with three packages:
54
85
 
55
86
  | Package | Description |
56
87
  |---------|------------|
57
- | `shared/` | TypeScript types, message definitions, constants |
58
- | `server/` | Bun WebSocket server — handlers, session management, mesh networking |
59
- | `client/` | React + Vite dashboard — UI components, state management, themes |
88
+ | `shared/` | TypeScript types, message protocol definitions, constants |
89
+ | `server/` | Bun WebSocket server — session management, analytics engine, mesh networking, structured logging |
90
+ | `client/` | React 19 + Vite + Tailwind + daisyUI — UI components, state management, 23 themes |
60
91
 
61
- The server communicates with clients via WebSocket using a typed message protocol defined in `shared/`. Sessions are managed through the Claude Agent SDK. The client uses Tanstack Store for state management and Tanstack Router for routing.
92
+ The server communicates with clients via WebSocket using a typed message protocol defined in `shared/`. Sessions are managed through the [Claude Agent SDK](https://github.com/anthropics/claude-agent-sdk). The client uses Tanstack Store for state and Tanstack Router for routing.
93
+
94
+ ### Security
95
+
96
+ - Authentication via passphrase with scrypt hashing and 24-hour token expiration
97
+ - Per-client WebSocket rate limiting (100 messages per 10-second window)
98
+ - Attachment upload size limits (10MB max)
99
+ - Bash `cd` commands boundary-checked against project directory
100
+ - Mesh pairing tokens expire after 5 minutes
101
+ - Graceful server shutdown with active stream draining
102
+
103
+ ### Testing
104
+
105
+ Playwright test suite covering onboarding, session flow, keyboard shortcuts, accessibility, message actions, and session previews.
106
+
107
+ ```bash
108
+ # Start the server first
109
+ bun run dev
110
+
111
+ # Run tests
112
+ bunx playwright test
113
+
114
+ # Single test file
115
+ bunx playwright test tests/session-flow.spec.ts
116
+ ```
62
117
 
63
118
  ## Configuration
64
119
 
@@ -66,14 +121,20 @@ Lattice stores its config at `~/.lattice/config.json`. Global Claude settings ar
66
121
 
67
122
  | Path | Purpose |
68
123
  |------|---------|
69
- | `~/.lattice/config.json` | Lattice daemon config (port, name, TLS, projects) |
124
+ | `~/.lattice/config.json` | Daemon config (port, name, TLS, projects, cost budget) |
125
+ | `~/.lattice/bookmarks.json` | Message bookmarks across all sessions |
70
126
  | `~/.claude/CLAUDE.md` | Global Claude instructions |
71
127
  | `~/.claude.json` | Global MCP server configuration |
72
128
  | `~/.claude/skills/` | Global skills directory |
73
- | `~/.claude/rules/` | Global rules |
74
129
 
75
130
  Project-level settings are stored in each project's `.claude/` directory and `.mcp.json`.
76
131
 
132
+ ### Environment
133
+
134
+ - `ANTHROPIC_API_KEY` — Optional. Server uses the token from `claude setup-token` if not set.
135
+ - `DEBUG=lattice:*` — Enable structured debug logging (namespaces: server, ws, chat, session, mesh, auth, fs, analytics)
136
+ - Server binds to `0.0.0.0:7654` by default. Override with `lattice --port <port>`.
137
+
77
138
  ## Contributing
78
139
 
79
140
  See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, coding standards, and pull request guidelines.
@@ -41,15 +41,15 @@ export function CacheEfficiencyChart({ data }: CacheEfficiencyChartProps) {
41
41
  <AreaChart data={displayData} margin={{ top: 4, right: 4, left: -20, bottom: 0 }}>
42
42
  <defs>
43
43
  <linearGradient id="cacheEffGrad" x1="0" y1="0" x2="0" y2="1">
44
- <stop offset="5%" stopColor={colors.success} stopOpacity={0.4} />
45
- <stop offset="95%" stopColor={colors.success} stopOpacity={0.02} />
44
+ <stop offset="5%" stopColor={colors.success} stopOpacity={0.8} />
45
+ <stop offset="95%" stopColor={colors.success} stopOpacity={0.2} />
46
46
  </linearGradient>
47
47
  </defs>
48
48
  <CartesianGrid strokeDasharray="3 3" stroke={colors.gridStroke} vertical={false} />
49
49
  <XAxis dataKey="date" tick={getTickStyle()} axisLine={false} tickLine={false} />
50
50
  <YAxis domain={[0, 100]} tick={getTickStyle()} axisLine={false} tickLine={false} tickFormatter={function (v) { return v + "%"; }} />
51
51
  <Tooltip content={<CustomTooltip />} />
52
- <Area type="monotone" dataKey="rate" stroke={colors.success} fill="url(#cacheEffGrad)" strokeWidth={1.5} />
52
+ <Area type="monotone" dataKey="rate" stroke={colors.success} fill="url(#cacheEffGrad)" strokeWidth={2} />
53
53
  </AreaChart>
54
54
  </ResponsiveContainer>
55
55
  );
@@ -49,20 +49,20 @@ export function CostAreaChart({ data }: CostAreaChartProps) {
49
49
  <AreaChart data={data} margin={{ top: 4, right: 4, left: -20, bottom: 0 }}>
50
50
  <defs>
51
51
  <linearGradient id="opusGrad" x1="0" y1="0" x2="0" y2="1">
52
- <stop offset="5%" stopColor={colors.secondary} stopOpacity={0.4} />
53
- <stop offset="95%" stopColor={colors.secondary} stopOpacity={0.05} />
52
+ <stop offset="5%" stopColor={colors.secondary} stopOpacity={0.8} />
53
+ <stop offset="95%" stopColor={colors.secondary} stopOpacity={0.2} />
54
54
  </linearGradient>
55
55
  <linearGradient id="sonnetGrad" x1="0" y1="0" x2="0" y2="1">
56
- <stop offset="5%" stopColor={colors.primary} stopOpacity={0.4} />
57
- <stop offset="95%" stopColor={colors.primary} stopOpacity={0.05} />
56
+ <stop offset="5%" stopColor={colors.primary} stopOpacity={0.8} />
57
+ <stop offset="95%" stopColor={colors.primary} stopOpacity={0.2} />
58
58
  </linearGradient>
59
59
  <linearGradient id="haikuGrad" x1="0" y1="0" x2="0" y2="1">
60
- <stop offset="5%" stopColor={colors.success} stopOpacity={0.4} />
61
- <stop offset="95%" stopColor={colors.success} stopOpacity={0.05} />
60
+ <stop offset="5%" stopColor={colors.success} stopOpacity={0.8} />
61
+ <stop offset="95%" stopColor={colors.success} stopOpacity={0.2} />
62
62
  </linearGradient>
63
63
  <linearGradient id="otherGrad" x1="0" y1="0" x2="0" y2="1">
64
- <stop offset="5%" stopColor={colors.warning} stopOpacity={0.4} />
65
- <stop offset="95%" stopColor={colors.warning} stopOpacity={0.05} />
64
+ <stop offset="5%" stopColor={colors.warning} stopOpacity={0.8} />
65
+ <stop offset="95%" stopColor={colors.warning} stopOpacity={0.2} />
66
66
  </linearGradient>
67
67
  </defs>
68
68
  <CartesianGrid strokeDasharray="3 3" stroke={colors.gridStroke} vertical={false} />
@@ -37,8 +37,8 @@ export function CostDistributionChart({ data }: CostDistributionChartProps) {
37
37
  <AreaChart data={data} margin={{ top: 4, right: 4, left: -20, bottom: 0 }}>
38
38
  <defs>
39
39
  <linearGradient id="distGrad" x1="0" y1="0" x2="0" y2="1">
40
- <stop offset="5%" stopColor={colors.primary} stopOpacity={0.35} />
41
- <stop offset="95%" stopColor={colors.primary} stopOpacity={0.02} />
40
+ <stop offset="5%" stopColor={colors.primary} stopOpacity={0.8} />
41
+ <stop offset="95%" stopColor={colors.primary} stopOpacity={0.2} />
42
42
  </linearGradient>
43
43
  </defs>
44
44
  <CartesianGrid strokeDasharray="3 3" stroke={colors.gridStroke} vertical={false} />
@@ -37,8 +37,8 @@ export function CumulativeCostChart({ data }: CumulativeCostChartProps) {
37
37
  <AreaChart data={data} margin={{ top: 4, right: 4, left: -20, bottom: 0 }}>
38
38
  <defs>
39
39
  <linearGradient id="cumulativeGrad" x1="0" y1="0" x2="0" y2="1">
40
- <stop offset="5%" stopColor={colors.primary} stopOpacity={0.3} />
41
- <stop offset="95%" stopColor={colors.primary} stopOpacity={0} />
40
+ <stop offset="5%" stopColor={colors.primary} stopOpacity={0.7} />
41
+ <stop offset="95%" stopColor={colors.primary} stopOpacity={0.15} />
42
42
  </linearGradient>
43
43
  </defs>
44
44
  <CartesianGrid strokeDasharray="3 3" stroke={colors.gridStroke} vertical={false} />
@@ -53,25 +53,25 @@ export function TokenFlowChart({ data }: TokenFlowChartProps) {
53
53
  <AreaChart data={data} margin={{ top: 4, right: 4, left: -20, bottom: 0 }}>
54
54
  <defs>
55
55
  <linearGradient id="inputGrad" x1="0" y1="0" x2="0" y2="1">
56
- <stop offset="5%" stopColor={colors.primary} stopOpacity={0.4} />
57
- <stop offset="95%" stopColor={colors.primary} stopOpacity={0.05} />
56
+ <stop offset="5%" stopColor={colors.primary} stopOpacity={0.8} />
57
+ <stop offset="95%" stopColor={colors.primary} stopOpacity={0.25} />
58
58
  </linearGradient>
59
59
  <linearGradient id="outputGrad" x1="0" y1="0" x2="0" y2="1">
60
- <stop offset="5%" stopColor={colors.success} stopOpacity={0.4} />
61
- <stop offset="95%" stopColor={colors.success} stopOpacity={0.05} />
60
+ <stop offset="5%" stopColor={colors.success} stopOpacity={0.8} />
61
+ <stop offset="95%" stopColor={colors.success} stopOpacity={0.25} />
62
62
  </linearGradient>
63
63
  <linearGradient id="cacheReadGrad" x1="0" y1="0" x2="0" y2="1">
64
- <stop offset="5%" stopColor={colors.warning} stopOpacity={0.4} />
65
- <stop offset="95%" stopColor={colors.warning} stopOpacity={0.05} />
64
+ <stop offset="5%" stopColor={colors.warning} stopOpacity={0.8} />
65
+ <stop offset="95%" stopColor={colors.warning} stopOpacity={0.25} />
66
66
  </linearGradient>
67
67
  </defs>
68
68
  <CartesianGrid strokeDasharray="3 3" stroke={colors.gridStroke} vertical={false} />
69
69
  <XAxis dataKey="date" tick={getTickStyle()} axisLine={false} tickLine={false} />
70
70
  <YAxis tick={getTickStyle()} axisLine={false} tickLine={false} tickFormatter={formatTokens} />
71
71
  <Tooltip content={<CustomTooltip />} />
72
- <Area type="monotone" dataKey="input" stackId="1" stroke={colors.primary} fill="url(#inputGrad)" strokeWidth={1.5} />
73
- <Area type="monotone" dataKey="output" stackId="1" stroke={colors.success} fill="url(#outputGrad)" strokeWidth={1.5} />
74
- <Area type="monotone" dataKey="cacheRead" stackId="1" stroke={colors.warning} fill="url(#cacheReadGrad)" strokeWidth={1.5} />
72
+ <Area type="monotone" dataKey="input" stackId="1" stroke={colors.primary} fill="url(#inputGrad)" strokeWidth={2} />
73
+ <Area type="monotone" dataKey="output" stackId="1" stroke={colors.success} fill="url(#outputGrad)" strokeWidth={2} />
74
+ <Area type="monotone" dataKey="cacheRead" stackId="1" stroke={colors.warning} fill="url(#cacheReadGrad)" strokeWidth={2} />
75
75
  </AreaChart>
76
76
  </ResponsiveContainer>
77
77
  );
@@ -1,5 +1,34 @@
1
1
  import { useState, useCallback, useRef } from "react";
2
2
 
3
+ interface SpeechRecognitionResult {
4
+ readonly transcript: string;
5
+ readonly confidence: number;
6
+ readonly isFinal: boolean;
7
+ }
8
+
9
+ interface SpeechRecognitionResultItem {
10
+ readonly length: number;
11
+ readonly isFinal: boolean;
12
+ item(index: number): SpeechRecognitionResult;
13
+ [index: number]: SpeechRecognitionResult;
14
+ }
15
+
16
+ interface SpeechRecognitionResultList {
17
+ readonly length: number;
18
+ item(index: number): SpeechRecognitionResultItem;
19
+ [index: number]: SpeechRecognitionResultItem;
20
+ }
21
+
22
+ interface SpeechRecognitionEvent extends Event {
23
+ readonly resultIndex: number;
24
+ readonly results: SpeechRecognitionResultList;
25
+ }
26
+
27
+ interface SpeechRecognitionErrorEvent extends Event {
28
+ readonly error: string;
29
+ readonly message: string;
30
+ }
31
+
3
32
  interface SpeechRecognitionLike extends EventTarget {
4
33
  continuous: boolean;
5
34
  interimResults: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cryptiklemur/lattice",
3
- "version": "1.16.2",
3
+ "version": "1.16.4",
4
4
  "description": "Multi-machine agentic dashboard for Claude Code. Monitor sessions, manage MCP servers and skills, orchestrate across mesh-networked nodes.",
5
5
  "license": "MIT",
6
6
  "author": "Aaron Scherer <me@aaronscherer.me>",