@a13xu/lucid 1.16.0 → 1.16.2

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/README.md CHANGED
@@ -4,11 +4,11 @@
4
4
  [![npm downloads](https://img.shields.io/npm/dm/@a13xu/lucid)](https://www.npmjs.com/package/@a13xu/lucid)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
6
 
7
- > **MCP server for Claude Code** — persistent memory, smart code indexing, and code quality validation. Works out of the box with zero configuration.
7
+ > **MCP server for Claude Code** — persistent memory, smart code indexing, model selection, and code quality validation. Works out of the box with zero configuration.
8
8
 
9
9
  Token-efficient memory, code indexing, and validation for Claude Code agents — backed by **SQLite + FTS5**.
10
10
 
11
- Stores a persistent knowledge graph (entities, relations, observations), indexes source files as compressed binary with change detection, retrieves minimal relevant context via TF-IDF or Qdrant, and validates code for LLM drift patterns. Supports TypeScript, JavaScript, Python, **Vue, Nuxt**.
11
+ Stores a persistent knowledge graph (entities, relations, observations), indexes source files as compressed binary with change detection, retrieves minimal relevant context via TF-IDF or Qdrant, and validates code for LLM drift patterns. Supports TypeScript, JavaScript, Python, **Vue, Nuxt**. Optional **LLMLingua-2 semantic compression** reduces context tokens by 30–70% while preserving meaning.
12
12
 
13
13
  ## Install
14
14
 
@@ -45,15 +45,16 @@ Default DB path: `~/.claude/memory.db`
45
45
  ## Quick start
46
46
 
47
47
  ```
48
- 1. "Index this project" → init_project() → scans CLAUDE.md, package.json, src/**
49
- 2. Write code → sync_file(path) → compressed + hashed + diff stored
50
- 3. "What's relevant?" → get_context("auth flow") TF-IDF ranked skeletons, ~500 tokens
51
- 4. "What changed?" get_recent(hours=2) line diffs of recent edits
52
- 5. "Where is X used?" grep_code("X") matching lines only, ~30 tokens
53
- 6. "What do we know?" → recall("query") knowledge graph search
48
+ 1. "Index this project" → init_project() → scans CLAUDE.md, package.json, src/**
49
+ 2. Write code → sync_file(path) → compressed + hashed + diff stored
50
+ 3. "What's relevant?" → smart_context("auth flow") recall + code in one call, adaptive budget
51
+ 4. "What model?" suggest_model("refactor auth") haiku (lookup) or sonnet (reasoning)
52
+ 5. "What changed?" get_recent(hours=2) line diffs of recent edits
53
+ 6. "Where is X used?" → grep_code("X") matching lines only, ~30 tokens
54
+ 7. "What do we know?" → recall("query") → knowledge graph search
54
55
  ```
55
56
 
56
- ## Tools (30)
57
+ ## Tools (37)
57
58
 
58
59
  ### Memory
59
60
  | Tool | Description |
@@ -76,8 +77,11 @@ Default DB path: `~/.claude/memory.db`
76
77
  ### Token optimization
77
78
  | Tool | Description |
78
79
  |---|---|
79
- | `get_context` | **Smart context retrieval.** Ranks all indexed files by TF-IDF relevance (or Qdrant vector search if `QDRANT_URL` is set), applies recency boost, returns skeletons (imports + signatures only) for large files. Respects `maxContextTokens` budget. |
80
+ | `smart_context` | **Recommended entry point.** Combines `recall()` (knowledge graph) + `get_context()` (code files) in one call. Adaptive token budget: `simple`=2000, `moderate`=6000, `complex`=12000. Logs an experience for `reward()`/`penalize()` feedback. |
81
+ | `suggest_model` | Classify task complexity → recommend Claude model. Returns `{ model, model_id, reasoning, context_budget }`. Simple lookups → Haiku; reasoning/code → Sonnet. Call at the start of any workflow. |
82
+ | `get_context` | **Classic code context.** Ranks indexed files by TF-IDF (or Qdrant), applies recency boost, returns skeletons for large files. Respects `maxContextTokens` budget. |
80
83
  | `get_recent` | Return files modified in the last N hours with line-level diffs. |
84
+ | `compress_text` | Compress any text using LLMLingua-2 semantic compression. Returns compressed text + stats (ratio, tokens saved). Model downloads ~700MB on first use. |
81
85
 
82
86
  ### Logic Guardian
83
87
  | Tool | Description |
@@ -86,11 +90,19 @@ Default DB path: `~/.claude/memory.db`
86
90
  | `check_drift` | Analyze a code snippet inline without saving to disk. |
87
91
  | `get_checklist` | Return the full 5-pass validation protocol (Logic Trace, Contract Verification, Stupid Mistakes, Integration Sanity, Explain It). |
88
92
 
93
+ ### Plans
94
+ | Tool | Description |
95
+ |---|---|
96
+ | `plan_create` | Create a development plan with title, description, and tasks. Returns plan ID. |
97
+ | `plan_list` | List all plans with status summary (total/done/in-progress tasks). |
98
+ | `plan_get` | Get full plan details including all tasks and their status. |
99
+ | `plan_update_task` | Update a task's status (`pending` → `in_progress` → `done` \| `blocked`) and optionally add notes. Accepts `task_id` as number or string. |
100
+
89
101
  ### Reward system
90
102
  | Tool | Description |
91
103
  |---|---|
92
- | `reward` | Signal that the last `get_context()` result was helpful (+1). Rewarded files rank higher in future similar queries. |
93
- | `penalize` | Signal that the last `get_context()` result was unhelpful (-1). Penalized files rank lower in future queries. |
104
+ | `reward` | Signal that the last `smart_context()`/`get_context()` result was helpful (+1). Rewarded files rank higher in future similar queries. |
105
+ | `penalize` | Signal that the last result was unhelpful (-1). Penalized files rank lower. Accepts optional `note` to log what was missing. |
94
106
  | `show_rewards` | Show top rewarded experiences and most rewarded files. Rewards decay exponentially (half-life ~14 days). |
95
107
 
96
108
  ### Code Quality Guard
@@ -115,7 +127,31 @@ Default DB path: `~/.claude/memory.db`
115
127
 
116
128
  ## Token optimization in depth
117
129
 
118
- ### How `get_context` works
130
+ ### How `smart_context` works (recommended)
131
+
132
+ ```
133
+ query: "auth middleware"
134
+
135
+ 1. recall(query) — knowledge graph search (entities, relations)
136
+
137
+ 2. TF-IDF score all indexed files against query
138
+ (or Qdrant top-k if QDRANT_URL is set)
139
+
140
+ 3. Boost recently-modified files (+0.3 score)
141
+ Boost rewarded files (+0.25 score, decayed)
142
+
143
+ 4. For each file within token budget:
144
+ file < maxTokensPerFile → return full source
145
+ file > maxTokensPerFile → return skeleton only
146
+ (imports + signatures + TODOs)
147
+ + relevant fragments around query terms
148
+
149
+ 5. Optional: LLMLingua-2 compression (if enabled in config)
150
+
151
+ output: merged knowledge + code — budget: 2k/6k/12k by task_type
152
+ ```
153
+
154
+ ### How `get_context` works (classic)
119
155
 
120
156
  ```
121
157
  query: "auth middleware"
@@ -183,6 +219,32 @@ Or in `.mcp.json`:
183
219
 
184
220
  Falls back to TF-IDF automatically if Qdrant is unreachable.
185
221
 
222
+ ### Semantic compression (optional)
223
+
224
+ LLMLingua-2 (`microsoft/llmlingua-2-bert-base-multilingual-cased-meetingbank`) identifies and drops semantically unimportant tokens before returning context to Claude — and before generating Qdrant embeddings.
225
+
226
+ Enable in `lucid.config.json`:
227
+
228
+ ```json
229
+ {
230
+ "semanticCompression": {
231
+ "enabled": true,
232
+ "ratio": 0.5,
233
+ "minLength": 300,
234
+ "applyToEmbeddings": true
235
+ }
236
+ }
237
+ ```
238
+
239
+ | Key | Default | Description |
240
+ |---|---|---|
241
+ | `enabled` | `false` | Opt-in — model downloads ~700MB on first use |
242
+ | `ratio` | `0.5` | Fraction of tokens to keep (0.3 = keep 30%) |
243
+ | `minLength` | `300` | Skip compression for texts shorter than this |
244
+ | `applyToEmbeddings` | `true` | Also compress chunk text before Qdrant embedding |
245
+
246
+ Model is cached in `~/.lucid/models/` after first download. Falls back to uncompressed text on any error — safe to enable unconditionally.
247
+
186
248
  ### Configuration (`lucid.config.json`)
187
249
 
188
250
  Create in your project root to customize behavior:
@@ -191,9 +253,13 @@ Create in your project root to customize behavior:
191
253
  {
192
254
  "whitelistDirs": ["src", "backend", "api"],
193
255
  "blacklistDirs": ["migrations", "fixtures"],
194
- "maxTokensPerFile": 400,
195
- "maxContextTokens": 6000,
196
- "recentWindowHours": 12
256
+ "maxTokensPerFile": 600,
257
+ "maxContextTokens": 8000,
258
+ "recentWindowHours": 48,
259
+ "semanticCompression": {
260
+ "enabled": false,
261
+ "ratio": 0.5
262
+ }
197
263
  }
198
264
  ```
199
265
 
@@ -201,9 +267,9 @@ Create in your project root to customize behavior:
201
267
  |---|---|---|
202
268
  | `whitelistDirs` | — | Only index/return files from these dirs |
203
269
  | `blacklistDirs` | — | Extra dirs to skip (merged with built-in skips) |
204
- | `maxTokensPerFile` | `400` | Files above this get skeleton treatment |
205
- | `maxContextTokens` | `4000` | Total token budget for `get_context` |
206
- | `recentWindowHours` | `24` | "Recently touched" threshold |
270
+ | `maxTokensPerFile` | `600` | Files above this get skeleton treatment |
271
+ | `maxContextTokens` | `8000` | Total token budget for `get_context` |
272
+ | `recentWindowHours` | `48` | "Recently touched" threshold |
207
273
 
208
274
  ## Why no vectors by default?
209
275
 
@@ -237,6 +303,63 @@ TF-IDF is fast, deterministic, and requires zero external services. Qdrant is av
237
303
  ## Relation types
238
304
  `uses` · `depends_on` · `created_by` · `part_of` · `replaced_by` · `conflicts_with` · `tested_by`
239
305
 
306
+ ## HTTP daemon & auto-sync
307
+
308
+ Lucid can run as a background HTTP daemon (port 7821) for auto-syncing files without Claude's cooperation.
309
+
310
+ ```bash
311
+ # Start daemon (watches for sync requests, serves REST API)
312
+ lucid watch
313
+
314
+ # With HTTP server
315
+ lucid watch --http
316
+
317
+ # Check status
318
+ lucid status
319
+
320
+ # Stop
321
+ lucid stop
322
+ ```
323
+
324
+ ### REST API (when `--http` is active)
325
+
326
+ | Endpoint | Description |
327
+ |---|---|
328
+ | `POST /sync` `{ path }` | Sync a single file |
329
+ | `POST /sync-project` `{ directory? }` | Sync entire project |
330
+ | `GET /context?q=<query>` | Get context via HTTP |
331
+ | `POST /validate` `{ path }` | Validate file for drift |
332
+ | `GET /health` | Daemon health check |
333
+
334
+ ### Auto-sync hook (`lucid-sync`)
335
+
336
+ `init_project` installs a Claude Code `PostToolUse` hook that calls `lucid-sync` after every file write/edit. The sync binary:
337
+
338
+ 1. Tries HTTP sync (500ms timeout, if daemon running)
339
+ 2. Falls back to direct SQLite sync (no daemon needed)
340
+
341
+ This keeps the knowledge graph current automatically — without relying on Claude remembering to call `sync_file`.
342
+
343
+ ## Skills enforcement
344
+
345
+ Lucid ships **enforcement skills** that install globally into `~/.claude/skills/` and activate in every project:
346
+
347
+ | Skill | Purpose |
348
+ |---|---|
349
+ | `lucid-start` | Session start — `get_recent` + `smart_context` before any coding |
350
+ | `lucid-context` | Pre-task context loading — `suggest_model` + `smart_context` |
351
+ | `lucid-audit` | Pre-done gate — validate + check drift before marking complete |
352
+ | `lucid-plan` | Planning workflow |
353
+ | `lucid-sync` | Post-edit sync reminder |
354
+ | `lucid-webdev` | Web dev workflow with context |
355
+
356
+ All skills use `<HARD-GATE>` blocks that prevent proceeding until required tools are called.
357
+
358
+ Install globally:
359
+ ```bash
360
+ init_project() # installs skills to ~/.claude/skills/ automatically
361
+ ```
362
+
240
363
  ## Debugging
241
364
 
242
365
  ```bash
@@ -244,7 +367,7 @@ echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"capabilities":{},
244
367
  | npx @a13xu/lucid
245
368
  ```
246
369
 
247
- In Claude Code: run `/mcp` — you should see `lucid` with 20 tools.
370
+ In Claude Code: run `/mcp` — you should see `lucid` with 37 tools.
248
371
 
249
372
  ## Contributing
250
373
 
@@ -260,8 +383,11 @@ Bug reports and pull requests are welcome on [GitHub](https://github.com/a13xu/l
260
383
  - **Runtime:** Node.js 18+, TypeScript, ES modules
261
384
  - **MCP SDK:** `@modelcontextprotocol/sdk`
262
385
  - **Database:** `better-sqlite3` (synchronous, WAL mode)
263
- - **Compression:** Node.js built-in `zlib` (deflate level 9)
386
+ - **Compression:** Node.js built-in `zlib` (deflate level 9) + LLMLingua-2 semantic compression (optional)
264
387
  - **Hashing:** SHA-256 via `crypto` (change detection)
265
388
  - **Ranking:** TF-IDF (built-in) or Qdrant (optional, via REST)
389
+ - **Semantic compression:** `@huggingface/transformers` (ONNX Runtime, q8 quantization)
390
+ - **HTTP daemon:** Express 5 on port 7821 (optional)
391
+ - **File watcher:** `chokidar`
266
392
  - **Validation:** `zod`
267
393
  - **Transport:** stdio
@@ -13,7 +13,11 @@
13
13
  import { join } from "path";
14
14
  import { homedir } from "os";
15
15
  import { mkdirSync } from "fs";
16
- const MODEL_ID = "microsoft/llmlingua-2-bert-base-multilingual-cased-meetingbank";
16
+ // Microsoft's original repo ships only PyTorch weights, so transformers.js
17
+ // (ONNX Runtime) cannot load it. ldenoue/* mirrors the same checkpoint with
18
+ // pre-built `onnx/model.onnx` (710 MB) and `onnx/model_quantized.onnx` (179 MB),
19
+ // matching the dtype lookups used below.
20
+ const MODEL_ID = "ldenoue/llmlingua-2-bert-base-multilingual-cased-meetingbank";
17
21
  const MODELS_DIR = join(homedir(), ".lucid", "models");
18
22
  let _pipeline = null;
19
23
  let _loadError = null;
@@ -1 +1,2 @@
1
- export declare const CHECKLIST = "# Logic Guardian \u2014 Validation Checklist (5 passes)\n\n## Pass 1: Logic Trace\nTrace through the code with CONCRETE values:\n- Happy path \u2192 real values, write each variable state\n- Empty/zero \u2192 null, 0, \"\", []\n- Boundary \u2192 first element, last element, max int, single char\n- Error case \u2192 network down, file missing, permission denied\n\nSTOP if any trace produces unexpected output. Fix before continuing.\n\n## Pass 2: Contract Verification\n- [ ] Preconditions: what must be true BEFORE this runs? Is it checked?\n- [ ] Postconditions: what must be true AFTER? Can you prove it?\n- [ ] Invariants: what must ALWAYS be true? Does the code maintain it?\n- [ ] Return type: does EVERY code path return the expected type?\n- [ ] Side effects: are all side effects intentional?\n\n## Pass 3: Stupid Mistakes Checklist\n\n### Off-by-one\n- [ ] < vs <= \u2014 verify with boundary values\n- [ ] Array indices \u2014 last is length - 1\n- [ ] Loop iterations \u2014 exactly N times?\n\n### Null/Undefined Propagation\n- [ ] Every .property access \u2014 can the object be null?\n- [ ] Every array index \u2014 can the array be empty?\n- [ ] Every map lookup \u2014 can the key be missing?\n\n### Type Confusion\n- [ ] String vs Number comparisons\n- [ ] Integer vs Float division\n- [ ] Boolean coercion edge cases\n\n### Logic Inversions (THE #1 LLM drift pattern)\n- [ ] if/else \u2014 is the condition testing what you THINK?\n- [ ] Early returns \u2014 does the guard return the RIGHT value?\n- [ ] filter/find/some \u2014 keeping the RIGHT elements?\n- [ ] Error handling \u2014 catching and re-throwing correctly?\n\n### State & Mutation\n- [ ] Mutating shared object when you should copy?\n- [ ] Async state read after it might have changed?\n\n### Copy-Paste Drift\n- [ ] ALL variable names updated in copied blocks?\n- [ ] Conditions changed, not just variable names?\n\n## Pass 4: Integration Sanity\n- [ ] Breaks existing callers?\n- [ ] Imports/exports correct?\n- [ ] If async, all callers awaiting it?\n- [ ] If type changed, all usages updated?\n\n## Pass 5: Explain It Test\nIn ONE sentence: what does this code do?\nIf you can't explain it, or the sentence doesn't match the code \u2192 something is wrong.\n\n## Anti-Drift Triggers\nSTOP if you find yourself thinking:\n- \"This is similar to...\" \u2192 You're pattern-matching. TRACE THE LOGIC.\n- \"This should work because the other one does\" \u2192 VERIFY INDEPENDENTLY.\n- \"I'll just copy and change the names\" \u2192 CHECK EVERY DIFFERENCE.\n- \"The error handling is probably fine\" \u2192 TRACE THE ERROR PATH.\n- \"This is standard boilerplate\" \u2192 Verify it fits this context.\n";
1
+ export declare const ORIGINAL_CHECKLIST = "# Logic Guardian \u2014 Validation Checklist (5 passes)\n\n## Pass 1: Logic Trace\nTrace through the code with CONCRETE values:\n- Happy path \u2192 real values, write each variable state\n- Empty/zero \u2192 null, 0, \"\", []\n- Boundary \u2192 first element, last element, max int, single char\n- Error case \u2192 network down, file missing, permission denied\n\nSTOP if any trace produces unexpected output. Fix before continuing.\n\n## Pass 2: Contract Verification\n- [ ] Preconditions: what must be true BEFORE this runs? Is it checked?\n- [ ] Postconditions: what must be true AFTER? Can you prove it?\n- [ ] Invariants: what must ALWAYS be true? Does the code maintain it?\n- [ ] Return type: does EVERY code path return the expected type?\n- [ ] Side effects: are all side effects intentional?\n\n## Pass 3: Stupid Mistakes Checklist\n\n### Off-by-one\n- [ ] < vs <= \u2014 verify with boundary values\n- [ ] Array indices \u2014 last is length - 1\n- [ ] Loop iterations \u2014 exactly N times?\n\n### Null/Undefined Propagation\n- [ ] Every .property access \u2014 can the object be null?\n- [ ] Every array index \u2014 can the array be empty?\n- [ ] Every map lookup \u2014 can the key be missing?\n\n### Type Confusion\n- [ ] String vs Number comparisons\n- [ ] Integer vs Float division\n- [ ] Boolean coercion edge cases\n\n### Logic Inversions (THE #1 LLM drift pattern)\n- [ ] if/else \u2014 is the condition testing what you THINK?\n- [ ] Early returns \u2014 does the guard return the RIGHT value?\n- [ ] filter/find/some \u2014 keeping the RIGHT elements?\n- [ ] Error handling \u2014 catching and re-throwing correctly?\n\n### State & Mutation\n- [ ] Mutating shared object when you should copy?\n- [ ] Async state read after it might have changed?\n\n### Copy-Paste Drift\n- [ ] ALL variable names updated in copied blocks?\n- [ ] Conditions changed, not just variable names?\n\n## Pass 4: Integration Sanity\n- [ ] Breaks existing callers?\n- [ ] Imports/exports correct?\n- [ ] If async, all callers awaiting it?\n- [ ] If type changed, all usages updated?\n\n## Pass 5: Explain It Test\nIn ONE sentence: what does this code do?\nIf you can't explain it, or the sentence doesn't match the code \u2192 something is wrong.\n\n## Anti-Drift Triggers\nSTOP if you find yourself thinking:\n- \"This is similar to...\" \u2192 You're pattern-matching. TRACE THE LOGIC.\n- \"This should work because the other one does\" \u2192 VERIFY INDEPENDENTLY.\n- \"I'll just copy and change the names\" \u2192 CHECK EVERY DIFFERENCE.\n- \"The error handling is probably fine\" \u2192 TRACE THE ERROR PATH.\n- \"This is standard boilerplate\" \u2192 Verify it fits this context.\n";
2
+ export declare const CHECKLIST: string;
@@ -1,4 +1,7 @@
1
- export const CHECKLIST = `# Logic Guardian — Validation Checklist (5 passes)
1
+ import { join } from "path";
2
+ import { homedir } from "os";
3
+ import { existsSync, readFileSync } from "fs";
4
+ export const ORIGINAL_CHECKLIST = `# Logic Guardian — Validation Checklist (5 passes)
2
5
 
3
6
  ## Pass 1: Logic Trace
4
7
  Trace through the code with CONCRETE values:
@@ -65,3 +68,19 @@ STOP if you find yourself thinking:
65
68
  - "The error handling is probably fine" → TRACE THE ERROR PATH.
66
69
  - "This is standard boilerplate" → Verify it fits this context.
67
70
  `;
71
+ // Opt-in: if a pre-compressed copy exists at ~/.lucid/compressed-prompts/checklist.txt
72
+ // (produced by `npm run compress-prompts`), serve that instead. Falls back to the
73
+ // original on any error so this is always safe.
74
+ function loadCompressed() {
75
+ try {
76
+ const p = join(homedir(), ".lucid", "compressed-prompts", "checklist.txt");
77
+ if (!existsSync(p))
78
+ return null;
79
+ const text = readFileSync(p, "utf-8").trim();
80
+ return text.length > 0 ? text : null;
81
+ }
82
+ catch {
83
+ return null;
84
+ }
85
+ }
86
+ export const CHECKLIST = loadCompressed() ?? ORIGINAL_CHECKLIST;
@@ -1 +1,2 @@
1
- export declare const CODING_RULES = "# 25 Golden Rules \u2014 Code Quality Checklist\n\n## Section 1: General Quality (Rules 1\u201310)\n\n- [ ] **Rule 1 \u2014 File Size**: File is under 500 lines (components under 300).\n PASS: file has fewer lines. FAIL: file exceeds limit \u2014 split into modules.\n\n- [ ] **Rule 2 \u2014 Function Length**: Every function/method is under 60 lines.\n PASS: function is focused and short. FAIL: function exceeds 60 lines \u2014 break it up.\n\n- [ ] **Rule 3 \u2014 Meaningful Names**: No vague variable names (x, tmp, data, val, obj, foo, bar).\n No vague function names (doSomething, handleStuff, processData, manage, doWork).\n PASS: names explain purpose. FAIL: name is a placeholder \u2014 rename to intent.\n\n- [ ] **Rule 4 \u2014 Single Responsibility**: Functions/methods do exactly ONE thing.\n If the name contains \"And\" or \"Or\", it is doing two things.\n PASS: one verb, one concept. FAIL: split into two functions.\n\n- [ ] **Rule 5 \u2014 No Dead Code**: No commented-out code blocks (3+ consecutive lines with =, (, {, ;).\n PASS: code is live. FAIL: remove dead code \u2014 use version control for history.\n\n- [ ] **Rule 6 \u2014 Explicit Error Handling**: Errors are caught, logged, or re-thrown.\n No silent swallowing (catch {} or except: pass).\n PASS: every error path is handled. FAIL: add logging or re-throw.\n\n- [ ] **Rule 7 \u2014 No Magic Numbers**: Numeric literals are replaced with named constants.\n PASS: constants have descriptive names. FAIL: extract to a named constant.\n\n- [ ] **Rule 8 \u2014 Max 3 Nesting Levels**: Code is not nested more than 3 levels deep.\n PASS: deepest indent is 3 levels. FAIL: extract logic or use early returns.\n\n- [ ] **Rule 9 \u2014 DRY (Don't Repeat Yourself)**: No near-duplicate blocks of code.\n PASS: logic is extracted into a shared function. FAIL: refactor duplicates.\n\n- [ ] **Rule 10 \u2014 Explicit Return Types**: Typed languages declare return types on public functions.\n PASS: all public functions have explicit return types. FAIL: add return type annotation.\n\n## Section 2: Frontend Components (Rules 11\u201318)\n\n- [ ] **Rule 11 \u2014 Component Size**: UI components are under 300 lines.\n PASS: component is focused. FAIL: extract sub-components or custom hooks.\n\n- [ ] **Rule 12 \u2014 No Inline Styles**: No style={{ }} in JSX/Vue templates.\n PASS: styles are in CSS/SCSS/CSS-in-JS. FAIL: move to stylesheet or styled component.\n\n- [ ] **Rule 13 \u2014 Prop Limit**: Components accept at most 8 props.\n PASS: props are few and cohesive. FAIL: group related props into an object.\n\n- [ ] **Rule 14 \u2014 Prefer Composition**: Large components are split into sub-components.\n No \"god components\" handling layout + data + formatting + interaction.\n PASS: each component has one visual/logical role. FAIL: extract a sub-component.\n\n- [ ] **Rule 15 \u2014 No Direct DOM Access**: No document.querySelector / getElementById in components.\n PASS: refs are used (useRef, ref=). FAIL: replace with ref mechanism.\n\n- [ ] **Rule 16 \u2014 Data Fetching in Services/Hooks**: No fetch() or axios calls in component body.\n PASS: data fetching is in a custom hook or service. FAIL: extract to useXxx hook.\n\n- [ ] **Rule 17 \u2014 One Styling System**: File uses only one styling approach\n (Tailwind OR styled-components OR CSS modules \u2014 not all three).\n PASS: consistent styling. FAIL: standardize on one approach.\n\n- [ ] **Rule 18 \u2014 No Nested Ternaries in JSX**: JSX conditionals use if/else or variables, not nested ternaries.\n PASS: conditions are readable. FAIL: extract condition to a variable or early return.\n\n## Section 3: Architecture (Rules 19\u201325)\n\n- [ ] **Rule 19 \u2014 Single Source of Truth**: State is not duplicated across multiple stores or components.\n PASS: one authoritative source for each piece of state. FAIL: remove duplication.\n\n- [ ] **Rule 20 \u2014 UI/Logic Separation**: Business logic is not inside UI components.\n PASS: components call services/hooks; logic lives elsewhere. FAIL: extract to service.\n\n- [ ] **Rule 21 \u2014 Dependency Abstraction**: External APIs/SDKs are wrapped in adapter/service layers.\n PASS: swapping a library touches one file. FAIL: add an abstraction layer.\n\n- [ ] **Rule 22 \u2014 No Circular Imports**: Module dependency graph is a DAG (no cycles).\n PASS: import graph has no cycles. FAIL: restructure modules to remove the cycle.\n\n- [ ] **Rule 23 \u2014 Config in Dedicated Files**: Magic strings and environment-specific values are in config files.\n PASS: config is centralized. FAIL: extract to config.ts or .env.\n\n- [ ] **Rule 24 \u2014 Public API Coverage**: Every exported function has a corresponding test.\n PASS: public API is covered by tests. FAIL: write a test for the new export.\n\n- [ ] **Rule 25 \u2014 No God Objects**: Classes/modules are focused \u2014 no object that knows everything.\n PASS: objects have clear, narrow responsibilities. FAIL: split the god object.\n\n---\n\n## Quick Check Before Marking Done\n\n1. Run `check_code_quality` on modified files \u2014 fix HIGH severity issues.\n2. Run `validate_file` (Logic Guardian) \u2014 fix correctness bugs first.\n3. Verify rules 3, 4, 8 manually (naming and nesting are hard to auto-detect fully).\n4. For frontend work, verify rules 12, 15, 16 \u2014 these are the most common oversights.\n";
1
+ export declare const ORIGINAL_CODING_RULES = "# 25 Golden Rules \u2014 Code Quality Checklist\n\n## Section 1: General Quality (Rules 1\u201310)\n\n- [ ] **Rule 1 \u2014 File Size**: File is under 500 lines (components under 300).\n PASS: file has fewer lines. FAIL: file exceeds limit \u2014 split into modules.\n\n- [ ] **Rule 2 \u2014 Function Length**: Every function/method is under 60 lines.\n PASS: function is focused and short. FAIL: function exceeds 60 lines \u2014 break it up.\n\n- [ ] **Rule 3 \u2014 Meaningful Names**: No vague variable names (x, tmp, data, val, obj, foo, bar).\n No vague function names (doSomething, handleStuff, processData, manage, doWork).\n PASS: names explain purpose. FAIL: name is a placeholder \u2014 rename to intent.\n\n- [ ] **Rule 4 \u2014 Single Responsibility**: Functions/methods do exactly ONE thing.\n If the name contains \"And\" or \"Or\", it is doing two things.\n PASS: one verb, one concept. FAIL: split into two functions.\n\n- [ ] **Rule 5 \u2014 No Dead Code**: No commented-out code blocks (3+ consecutive lines with =, (, {, ;).\n PASS: code is live. FAIL: remove dead code \u2014 use version control for history.\n\n- [ ] **Rule 6 \u2014 Explicit Error Handling**: Errors are caught, logged, or re-thrown.\n No silent swallowing (catch {} or except: pass).\n PASS: every error path is handled. FAIL: add logging or re-throw.\n\n- [ ] **Rule 7 \u2014 No Magic Numbers**: Numeric literals are replaced with named constants.\n PASS: constants have descriptive names. FAIL: extract to a named constant.\n\n- [ ] **Rule 8 \u2014 Max 3 Nesting Levels**: Code is not nested more than 3 levels deep.\n PASS: deepest indent is 3 levels. FAIL: extract logic or use early returns.\n\n- [ ] **Rule 9 \u2014 DRY (Don't Repeat Yourself)**: No near-duplicate blocks of code.\n PASS: logic is extracted into a shared function. FAIL: refactor duplicates.\n\n- [ ] **Rule 10 \u2014 Explicit Return Types**: Typed languages declare return types on public functions.\n PASS: all public functions have explicit return types. FAIL: add return type annotation.\n\n## Section 2: Frontend Components (Rules 11\u201318)\n\n- [ ] **Rule 11 \u2014 Component Size**: UI components are under 300 lines.\n PASS: component is focused. FAIL: extract sub-components or custom hooks.\n\n- [ ] **Rule 12 \u2014 No Inline Styles**: No style={{ }} in JSX/Vue templates.\n PASS: styles are in CSS/SCSS/CSS-in-JS. FAIL: move to stylesheet or styled component.\n\n- [ ] **Rule 13 \u2014 Prop Limit**: Components accept at most 8 props.\n PASS: props are few and cohesive. FAIL: group related props into an object.\n\n- [ ] **Rule 14 \u2014 Prefer Composition**: Large components are split into sub-components.\n No \"god components\" handling layout + data + formatting + interaction.\n PASS: each component has one visual/logical role. FAIL: extract a sub-component.\n\n- [ ] **Rule 15 \u2014 No Direct DOM Access**: No document.querySelector / getElementById in components.\n PASS: refs are used (useRef, ref=). FAIL: replace with ref mechanism.\n\n- [ ] **Rule 16 \u2014 Data Fetching in Services/Hooks**: No fetch() or axios calls in component body.\n PASS: data fetching is in a custom hook or service. FAIL: extract to useXxx hook.\n\n- [ ] **Rule 17 \u2014 One Styling System**: File uses only one styling approach\n (Tailwind OR styled-components OR CSS modules \u2014 not all three).\n PASS: consistent styling. FAIL: standardize on one approach.\n\n- [ ] **Rule 18 \u2014 No Nested Ternaries in JSX**: JSX conditionals use if/else or variables, not nested ternaries.\n PASS: conditions are readable. FAIL: extract condition to a variable or early return.\n\n## Section 3: Architecture (Rules 19\u201325)\n\n- [ ] **Rule 19 \u2014 Single Source of Truth**: State is not duplicated across multiple stores or components.\n PASS: one authoritative source for each piece of state. FAIL: remove duplication.\n\n- [ ] **Rule 20 \u2014 UI/Logic Separation**: Business logic is not inside UI components.\n PASS: components call services/hooks; logic lives elsewhere. FAIL: extract to service.\n\n- [ ] **Rule 21 \u2014 Dependency Abstraction**: External APIs/SDKs are wrapped in adapter/service layers.\n PASS: swapping a library touches one file. FAIL: add an abstraction layer.\n\n- [ ] **Rule 22 \u2014 No Circular Imports**: Module dependency graph is a DAG (no cycles).\n PASS: import graph has no cycles. FAIL: restructure modules to remove the cycle.\n\n- [ ] **Rule 23 \u2014 Config in Dedicated Files**: Magic strings and environment-specific values are in config files.\n PASS: config is centralized. FAIL: extract to config.ts or .env.\n\n- [ ] **Rule 24 \u2014 Public API Coverage**: Every exported function has a corresponding test.\n PASS: public API is covered by tests. FAIL: write a test for the new export.\n\n- [ ] **Rule 25 \u2014 No God Objects**: Classes/modules are focused \u2014 no object that knows everything.\n PASS: objects have clear, narrow responsibilities. FAIL: split the god object.\n\n---\n\n## Quick Check Before Marking Done\n\n1. Run `check_code_quality` on modified files \u2014 fix HIGH severity issues.\n2. Run `validate_file` (Logic Guardian) \u2014 fix correctness bugs first.\n3. Verify rules 3, 4, 8 manually (naming and nesting are hard to auto-detect fully).\n4. For frontend work, verify rules 12, 15, 16 \u2014 these are the most common oversights.\n";
2
+ export declare const CODING_RULES: string;
@@ -1,4 +1,7 @@
1
- export const CODING_RULES = `# 25 Golden Rules — Code Quality Checklist
1
+ import { join } from "path";
2
+ import { homedir } from "os";
3
+ import { existsSync, readFileSync } from "fs";
4
+ export const ORIGINAL_CODING_RULES = `# 25 Golden Rules — Code Quality Checklist
2
5
 
3
6
  ## Section 1: General Quality (Rules 1–10)
4
7
 
@@ -95,3 +98,19 @@ export const CODING_RULES = `# 25 Golden Rules — Code Quality Checklist
95
98
  3. Verify rules 3, 4, 8 manually (naming and nesting are hard to auto-detect fully).
96
99
  4. For frontend work, verify rules 12, 15, 16 — these are the most common oversights.
97
100
  `;
101
+ // Opt-in: if a pre-compressed copy exists at ~/.lucid/compressed-prompts/coding-rules.txt
102
+ // (produced by `npm run compress-prompts`), serve that instead. Falls back to the
103
+ // original on any error so this is always safe.
104
+ function loadCompressed() {
105
+ try {
106
+ const p = join(homedir(), ".lucid", "compressed-prompts", "coding-rules.txt");
107
+ if (!existsSync(p))
108
+ return null;
109
+ const text = readFileSync(p, "utf-8").trim();
110
+ return text.length > 0 ? text : null;
111
+ }
112
+ catch {
113
+ return null;
114
+ }
115
+ }
116
+ export const CODING_RULES = loadCompressed() ?? ORIGINAL_CODING_RULES;