specmem-hardwicksoftware 3.7.35 → 3.7.36

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 (55) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +11 -15
  3. package/bin/specmem-console.cjs +839 -51
  4. package/claude-hooks/agent-chooser-hook.js +6 -6
  5. package/claude-hooks/agent-loading-hook.cjs +16 -16
  6. package/claude-hooks/agent-loading-hook.js +18 -18
  7. package/claude-hooks/agent-type-matcher.js +1 -1
  8. package/claude-hooks/background-completion-silencer.js +1 -1
  9. package/claude-hooks/file-claim-enforcer.cjs +37 -36
  10. package/claude-hooks/output-cleaner.cjs +1 -1
  11. package/claude-hooks/settings.json +27 -3
  12. package/claude-hooks/specmem-search-enforcer.cjs +2 -11
  13. package/claude-hooks/specmem-team-member-inject.js +1 -1
  14. package/claude-hooks/specmem-unified-hook.py +1 -1
  15. package/claude-hooks/subagent-loading-hook.cjs +1 -1
  16. package/claude-hooks/task-progress-hook.cjs +7 -7
  17. package/claude-hooks/task-progress-hook.js +3 -3
  18. package/claude-hooks/team-comms-enforcer.cjs +49 -47
  19. package/dist/claude-sessions/sessionParser.js +5 -0
  20. package/dist/codebase/codebaseIndexer.js +48 -17
  21. package/dist/codebase/exclusions.js +3 -4
  22. package/dist/codebase/index.js +4 -0
  23. package/dist/codebase/pdfExtractor.js +298 -0
  24. package/dist/dashboard/api/taskTeamMembers.js +2 -2
  25. package/dist/db/bigBrainMigrations.js +29 -0
  26. package/dist/hooks/hookManager.js +4 -4
  27. package/dist/hooks/teamFramingCli.js +1 -1
  28. package/dist/hooks/teamMemberPrepromptHook.js +5 -5
  29. package/dist/init/claudeConfigInjector.js +2 -2
  30. package/dist/mcp/compactionProxy.js +834 -186
  31. package/dist/mcp/compactionProxyDaemon.js +112 -37
  32. package/dist/mcp/contextVault.js +439 -0
  33. package/dist/mcp/embeddingServerManager.js +61 -1
  34. package/dist/mcp/mcpProtocolHandler.js +6 -1
  35. package/dist/mcp/miniCOTServerManager.js +82 -8
  36. package/dist/mcp/specMemServer.js +45 -10
  37. package/dist/mcp/toolRegistry.js +6 -0
  38. package/dist/startup/startupIndexing.js +14 -0
  39. package/dist/team-members/taskOrchestrator.js +3 -3
  40. package/dist/team-members/taskTeamMemberLogger.js +2 -2
  41. package/dist/tools/goofy/deployTeamMember.js +3 -3
  42. package/dist/tools/goofy/digInTheVault.js +81 -0
  43. package/dist/tools/goofy/stashTheGoods.js +56 -0
  44. package/dist/tools/teamMemberDeployer.js +2 -2
  45. package/dist/watcher/changeHandler.js +65 -8
  46. package/dist/watcher/changeQueue.js +20 -1
  47. package/embedding-sandbox/mini-cot-service.py +11 -13
  48. package/embedding-sandbox/pdf-text-extract.py +208 -0
  49. package/package.json +1 -1
  50. package/scripts/deploy-hooks.cjs +2 -2
  51. package/scripts/global-postinstall.cjs +2 -2
  52. package/scripts/specmem-init.cjs +130 -36
  53. package/specmem/model-config.json +6 -6
  54. package/specmem/supervisord.conf +1 -1
  55. package/svg-sections/readme-token-compaction.svg +246 -0
@@ -1,6 +1,6 @@
1
1
  ; ============================================
2
2
  ; SPECMEM BRAIN CONTAINER - DYNAMIC SUPERVISORD CONFIG
3
- ; Generated by specmem-init at 2026-02-26T20:34:50.062Z
3
+ ; Generated by specmem-init at 2026-03-02T00:36:22.804Z
4
4
  ; Thread counts from model-config.json resourcePool
5
5
  ; ============================================
6
6
 
@@ -0,0 +1,246 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 1020" width="800" height="1020">
2
+ <defs>
3
+ <linearGradient id="bgGrad" x1="0%" y1="0%" x2="100%" y2="100%">
4
+ <stop offset="0%" style="stop-color:#0d1117"/>
5
+ <stop offset="100%" style="stop-color:#161b22"/>
6
+ </linearGradient>
7
+ <linearGradient id="cardGrad" x1="0%" y1="0%" x2="100%" y2="100%">
8
+ <stop offset="0%" style="stop-color:#1c2128;stop-opacity:0.9"/>
9
+ <stop offset="100%" style="stop-color:#21262d;stop-opacity:0.85"/>
10
+ </linearGradient>
11
+ <linearGradient id="titleGrad" x1="0%" y1="0%" x2="100%" y2="0%">
12
+ <stop offset="0%" style="stop-color:#00bfff"/>
13
+ <stop offset="50%" style="stop-color:#a855f7"/>
14
+ <stop offset="100%" style="stop-color:#00bfff"/>
15
+ </linearGradient>
16
+ <linearGradient id="cyanPurple" x1="0%" y1="0%" x2="100%" y2="0%">
17
+ <stop offset="0%" style="stop-color:#00bfff"/>
18
+ <stop offset="100%" style="stop-color:#a855f7"/>
19
+ </linearGradient>
20
+ <linearGradient id="greenGrad" x1="0%" y1="0%" x2="100%" y2="0%">
21
+ <stop offset="0%" style="stop-color:#22c55e"/>
22
+ <stop offset="100%" style="stop-color:#4ade80"/>
23
+ </linearGradient>
24
+ <linearGradient id="orangeGrad" x1="0%" y1="0%" x2="100%" y2="0%">
25
+ <stop offset="0%" style="stop-color:#f59e0b"/>
26
+ <stop offset="100%" style="stop-color:#f78534"/>
27
+ </linearGradient>
28
+ <filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
29
+ <feGaussianBlur in="SourceAlpha" stdDeviation="3" result="blur"/>
30
+ <feFlood flood-color="#00bfff" flood-opacity="0.3"/>
31
+ <feComposite in2="blur" operator="in"/>
32
+ <feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
33
+ </filter>
34
+ <filter id="glowGreen" x="-20%" y="-20%" width="140%" height="140%">
35
+ <feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>
36
+ <feFlood flood-color="#22c55e" flood-opacity="0.4"/>
37
+ <feComposite in2="blur" operator="in"/>
38
+ <feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
39
+ </filter>
40
+ </defs>
41
+
42
+ <!-- Background -->
43
+ <rect width="800" height="1020" rx="16" ry="16" fill="url(#bgGrad)"/>
44
+ <rect width="800" height="1020" rx="16" ry="16" fill="none" stroke="url(#cyanPurple)" stroke-width="1" stroke-opacity="0.2"/>
45
+
46
+ <!-- Title Section -->
47
+ <text x="400" y="36" text-anchor="middle" font-family="system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif" font-size="20" font-weight="700" fill="url(#titleGrad)">Token Compaction Pipeline</text>
48
+ <text x="400" y="56" text-anchor="middle" font-family="system-ui, sans-serif" font-size="11" fill="#6e7681">5-layer MITM proxy between Claude Code and Anthropic API. Every request gets optimized.</text>
49
+
50
+ <!-- Big stat banner -->
51
+ <rect x="40" y="72" width="720" height="70" rx="12" fill="url(#cardGrad)" stroke="#22c55e" stroke-width="1.5" filter="url(#glowGreen)"/>
52
+ <text x="200" y="103" text-anchor="middle" font-family="system-ui, sans-serif" font-size="36" font-weight="800" fill="#22c55e">~60%</text>
53
+ <text x="200" y="125" text-anchor="middle" font-family="system-ui, sans-serif" font-size="11" fill="#6e7681">input token reduction</text>
54
+ <text x="400" y="103" text-anchor="middle" font-family="system-ui, sans-serif" font-size="36" font-weight="800" fill="#00bfff">5</text>
55
+ <text x="400" y="125" text-anchor="middle" font-family="system-ui, sans-serif" font-size="11" fill="#6e7681">compression layers</text>
56
+ <text x="600" y="103" text-anchor="middle" font-family="system-ui, sans-serif" font-size="36" font-weight="800" fill="#a855f7">0ms</text>
57
+ <text x="600" y="125" text-anchor="middle" font-family="system-ui, sans-serif" font-size="11" fill="#6e7681">added latency (async)</text>
58
+
59
+ <!-- Pipeline flow label -->
60
+ <text x="400" y="170" text-anchor="middle" font-family="system-ui, sans-serif" font-size="14" font-weight="600" fill="#e6edf3">Request Flow: Claude Code &#x2192; Compaction Proxy &#x2192; Anthropic API</text>
61
+
62
+ <!-- ═══════════════════════════════════════════════════════ -->
63
+ <!-- LAYER 1: Context Vault (y=188, h=126) -->
64
+ <!-- ═══════════════════════════════════════════════════════ -->
65
+ <g transform="translate(30, 188)">
66
+ <rect width="740" height="126" rx="12" fill="url(#cardGrad)" stroke="#22c55e" stroke-width="1.5"/>
67
+ <rect width="740" height="3" rx="1.5" fill="url(#greenGrad)"/>
68
+
69
+ <circle cx="36" cy="30" r="14" fill="none" stroke="#22c55e" stroke-width="1.5" stroke-opacity="0.7"/>
70
+ <text x="36" y="35" text-anchor="middle" font-family="system-ui, sans-serif" font-size="13" font-weight="700" fill="#22c55e">1</text>
71
+
72
+ <text x="60" y="34" font-family="system-ui, sans-serif" font-size="14" font-weight="700" fill="#4ade80">&#x1F3E6; Context Vault</text>
73
+ <rect x="210" y="20" width="90" height="20" rx="10" fill="#22c55e" fill-opacity="0.15" stroke="#22c55e" stroke-width="0.8" stroke-opacity="0.4"/>
74
+ <text x="255" y="34" text-anchor="middle" font-family="'SF Mono', 'Fira Code', Consolas, monospace" font-size="10" font-weight="600" fill="#4ade80">99% savings</text>
75
+
76
+ <text font-family="system-ui, sans-serif" font-size="11" fill="#8b949e">
77
+ <tspan x="24" y="58">Tool results larger than 5KB are auto-stashed to PostgreSQL with full-text indexing (tsvector).</tspan>
78
+ <tspan x="24" dy="15">Claude receives a compact receipt (~800 bytes) with preview, vocabulary, and retrieval commands.</tspan>
79
+ <tspan x="24" dy="15">On-demand retrieval via BM25-ranked search. 24h TTL with automatic expiry.</tspan>
80
+ </text>
81
+
82
+ <rect x="24" y="106" width="80" height="14" rx="3" fill="#ef4444" fill-opacity="0.2" stroke="#ef4444" stroke-width="0.8" stroke-opacity="0.4"/>
83
+ <text x="64" y="117" text-anchor="middle" font-family="'SF Mono', monospace" font-size="8" fill="#f87171">315KB result</text>
84
+ <text x="118" y="117" font-family="system-ui, sans-serif" font-size="11" fill="#484f58">&#x2192;</text>
85
+ <rect x="138" y="106" width="68" height="14" rx="3" fill="#22c55e" fill-opacity="0.2" stroke="#22c55e" stroke-width="0.8" stroke-opacity="0.4"/>
86
+ <text x="172" y="117" text-anchor="middle" font-family="'SF Mono', monospace" font-size="8" fill="#4ade80">800B receipt</text>
87
+ <text x="225" y="117" font-family="'SF Mono', monospace" font-size="8" fill="#484f58">stash_the_goods() / dig_in_the_vault()</text>
88
+ </g>
89
+
90
+ <!-- Connector 1→2 -->
91
+ <line x1="66" y1="314" x2="66" y2="330" stroke="#30363d" stroke-width="2" stroke-dasharray="3,3"/>
92
+ <polygon points="62,328 66,336 70,328" fill="#30363d"/>
93
+
94
+ <!-- ═══════════════════════════════════════════════════════ -->
95
+ <!-- LAYER 2: Steno + YCC (y=336, h=180) -->
96
+ <!-- ═══════════════════════════════════════════════════════ -->
97
+ <g transform="translate(30, 336)">
98
+ <rect width="740" height="180" rx="12" fill="url(#cardGrad)" stroke="#00bfff" stroke-width="1.5"/>
99
+ <rect width="740" height="3" rx="1.5" fill="#00bfff"/>
100
+
101
+ <circle cx="36" cy="30" r="14" fill="none" stroke="#00bfff" stroke-width="1.5" stroke-opacity="0.7"/>
102
+ <text x="36" y="35" text-anchor="middle" font-family="system-ui, sans-serif" font-size="13" font-weight="700" fill="#00bfff">2</text>
103
+
104
+ <text x="60" y="34" font-family="system-ui, sans-serif" font-size="14" font-weight="700" fill="#00bfff">&#x1F916; Steno Compression</text>
105
+ <rect x="240" y="20" width="90" height="20" rx="10" fill="#00bfff" fill-opacity="0.12" stroke="#00bfff" stroke-width="0.8" stroke-opacity="0.4"/>
106
+ <text x="285" y="34" text-anchor="middle" font-family="'SF Mono', 'Fira Code', Consolas, monospace" font-size="10" font-weight="600" fill="#00bfff">~40% savings</text>
107
+
108
+ <text font-family="system-ui, sans-serif" font-size="11" fill="#8b949e">
109
+ <tspan x="24" y="58">Strips ~80 filler words (the, a, is, are, was, were, of, to, in, for ...) that carry minimal semantic</tspan>
110
+ <tspan x="24" dy="15">meaning. Applies ~100 programming abbreviations: function&#x2192;fn, configuration&#x2192;cfg, database&#x2192;db,</tspan>
111
+ <tspan x="24" dy="15">implementation&#x2192;impl, authentication&#x2192;auth, environment&#x2192;env, repository&#x2192;repo, and more.</tspan>
112
+ </text>
113
+
114
+ <!-- Before/after example -->
115
+ <rect x="24" y="104" width="340" height="14" rx="3" fill="#1a1f26" stroke="#21262d" stroke-width="0.8"/>
116
+ <text x="30" y="115" font-family="'SF Mono', monospace" font-size="8" fill="#6e7681">"the function configuration is required"</text>
117
+ <text x="372" y="115" font-family="system-ui, sans-serif" font-size="11" fill="#484f58">&#x2192;</text>
118
+ <rect x="390" y="104" width="130" height="14" rx="3" fill="#00bfff" fill-opacity="0.1" stroke="#00bfff" stroke-width="0.8" stroke-opacity="0.3"/>
119
+ <text x="396" y="115" font-family="'SF Mono', monospace" font-size="8" fill="#58a6ff">"fn cfg reqd"</text>
120
+ <text x="540" y="115" font-family="system-ui, sans-serif" font-size="8" fill="#484f58">KEEP_WORDS: not, no, never, must, all</text>
121
+
122
+ <!-- ── YCC Sub-layer ── -->
123
+ <line x1="24" y1="128" x2="716" y2="128" stroke="#30363d" stroke-width="0.8" stroke-dasharray="4,3"/>
124
+
125
+ <!-- YC Logo -->
126
+ <rect x="24" y="137" width="36" height="36" rx="8" fill="#a855f7" fill-opacity="0.2" stroke="#a855f7" stroke-width="1.5" stroke-opacity="0.6"/>
127
+ <text x="42" y="161" text-anchor="middle" font-family="system-ui, sans-serif" font-size="16" font-weight="900" fill="#c084fc">YC</text>
128
+
129
+ <!-- Yung Cracka Compress title + badge -->
130
+ <text x="72" y="152" font-family="system-ui, sans-serif" font-size="13" font-weight="700" fill="#c084fc">&#x1F977;&#x1F3FB; Yung Cracka Compress</text>
131
+ <rect x="260" y="140" width="68" height="18" rx="9" fill="#a855f7" fill-opacity="0.12" stroke="#a855f7" stroke-width="0.8" stroke-opacity="0.4"/>
132
+ <text x="294" y="153" text-anchor="middle" font-family="'SF Mono', monospace" font-size="9" font-weight="600" fill="#c084fc">opt-in</text>
133
+ <text x="340" y="153" font-family="'SF Mono', monospace" font-size="8" fill="#484f58">SLANG_ENABLED: false</text>
134
+
135
+ <!-- YCC description -->
136
+ <text x="72" y="172" font-family="system-ui, sans-serif" font-size="10" fill="#6e7681">DMV x Florida slang layer. 90+ entries LLMs already understand. definitely&#x2192;def, probably&#x2192;prolly, through&#x2192;thru</text>
137
+ </g>
138
+
139
+ <!-- Connector 2→3 -->
140
+ <line x1="66" y1="516" x2="66" y2="532" stroke="#30363d" stroke-width="2" stroke-dasharray="3,3"/>
141
+ <polygon points="62,530 66,538 70,530" fill="#30363d"/>
142
+
143
+ <!-- ═══════════════════════════════════════════════════════ -->
144
+ <!-- LAYER 3: Neural MT (y=538, h=142) -->
145
+ <!-- ═══════════════════════════════════════════════════════ -->
146
+ <g transform="translate(30, 538)">
147
+ <rect width="740" height="142" rx="12" fill="url(#cardGrad)" stroke="#a855f7" stroke-width="1.5"/>
148
+ <rect width="740" height="3" rx="1.5" fill="#a855f7"/>
149
+
150
+ <circle cx="36" cy="30" r="14" fill="none" stroke="#a855f7" stroke-width="1.5" stroke-opacity="0.7"/>
151
+ <text x="36" y="35" text-anchor="middle" font-family="system-ui, sans-serif" font-size="13" font-weight="700" fill="#a855f7">3</text>
152
+
153
+ <text x="60" y="34" font-family="system-ui, sans-serif" font-size="14" font-weight="700" fill="#a855f7">&#x1F9D1;&#x200D;&#x1F4BB; Neural MT (EN&#x2192;ZH)</text>
154
+ <rect x="270" y="20" width="105" height="20" rx="10" fill="#a855f7" fill-opacity="0.12" stroke="#a855f7" stroke-width="0.8" stroke-opacity="0.4"/>
155
+ <text x="322" y="34" text-anchor="middle" font-family="'SF Mono', 'Fira Code', Consolas, monospace" font-size="10" font-weight="600" fill="#a855f7">+30% on top</text>
156
+
157
+ <text font-family="system-ui, sans-serif" font-size="11" fill="#8b949e">
158
+ <tspan x="24" y="58">Steno'd tool_result text is translated EN&#x2192;ZH via local Argos Translate (air-gapped, no API calls).</tspan>
159
+ <tspan x="24" dy="15">Loop-back verification: ZH&#x2192;EN back-translation compared via LCS Dice + Jaccard (threshold 0.65).</tspan>
160
+ <tspan x="24" dy="15">Failed verifications fall back to steno-only. Passthrough vocab for untranslatable tech terms (webpack,</tspan>
161
+ <tspan x="24" dy="15">nginx, docker, etc). Word-level TM cache grows over time &#x2014; repeated words skip the socket entirely.</tspan>
162
+ </text>
163
+
164
+ <!-- Verification flow diagram -->
165
+ <rect x="24" y="120" width="58" height="14" rx="3" fill="#00bfff" fill-opacity="0.1" stroke="#00bfff" stroke-width="0.8" stroke-opacity="0.3"/>
166
+ <text x="53" y="131" text-anchor="middle" font-family="'SF Mono', monospace" font-size="8" fill="#58a6ff">steno'd</text>
167
+ <text x="90" y="131" font-family="system-ui, sans-serif" font-size="9" fill="#484f58">&#x2192;</text>
168
+ <rect x="102" y="120" width="34" height="14" rx="3" fill="#a855f7" fill-opacity="0.15" stroke="#a855f7" stroke-width="0.8" stroke-opacity="0.4"/>
169
+ <text x="119" y="131" text-anchor="middle" font-family="'SF Mono', monospace" font-size="8" fill="#c084fc">ZH</text>
170
+ <text x="144" y="131" font-family="system-ui, sans-serif" font-size="9" fill="#484f58">&#x2192;</text>
171
+ <rect x="156" y="120" width="64" height="14" rx="3" fill="#f59e0b" fill-opacity="0.12" stroke="#f59e0b" stroke-width="0.8" stroke-opacity="0.3"/>
172
+ <text x="188" y="131" text-anchor="middle" font-family="'SF Mono', monospace" font-size="8" fill="#fbbf24">back-EN</text>
173
+ <text x="228" y="131" font-family="system-ui, sans-serif" font-size="9" fill="#484f58">&#x2192;</text>
174
+ <rect x="242" y="120" width="48" height="14" rx="3" fill="#22c55e" fill-opacity="0.15" stroke="#22c55e" stroke-width="0.8" stroke-opacity="0.4"/>
175
+ <text x="266" y="131" text-anchor="middle" font-family="'SF Mono', monospace" font-size="8" fill="#4ade80">&gt;=0.65</text>
176
+ <text x="298" y="131" font-family="system-ui, sans-serif" font-size="9" fill="#4ade80">use ZH</text>
177
+ <text x="350" y="131" font-family="system-ui, sans-serif" font-size="9" fill="#484f58">|</text>
178
+ <rect x="364" y="120" width="48" height="14" rx="3" fill="#ef4444" fill-opacity="0.15" stroke="#ef4444" stroke-width="0.8" stroke-opacity="0.4"/>
179
+ <text x="388" y="131" text-anchor="middle" font-family="'SF Mono', monospace" font-size="8" fill="#f87171">&lt;0.65</text>
180
+ <text x="420" y="131" font-family="system-ui, sans-serif" font-size="9" fill="#f87171">keep steno</text>
181
+ <text x="490" y="131" font-family="system-ui, sans-serif" font-size="8" fill="#484f58">TM cache + synonym learning from failures</text>
182
+ </g>
183
+
184
+ <!-- Connector 3→4 -->
185
+ <line x1="66" y1="680" x2="66" y2="696" stroke="#30363d" stroke-width="2" stroke-dasharray="3,3"/>
186
+ <polygon points="62,694 66,702 70,694" fill="#30363d"/>
187
+
188
+ <!-- ═══════════════════════════════════════════════════════ -->
189
+ <!-- LAYER 4: Old-Message Stripping (y=702, h=114) -->
190
+ <!-- ═══════════════════════════════════════════════════════ -->
191
+ <g transform="translate(30, 702)">
192
+ <rect width="740" height="114" rx="12" fill="url(#cardGrad)" stroke="#f59e0b" stroke-width="1.5"/>
193
+ <rect width="740" height="3" rx="1.5" fill="url(#orangeGrad)"/>
194
+
195
+ <circle cx="36" cy="30" r="14" fill="none" stroke="#f59e0b" stroke-width="1.5" stroke-opacity="0.7"/>
196
+ <text x="36" y="35" text-anchor="middle" font-family="system-ui, sans-serif" font-size="13" font-weight="700" fill="#f59e0b">4</text>
197
+
198
+ <text x="60" y="34" font-family="system-ui, sans-serif" font-size="14" font-weight="700" fill="#fbbf24">&#x1F5D1;&#xFE0F; Old-Message Stripping</text>
199
+ <rect x="272" y="20" width="100" height="20" rx="10" fill="#f59e0b" fill-opacity="0.12" stroke="#f59e0b" stroke-width="0.8" stroke-opacity="0.4"/>
200
+ <text x="322" y="34" text-anchor="middle" font-family="'SF Mono', 'Fira Code', Consolas, monospace" font-size="10" font-weight="600" fill="#fbbf24">85%+ savings</text>
201
+
202
+ <text font-family="system-ui, sans-serif" font-size="11" fill="#8b949e">
203
+ <tspan x="24" y="58">tool_result content from messages outside the recent window (last 3 messages preserved) gets</tspan>
204
+ <tspan x="24" dy="15">replaced with a 200-char preview summary. Stale file reads, grep outputs, and old assistant text</tspan>
205
+ <tspan x="24" dy="15">blocks are trimmed to first-line anchors. SpecMem hook injections (SM-* markers) also stripped.</tspan>
206
+ </text>
207
+
208
+ <text x="24" y="106" font-family="'SF Mono', monospace" font-size="8" fill="#484f58">threshold: 100 chars | preview: 200 chars | preserves: tool_use_id, is_error, cache_control</text>
209
+ </g>
210
+
211
+ <!-- Connector 4→5 -->
212
+ <line x1="66" y1="816" x2="66" y2="832" stroke="#30363d" stroke-width="2" stroke-dasharray="3,3"/>
213
+ <polygon points="62,830 66,838 70,830" fill="#30363d"/>
214
+
215
+ <!-- ═══════════════════════════════════════════════════════ -->
216
+ <!-- LAYER 5: System-Reminder Stripping (y=838, h=114) -->
217
+ <!-- ═══════════════════════════════════════════════════════ -->
218
+ <g transform="translate(30, 838)">
219
+ <rect width="740" height="114" rx="12" fill="url(#cardGrad)" stroke="#ef4444" stroke-width="1.5"/>
220
+ <rect width="740" height="3" rx="1.5" fill="#ef4444"/>
221
+
222
+ <circle cx="36" cy="30" r="14" fill="none" stroke="#ef4444" stroke-width="1.5" stroke-opacity="0.7"/>
223
+ <text x="36" y="35" text-anchor="middle" font-family="system-ui, sans-serif" font-size="13" font-weight="700" fill="#ef4444">5</text>
224
+
225
+ <text x="60" y="34" font-family="system-ui, sans-serif" font-size="14" font-weight="700" fill="#f87171">&#x1F9F9; System-Reminder Stripping</text>
226
+ <rect x="298" y="20" width="100" height="20" rx="10" fill="#ef4444" fill-opacity="0.12" stroke="#ef4444" stroke-width="0.8" stroke-opacity="0.4"/>
227
+ <text x="348" y="34" text-anchor="middle" font-family="'SF Mono', 'Fira Code', Consolas, monospace" font-size="10" font-weight="600" fill="#f87171">variable</text>
228
+
229
+ <text font-family="system-ui, sans-serif" font-size="11" fill="#8b949e">
230
+ <tspan x="24" y="58">Duplicate &lt;system-reminder&gt; tags stripped from messages. First instance is preserved (sets up</tspan>
231
+ <tspan x="24" dy="15">context/style), all subsequent identical reminders removed. System prompt dedup tracks content</tspan>
232
+ <tspan x="24" dy="15">hash &#x2014; same prompt across requests is sent once, then stripped on repeat.</tspan>
233
+ </text>
234
+
235
+ <text x="24" y="106" font-family="'SF Mono', monospace" font-size="8" fill="#484f58">regex: /&lt;system-reminder&gt;[\s\S]*?&lt;\/system-reminder&gt;/g | keeps first, strips rest</text>
236
+ </g>
237
+
238
+ <!-- ═══════════════════════════════════════════════════════ -->
239
+ <!-- Result bar (y=970, h=44) -->
240
+ <!-- ═══════════════════════════════════════════════════════ -->
241
+ <rect x="30" y="968" width="740" height="44" rx="12" fill="#22c55e" fill-opacity="0.08" stroke="#22c55e" stroke-width="1.5" stroke-opacity="0.4"/>
242
+ <circle cx="66" cy="990" r="12" fill="none" stroke="#22c55e" stroke-width="2"/>
243
+ <path d="M60 990 L64 995 L74 984" fill="none" stroke="#4ade80" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
244
+ <text x="88" y="986" font-family="system-ui, sans-serif" font-size="13" font-weight="600" fill="#4ade80">Combined: ~57-60% total input token reduction.</text>
245
+ <text x="88" y="1003" font-family="system-ui, sans-serif" font-size="10" fill="#6e7681">All layers run on every request. Falls back gracefully &#x2014; proxy never breaks the API call. Toggle via /config.</text>
246
+ </svg>