@softspark/ai-toolkit 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,742 @@
1
+ ---
2
+ title: "Plan: Offline-First SLM Profile — Lightweight Mode for Local Models"
3
+ category: planning
4
+ service: ai-toolkit
5
+ tags:
6
+ - offline
7
+ - slm
8
+ - small-language-models
9
+ - ollama
10
+ - lm-studio
11
+ - profile
12
+ - context-optimization
13
+ - privacy
14
+ doc_type: plan
15
+ status: proposed
16
+ created: "2026-04-10"
17
+ last_updated: "2026-04-10"
18
+ completion: "0%"
19
+ description: "Lightweight profile for ai-toolkit optimized for Small Language Models (SLMs) running locally via Ollama, LM Studio, or similar. Compiles a minimal instruction set that fits within 4K-8K system prompt budgets while preserving critical safety guardrails. Targets air-gapped, privacy-first, and cost-sensitive development workflows."
20
+ ---
21
+
22
+ # Plan: Offline-First SLM Profile — Lightweight Mode for Local Models
23
+
24
+ **Status:** Proposed
25
+ **Completion:** 0%
26
+ **Created:** 2026-04-10
27
+ **Origin:** Enterprise IP security requirements (air-gapped environments), cost-sensitive solo developers, and the growing adoption of local models (Ollama, LM Studio, llamafile). Current toolkit emits 20K+ token system prompts that exceed SLM context windows and degrade small model performance.
28
+ **Estimated Effort:** 4-5 weeks (1 person)
29
+
30
+ ---
31
+
32
+ ## 1. Objective
33
+
34
+ Create a `--profile offline-slm` install profile and a `scripts/compile_slm.py` compiler that produces a minimal, high-signal instruction set optimized for Small Language Models (8B-32B parameters). The compiled output preserves critical safety guardrails while stripping agent orchestration, multi-agent coordination, and complex skill routing that SLMs cannot handle.
35
+
36
+ **Key design principles:**
37
+ - **Token budget** — compiled output fits within 4K tokens (system prompt), with optional 8K mode for larger SLMs
38
+ - **Safety-preserved** — Constitution Articles I-V always included (non-negotiable)
39
+ - **Single-agent focus** — no multi-agent orchestration, no /swarm, no /teams
40
+ - **Deterministic compilation** — same input → same output, no LLM involved in compilation
41
+ - **Model-aware** — detects model size from Ollama API or manual flag and adjusts verbosity
42
+ - **Platform-agnostic** — outputs plain markdown consumable by any local inference engine
43
+ - **Hooks stripped** — SLM providers don't support lifecycle hooks; rules compile into system prompt
44
+
45
+ ---
46
+
47
+ ## 1a. Functional Requirements
48
+
49
+ | ID | Requirement | Priority | Success Metric |
50
+ |----|-------------|----------|----------------|
51
+ | FR1 | Token counter (stdlib-only, ±10% accuracy target) | Must | Conservative estimate, no external deps |
52
+ | FR2 | Component parser + scorer with safety-priority ranking | Must | Constitution=1.0, all components scored |
53
+ | FR3 | Compression engine with 4 levels (ultra-light, light, standard, extended) | Must | Each level strips progressively less |
54
+ | FR4 | Budget packer (greedy knapsack by score/size ratio) | Must | Output ≤ budget × 0.95 in all cases |
55
+ | FR5 | Markdown emitter with safety-first structure | Must | Constitution always first in output |
56
+ | FR6 | `--profile offline-slm` install integration | Must | `install.py` + `manifest.json` updated |
57
+ | FR7 | `compile-slm` CLI command with flags | Must | `--budget`, `--model-size`, `--persona`, `--lang`, `--output`, `--format`, `--dry-run` |
58
+ | FR8 | Constitution always included (non-negotiable) | Must | Compilation fails if constitution exceeds budget alone |
59
+ | FR9 | Model size detection from Ollama API | Should | Auto-detect with graceful fallback to `14b` |
60
+ | FR10 | Persona-aware compilation (boost relevant skills) | Should | Persona skills ranked higher |
61
+ | FR11 | Language-aware compilation (include matching rules only) | Should | Non-matching language rules excluded |
62
+ | FR12 | Integration guides for 4 platforms (Ollama, LM Studio, Aider, Continue.dev) | Should | Step-by-step setup per platform |
63
+ | FR13 | Compile quality validator (post-compilation checks) | Should | FAIL on missing constitution, budget exceeded |
64
+ | FR14 | 4 output formats (raw markdown, Ollama Modelfile, JSON string, Aider-compatible) | Should | Each format usable by target tool |
65
+ | FR15 | `--dry-run` output showing included components + token counts | Should | Table: component, score, tokens, included? |
66
+
67
+ ---
68
+
69
+ ## 2. Architecture Overview
70
+
71
+ ```
72
+ ai-toolkit install --profile offline-slm [--model-size 8b|14b|32b|70b]
73
+ ai-toolkit compile-slm [--budget 4096] [--persona backend-lead] [--lang typescript]
74
+
75
+ ┌──────────────────────────────────────────────────────────┐
76
+ │ offline-slm Profile │
77
+ │ │
78
+ │ Compiler: scripts/compile_slm.py │
79
+ │ Input: full toolkit (agents, skills, rules, constitution)│
80
+ │ Output: single compiled .md file for system prompt │
81
+ │ │
82
+ │ Token Budget Tiers: │
83
+ │ ultra-light (2K) — safety + persona only │
84
+ │ light (4K) — safety + persona + top skills + rules │
85
+ │ standard (8K) — safety + persona + full skills + rules │
86
+ │ extended (16K) — near-full toolkit (for 32B+ models) │
87
+ │ │
88
+ │ Output Files: │
89
+ │ ~/.ai-toolkit/compiled/slm-system-prompt.md │
90
+ │ ~/.ai-toolkit/compiled/slm-skills-reference.md │
91
+ │ CLAUDE.md (or equivalent) — auto-generated │
92
+ │ │
93
+ │ Integration Targets: │
94
+ │ Ollama (modelfile SYSTEM directive) │
95
+ │ LM Studio (system prompt field) │
96
+ │ llamafile (--system-prompt flag) │
97
+ │ Open WebUI (system prompt setting) │
98
+ │ Aider (--system-prompt-file flag) │
99
+ │ Continue.dev (system prompt in config) │
100
+ └──────────────────────────────────────────────────────────┘
101
+ ```
102
+
103
+ ### Compilation Pipeline
104
+
105
+ ```
106
+ Full Toolkit (20K+ tokens)
107
+
108
+
109
+ ┌─────────────────┐
110
+ │ 1. Parse Phase │ Read all agents, skills, rules, constitution
111
+ └────────┬────────┘
112
+
113
+ ┌─────────────────┐
114
+ │ 2. Rank Phase │ Score components by: safety criticality × usage frequency × persona relevance
115
+ └────────┬────────┘
116
+
117
+ ┌─────────────────┐
118
+ │ 3. Compress Phase│ Strip: examples, rationalization tables, related skills, verbose headers
119
+ └────────┬────────┘
120
+
121
+ ┌─────────────────┐
122
+ │ 4. Budget Phase │ Pack highest-scoring components until token budget reached
123
+ └────────┬────────┘
124
+
125
+ ┌─────────────────┐
126
+ │ 5. Emit Phase │ Write compiled .md + integration instructions
127
+ └─────────────────┘
128
+ ```
129
+
130
+ ---
131
+
132
+ ## 3. Progress Tracking
133
+
134
+ | # | Feature | Priority | Status | Est. Time | Notes |
135
+ |---|---------|----------|--------|-----------|-------|
136
+ | 1.1 | Token counter (tiktoken-free, word-based estimator) | P0 | Proposed | 0.5d | ~0.75 tokens/word heuristic (stdlib only) |
137
+ | 1.2 | Component parser + scorer | P0 | Proposed | 2d | Parse frontmatter, score by criticality/frequency/persona |
138
+ | 1.3 | Compression engine | P0 | Proposed | 2d | Strip examples, rationalization tables, headers |
139
+ | 1.4 | Budget packer | P0 | Proposed | 1d | Greedy knapsack by score/size ratio |
140
+ | 1.5 | Emitter (markdown output) | P0 | Proposed | 1d | Clean compiled .md file |
141
+ | 2.1 | Profile integration (`--profile offline-slm`) | P0 | Proposed | 1.5d | Install.py + manifest.json + state.json |
142
+ | 2.2 | CLI command (`ai-toolkit compile-slm`) | P0 | Proposed | 1d | Standalone compilation with flags |
143
+ | 2.3 | Model size detection (Ollama API) | P1 | Proposed | 1d | Auto-detect model params from `ollama list` |
144
+ | 2.4 | Persona-aware compilation | P1 | Proposed | 1.5d | Boost persona-relevant skills in ranking |
145
+ | 2.5 | Language-aware compilation | P1 | Proposed | 1d | Include only matching language rules |
146
+ | 3.1 | Integration guides (Ollama, LM Studio, Aider, Continue) | P1 | Proposed | 1.5d | Step-by-step per platform |
147
+ | 3.2 | Compile quality validator | P1 | Proposed | 1d | Verify output covers constitution, fits budget |
148
+ | 3.3 | Tests | P1 | Proposed | 3d | Unit: compilation determinism, budget compliance, 4 compression levels × 4 output formats, constitution guard. Integration: `compile-slm --model-size 8b`, verify output fits 2048 tokens + constitution present end-to-end. Target: 40+ tests |
149
+ | 3.4 | Documentation | P1 | Proposed | 2.5d | All 9 docs per CLAUDE.md: README, CLAUDE.md, ARCHITECTURE.md, package.json, llms.txt, llms-full.txt, AGENTS.md, skills-catalog.md, architecture-overview.md + integration guide |
150
+
151
+ **Phasing:**
152
+ - **Phase 1 (week 1-2):** Compiler — parser, scorer, compressor, packer, emitter
153
+ - **Phase 2 (week 2-3):** Integration — profile, CLI, model detection, persona/language awareness
154
+ - **Phase 3 (week 3-4):** Polish — integration guides, validator, tests, documentation
155
+
156
+ > **Demand validation gate:** Ship Phase 1 + basic Phase 2 (compiler + profile + CLI with `--budget` and `--model-size` flags) as MVP. Test with 3 real models (8B, 14B, 32B). Only build persona/language-aware compilation and platform-specific integration guides if MVP validation confirms output quality.
157
+
158
+ ---
159
+
160
+ ## 4. Dependency Graph
161
+
162
+ ```
163
+ Phase 1: Compiler (week 1-2)
164
+ ============================
165
+ Token counter (1.1) ────┐
166
+ ├──► Compression engine (1.3) ──► Budget packer (1.4) ──► Emitter (1.5)
167
+ Component parser (1.2) ──┘
168
+
169
+ Phase 2: Integration (week 2-3)
170
+ ================================
171
+ Profile integration (2.1) ──┐
172
+ ├──► CLI command (2.2)
173
+ Model detection (2.3) ──────┤
174
+ Persona-aware (2.4) ────────┤
175
+ Language-aware (2.5) ────────┘
176
+
177
+ Phase 3: Polish (week 3-4)
178
+ ===========================
179
+ ├──► Integration guides (3.1)
180
+ ├──► Compile validator (3.2)
181
+ └──► Tests + docs (3.3, 3.4)
182
+ ```
183
+
184
+ ---
185
+
186
+ ## 5. Detailed Implementation
187
+
188
+ ### Phase 1: Compiler Engine (week 1-2)
189
+
190
+ #### 1.1 Token Counter
191
+
192
+ **Stdlib-only token estimation** — no tiktoken, no external dependencies.
193
+
194
+ ```python
195
+ def estimate_tokens(text: str) -> int:
196
+ """Estimate token count from text without external dependencies.
197
+
198
+ Uses two heuristics and returns the higher (conservative) estimate:
199
+ 1. Word-based: ~0.75 tokens/word for English prose
200
+ 2. Char-based: ~1 token per 4 chars (more accurate for code-heavy content)
201
+
202
+ Accuracy target: ±10% vs tiktoken cl100k_base. To be validated on 50 toolkit files before shipping.
203
+ """
204
+ word_est = int(len(text.split()) * 0.75)
205
+ char_est = len(text) // 4
206
+ # Code blocks have higher token density — adjust
207
+ code_blocks = text.count('```')
208
+ code_penalty = code_blocks * 15
209
+ return max(word_est, char_est) + code_penalty
210
+ ```
211
+
212
+ **Why not tiktoken:** tiktoken requires a C extension and network download of the BPE file. This violates the stdlib-only constraint and fails in air-gapped environments (which is literally the target audience for this feature).
213
+
214
+ **Accuracy target:** ±10% vs tiktoken cl100k_base. Using `max(word, char)` gives a conservative estimate. We pack to budget × 0.95 (5% safety margin) to absorb estimation error.
215
+
216
+ ---
217
+
218
+ #### 1.2 Component Parser + Scorer
219
+
220
+ **Parse all toolkit components into a unified scoring table:**
221
+
222
+ ```python
223
+ @dataclass
224
+ class Component:
225
+ name: str
226
+ type: str # 'constitution', 'agent', 'skill', 'rule', 'hook-equivalent'
227
+ source_file: str
228
+ full_text: str
229
+ compressed_text: str # after stripping (populated by compressor)
230
+ tokens_full: int
231
+ tokens_compressed: int
232
+ score: float # 0.0 - 1.0
233
+
234
+ # Scoring factors
235
+ safety_criticality: float # 0.0-1.0 (constitution=1.0, guard hooks=0.9)
236
+ usage_frequency: float # 0.0-1.0 (from stats.json, normalized)
237
+ persona_relevance: float # 0.0-1.0 (match against active persona)
238
+ language_relevance: float # 0.0-1.0 (match against project language)
239
+ ```
240
+
241
+ **Scoring formula:**
242
+ ```python
243
+ score = (
244
+ safety_criticality * 0.40 + # Safety always dominates — non-negotiable content gets priority
245
+ usage_frequency * 0.25 + # Frequently used = valuable — from stats.json invocation counts
246
+ persona_relevance * 0.20 + # Persona-matched = valuable — e.g. backend-lead boosts API skills
247
+ language_relevance * 0.15 # Language-matched = contextual — include only relevant rules
248
+ )
249
+ # Weight rationale: safety must dominate (0.40) to guarantee constitution + guard rules always fit.
250
+ # Usage + persona (0.45 combined) ensure the most practical content fills remaining budget.
251
+ # Language (0.15) is a tiebreaker — most projects use 1-2 languages.
252
+ # Weights are compile-time constants in v1. If empirical testing (5 standard tasks across
253
+ # 3 model sizes) shows suboptimal results, expose as --score-weights flag in v2.
254
+ ```
255
+
256
+ **Fixed-score components (always included):**
257
+
258
+ | Component | Score | Reason |
259
+ |-----------|-------|--------|
260
+ | Constitution (Articles I-V) | 1.0 | Non-negotiable safety |
261
+ | Guard hooks (destructive, path) | 0.95 | Core safety rules (compiled as text, not hooks) |
262
+ | Active persona definition | 0.90 | User-selected identity |
263
+ | Active language rules | 0.85 | Project-specific quality gates |
264
+
265
+ **Dynamic-score components:**
266
+
267
+ | Component | Base Score | Adjusted By |
268
+ |-----------|-----------|-------------|
269
+ | Individual skills | 0.3-0.7 | Usage frequency + persona fit |
270
+ | Agent definitions | 0.2-0.6 | Persona relevance (only 1 agent in SLM mode) |
271
+ | Knowledge skills | 0.2-0.5 | Language match + persona match |
272
+ | Iron Law rules | 0.7 | Always high (quality enforcement) |
273
+
274
+ ---
275
+
276
+ #### 1.3 Compression Engine
277
+
278
+ **Strip low-signal content while preserving semantics:**
279
+
280
+ | Strip Target | Savings (est.) | Example |
281
+ |-------------|---------------|---------|
282
+ | `## Common Rationalizations` tables | 200-400 tokens/skill | 15 skills have these tables |
283
+ | `## Related Skills` sections | 50-100 tokens/skill | Routing not useful for SLMs |
284
+ | `## Verification Checklist` (keep 1-liner summary) | 100-200 tokens/agent | Compress to "Verify: tests pass, no placeholders" |
285
+ | Markdown headers (collapse hierarchy) | 20-50 tokens/file | `### 2.1.3 Sub-feature` → plain paragraph |
286
+ | Example code blocks (keep first, strip rest) | 100-500 tokens/skill | Keep 1 example max |
287
+ | Frontmatter (YAML) | 50-100 tokens/file | Strip entirely from compiled output |
288
+ | Agent `## Allowed CLI Commands` lists | 200-400 tokens/agent | Not needed when agent won't execute them |
289
+ | Multi-agent coordination instructions | 300-500 tokens | SLM = single agent, no /orchestrate |
290
+ | Effort-based budgeting rules | 100 tokens | SLM doesn't manage budgets |
291
+
292
+ **Compression levels:**
293
+
294
+ ```python
295
+ COMPRESSION_LEVELS = {
296
+ 'ultra-light': {
297
+ 'strip_examples': True,
298
+ 'strip_rationalizations': True,
299
+ 'strip_related_skills': True,
300
+ 'strip_verification': True,
301
+ 'strip_agent_commands': True,
302
+ 'strip_multi_agent': True,
303
+ 'max_skills': 5, # Only top 5 skills by score
304
+ 'max_agents': 0, # No agent definitions (persona only)
305
+ 'include_rules': False,
306
+ },
307
+ 'light': {
308
+ 'strip_examples': True,
309
+ 'strip_rationalizations': True,
310
+ 'strip_related_skills': True,
311
+ 'strip_verification': 'summary', # 1-liner
312
+ 'strip_agent_commands': True,
313
+ 'strip_multi_agent': True,
314
+ 'max_skills': 10,
315
+ 'max_agents': 1, # Persona agent only
316
+ 'include_rules': True,
317
+ },
318
+ 'standard': {
319
+ 'strip_examples': 'first-only', # Keep 1 example
320
+ 'strip_rationalizations': True,
321
+ 'strip_related_skills': True,
322
+ 'strip_verification': 'summary',
323
+ 'strip_agent_commands': True,
324
+ 'strip_multi_agent': True,
325
+ 'max_skills': 20,
326
+ 'max_agents': 3,
327
+ 'include_rules': True,
328
+ },
329
+ 'extended': {
330
+ 'strip_examples': 'first-only',
331
+ 'strip_rationalizations': 'first-only',
332
+ 'strip_related_skills': False,
333
+ 'strip_verification': False,
334
+ 'strip_agent_commands': False,
335
+ 'strip_multi_agent': True, # Still stripped for SLMs
336
+ 'max_skills': 40,
337
+ 'max_agents': 5,
338
+ 'include_rules': True,
339
+ },
340
+ }
341
+ ```
342
+
343
+ ---
344
+
345
+ #### 1.4 Budget Packer
346
+
347
+ **Greedy knapsack algorithm:** Sort components by `score / compressed_tokens` ratio (value density), pack until budget exhausted.
348
+
349
+ ```python
350
+ def pack_components(components: list[Component], budget: int) -> list[Component]:
351
+ """Pack highest-value components into token budget."""
352
+ # Fixed components always included (constitution, persona, language rules)
353
+ fixed = [c for c in components if c.score >= 0.85]
354
+ remaining_budget = budget - sum(c.tokens_compressed for c in fixed)
355
+
356
+ # Sort remaining by value density
357
+ dynamic = sorted(
358
+ [c for c in components if c.score < 0.85],
359
+ key=lambda c: c.score / max(c.tokens_compressed, 1),
360
+ reverse=True
361
+ )
362
+
363
+ packed = list(fixed)
364
+ for comp in dynamic:
365
+ if comp.tokens_compressed <= remaining_budget:
366
+ packed.append(comp)
367
+ remaining_budget -= comp.tokens_compressed
368
+
369
+ return packed
370
+ ```
371
+
372
+ **Budget validation:** After packing, verify total tokens ≤ budget × 0.95 (5% safety margin for tokenizer estimation error).
373
+
374
+ **Constitution budget guard:** Before packing dynamic components, verify that fixed components (constitution + persona + language rules) fit within the budget. If `sum(fixed.tokens_compressed) > budget`, fail with: `"Constitution + safety rules alone exceed {budget} token budget. Minimum safe budget: {required}. Use --budget {required} or higher."` This prevents silent omission of safety-critical content.
375
+
376
+ ---
377
+
378
+ #### 1.5 Emitter
379
+
380
+ **Output:** Single markdown file structured for maximum SLM comprehension.
381
+
382
+ ```markdown
383
+ # AI Coding Assistant — System Instructions
384
+
385
+ ## Safety Rules (MANDATORY)
386
+ [Compiled constitution — always first, highest attention position]
387
+
388
+ ## Your Identity
389
+ [Compiled persona — who you are, what you focus on]
390
+
391
+ ## Coding Standards
392
+ [Compiled language rules — active language only]
393
+
394
+ ## Key Skills
395
+ [Top N skill summaries — compressed, actionable]
396
+
397
+ ## Quality Checklist
398
+ [Compiled from Iron Laws + verification — bullet points only]
399
+ ```
400
+
401
+ **Why this structure:**
402
+ - Safety first = maximum attention weight in transformer architecture
403
+ - Identity second = establishes persona before task instructions
404
+ - Standards = project-specific rules that shape code output
405
+ - Skills at end = reference material, lower attention needed
406
+
407
+ ---
408
+
409
+ ### Phase 2: Integration (week 2-3)
410
+
411
+ #### 2.1 Profile Integration
412
+
413
+ **manifest.json addition:**
414
+ ```json
415
+ {
416
+ "profiles": {
417
+ "offline-slm": ["core"],
418
+ "offline-slm-extended": ["core", "agents"]
419
+ }
420
+ }
421
+ ```
422
+
423
+ **Install behavior:**
424
+ ```bash
425
+ ai-toolkit install --profile offline-slm
426
+
427
+ # What happens:
428
+ # 1. Standard install of core components
429
+ # 2. Runs compile_slm.py with auto-detected settings
430
+ # 3. Writes compiled output to ~/.ai-toolkit/compiled/
431
+ # 4. Generates integration instructions for detected local model tools
432
+ # 5. state.json records profile as "offline-slm"
433
+ ```
434
+
435
+ **No hooks installed:** SLM providers (Ollama, LM Studio) don't support lifecycle hooks. The critical hook behavior (destructive command guard, path guard) is compiled into the system prompt text as rules.
436
+
437
+ ---
438
+
439
+ #### 2.2 CLI Command
440
+
441
+ ```bash
442
+ ai-toolkit compile-slm # auto-detect model, default budget
443
+ ai-toolkit compile-slm --budget 4096 # explicit token budget
444
+ ai-toolkit compile-slm --budget 8192 --persona backend-lead # persona + budget
445
+ ai-toolkit compile-slm --model-size 8b # auto-select budget for 8B model
446
+ ai-toolkit compile-slm --model-size 32b # auto-select budget for 32B model
447
+ ai-toolkit compile-slm --lang typescript,python # include specific language rules
448
+ ai-toolkit compile-slm --output ./my-system-prompt.md # custom output path
449
+ ai-toolkit compile-slm --dry-run # show what would be included + token counts (table format below)
450
+
451
+ # --dry-run output format:
452
+ # Budget: 4096 tokens | Level: light | Persona: backend-lead
453
+ # ┌────────────────────────────┬──────────┬────────┬──────────┐
454
+ # │ Component │ Score │ Tokens │ Included │
455
+ # ├────────────────────────────┼──────────┼────────┼──────────┤
456
+ # │ Constitution (Articles I-V)│ 1.00 │ 420 │ YES │
457
+ # │ Persona: backend-lead │ 0.90 │ 180 │ YES │
458
+ # │ Rule: coding-style │ 0.85 │ 310 │ YES │
459
+ # │ Skill: /review │ 0.68 │ 290 │ YES │
460
+ # │ ... │ ... │ ... │ ... │
461
+ # │ Skill: /deploy │ 0.22 │ 350 │ NO (budget)│
462
+ # └────────────────────────────┴──────────┴────────┴──────────┘
463
+ # Total: 3,840 / 4,096 tokens (93.7% utilization)
464
+ ai-toolkit compile-slm --format ollama # output as Ollama Modelfile SYSTEM block
465
+ ai-toolkit compile-slm --format json-string # JSON-escaped string (for config files)
466
+ ai-toolkit compile-slm --format raw # plain markdown (default)
467
+ ```
468
+
469
+ **Model size → budget mapping:**
470
+
471
+ Note: budget is about *effective instruction following capacity*, not context window. A 128K-context 8B model can *hold* 16K system prompt tokens, but cannot *follow* them reliably. Empirically, SLMs degrade when system prompt exceeds ~10-15% of their effective capacity.
472
+
473
+ ```python
474
+ MODEL_BUDGETS = {
475
+ '7b': {'budget': 2048, 'level': 'ultra-light'}, # Llama 3.1 8B, Mistral 7B
476
+ '8b': {'budget': 2048, 'level': 'ultra-light'},
477
+ '14b': {'budget': 4096, 'level': 'light'}, # Qwen 2.5 14B, Phi-3 14B
478
+ '32b': {'budget': 8192, 'level': 'standard'}, # Qwen 2.5 32B, Mixtral 8x7B
479
+ '70b': {'budget': 16384, 'level': 'extended'}, # Llama 3.1 70B
480
+ }
481
+ ```
482
+
483
+ ---
484
+
485
+ #### 2.3 Model Size Detection
486
+
487
+ **Auto-detect from Ollama:**
488
+ ```python
489
+ def detect_model_size() -> str | None:
490
+ """Detect running model size from Ollama API."""
491
+ try:
492
+ # curl http://localhost:11434/api/tags
493
+ resp = urllib.request.urlopen('http://localhost:11434/api/tags', timeout=2)
494
+ data = json.loads(resp.read())
495
+ models = data.get('models', [])
496
+ if models:
497
+ # Extract parameter count from model name: "llama3.1:8b" → "8b"
498
+ latest = models[0]['name']
499
+ match = re.search(r'(\d+)[bB]', latest)
500
+ if match:
501
+ return match.group(0).lower()
502
+ except (urllib.error.URLError, TimeoutError, json.JSONDecodeError):
503
+ pass
504
+ return None
505
+ ```
506
+
507
+ **Fallback:** If no model detected, use `14b` defaults (4K budget, light compression). User can override with `--model-size`.
508
+
509
+ ---
510
+
511
+ ### Phase 3: Polish (week 3-4)
512
+
513
+ #### 3.1 Integration Guides
514
+
515
+ Per-platform setup instructions generated by the compiler.
516
+
517
+ **Ollama:**
518
+ ```bash
519
+ # 1. Compile system prompt
520
+ ai-toolkit compile-slm --format ollama --model-size 8b > Modelfile.ai-toolkit
521
+
522
+ # 2. Create custom model
523
+ ollama create my-coder -f Modelfile.ai-toolkit
524
+
525
+ # 3. Use
526
+ ollama run my-coder "implement the payment API"
527
+ ```
528
+
529
+ **LM Studio:**
530
+ ```
531
+ 1. ai-toolkit compile-slm --model-size 14b
532
+ 2. Open LM Studio → Chat → System Prompt
533
+ 3. Paste contents of ~/.ai-toolkit/compiled/slm-system-prompt.md
534
+ ```
535
+
536
+ **Aider:**
537
+ ```bash
538
+ ai-toolkit compile-slm --output .aider.system-prompt.md --model-size 32b
539
+ aider --model ollama/qwen2.5-coder:32b --system-prompt-file .aider.system-prompt.md
540
+ ```
541
+
542
+ **Continue.dev:**
543
+ ```bash
544
+ # 1. Compile to a local file
545
+ ai-toolkit compile-slm --model-size 14b
546
+
547
+ # 2. In .continue/config.json, paste the compiled content into systemMessage
548
+ # (Continue.dev does not support file references — content must be inline)
549
+ # Use: ai-toolkit compile-slm --format json-string to get escaped output
550
+ ```
551
+
552
+ ---
553
+
554
+ #### 3.2 Compile Quality Validator
555
+
556
+ Post-compilation checks:
557
+
558
+ | Check | Severity | Description |
559
+ |-------|----------|-------------|
560
+ | Constitution present | FAIL | Articles I-V must be in output |
561
+ | Budget exceeded | FAIL | Token count > budget |
562
+ | Persona missing (when specified) | WARN | Persona definition not included |
563
+ | No language rules included | WARN | Project language not detected |
564
+ | Less than 3 skills included | WARN | Very minimal — may be too sparse |
565
+ | Output empty | FAIL | Compilation produced no content |
566
+
567
+ ---
568
+
569
+ ## 6. File Summary
570
+
571
+ | File | Action | LOC (est.) | Description |
572
+ |------|--------|------------|-------------|
573
+ | `scripts/compile_slm.py` | CREATE | ~500 | Main compiler — orchestrates pipeline: parse → score → compress → pack → emit. Contains `Component` dataclass, scorer, and budget packer |
574
+ | `scripts/slm_token_counter.py` | CREATE | ~50 | Token estimation (stdlib only) — `estimate_tokens()` function used by compiler and validator |
575
+ | `scripts/slm_compression.py` | CREATE | ~300 | Compression engine — strip/summarize functions per content type, compression level configs (`COMPRESSION_LEVELS` dict) |
576
+ | `scripts/slm_integration.py` | CREATE | ~150 | Platform-specific output formatters — Ollama Modelfile, JSON-escaped string, raw markdown, Aider-compatible |
577
+ | `bin/ai-toolkit.js` | EDIT | +10 | Register `compile-slm` command |
578
+ | `scripts/install.py` | EDIT | +30 | Handle `--profile offline-slm` |
579
+ | `manifest.json` | EDIT | +5 | Add offline-slm profile |
580
+ | `kb/reference/offline-slm-guide.md` | CREATE | ~200 | Integration guides for all platforms |
581
+ | `tests/test_compile_slm.bats` | CREATE | ~150 | Compilation tests |
582
+ | `tests/test_slm_budgets.bats` | CREATE | ~80 | Budget compliance tests |
583
+ | **Total** | | **~1575** | |
584
+
585
+ ---
586
+
587
+ ## 6a. Non-Functional Requirements
588
+
589
+ | Category | Requirement |
590
+ |----------|-------------|
591
+ | **Performance** | Compilation < 2 seconds. No network calls during compilation (all data local). |
592
+ | **Accuracy** | Token estimation ±10% vs tiktoken cl100k_base. Budget compliance: output ≤ budget × 0.95. |
593
+ | **Determinism** | Same input (agents, skills, rules, persona, language, budget) → identical output. No randomness. |
594
+ | **Security** | Constitution Articles I-V always present in output — compilation fails if they exceed budget alone. |
595
+ | **Offline** | Zero network dependencies. Ollama auto-detection gracefully fails to manual fallback. |
596
+ | **Portability** | Output is plain markdown — consumable by any tool accepting a system prompt string/file. |
597
+ | **Quality gates** | `ruff check scripts/compile_slm.py scripts/slm_*.py` (0 errors), `mypy --strict scripts/compile_slm.py scripts/slm_*.py` (0 errors). Run before every commit. |
598
+ | **Type safety** | 100% public API type hints (all function signatures). `Component` dataclass fully typed. Scoring functions use typed parameters, not bare `dict`. |
599
+
600
+ ---
601
+
602
+ ## 6b. Cache Invalidation & Recompile Triggers
603
+
604
+ Compiled output (`~/.ai-toolkit/compiled/slm-system-prompt.md`) is a **derived artifact** — it must be recompiled when inputs change:
605
+
606
+ | Trigger | Action |
607
+ |---------|--------|
608
+ | `ai-toolkit update` | Auto-recompile if profile is `offline-slm` |
609
+ | `ai-toolkit install --profile offline-slm` | Always compile |
610
+ | Agent/skill/rule files changed (detected via mtime) | Warn: "Compiled SLM prompt may be stale. Run `ai-toolkit compile-slm`" |
611
+ | Manual `ai-toolkit compile-slm` | Always recompile |
612
+
613
+ Compiled output includes a header comment: `<!-- Compiled: 2026-04-10T10:30:00Z | Budget: 4096 | Level: light | Persona: backend-lead -->` for staleness detection.
614
+
615
+ ---
616
+
617
+ ## 6b-bis. Rollback & Removal
618
+
619
+ The offline-slm feature is purely additive — removing it is trivial:
620
+ 1. Delete `scripts/compile_slm.py`, `scripts/slm_token_counter.py`, `scripts/slm_compression.py`, `scripts/slm_integration.py`
621
+ 2. Remove `"offline-slm"` and `"offline-slm-extended"` from `manifest.json` profiles
622
+ 3. Remove `compile-slm` from `SCRIPT_COMMANDS` in `bin/ai-toolkit.js`
623
+ 4. Delete `~/.ai-toolkit/compiled/` directory (user-side)
624
+ 5. No hooks, no state files, no config entries to clean up
625
+
626
+ ---
627
+
628
+ ## 6c. Quality Gate Degradation Notice
629
+
630
+ **Important:** The `offline-slm` profile strips lifecycle hooks because SLM providers don't support them. This means:
631
+
632
+ - No pre-commit quality check (ruff/tsc/mypy)
633
+ - No destructive command interception (guard hooks)
634
+ - No session context preservation
635
+
636
+ Guard hook behavior is **compiled into the system prompt as text rules** — the SLM is *instructed* not to run destructive commands, but unlike hook-based enforcement, this is advisory, not blocking.
637
+
638
+ Documentation must clearly state: **"SLM mode trades enforcement for guidance. Safety rules are present but not machine-enforced."**
639
+
640
+ For teams needing enforcement, recommend `--profile offline-slm` combined with a Git pre-commit hook (`.git/hooks/pre-commit`) that runs lint/type-check independently of the AI tool.
641
+
642
+ ---
643
+
644
+ ## 7. Success Criteria (Overall)
645
+
646
+ | Metric | Target |
647
+ |--------|--------|
648
+ | Budget tiers | 4 (ultra-light 2K, light 4K, standard 8K, extended 16K) |
649
+ | Token budget compliance | 100% (output ≤ budget in all cases) |
650
+ | Constitution inclusion | 100% (always present, all 5 articles) |
651
+ | Compilation time | < 2 seconds |
652
+ | Model size auto-detection | Ollama API (with graceful fallback) |
653
+ | Output formats | 4 (raw markdown, Ollama Modelfile, JSON-escaped string, Aider-compatible) |
654
+ | Integration guides | 4 platforms (Ollama, LM Studio, Aider, Continue.dev) |
655
+ | Persona support | 4 personas (backend-lead, frontend-lead, devops-eng, junior-dev) |
656
+ | Language rule support | 13 languages (all existing rules) |
657
+ | External dependencies | 0 (stdlib Python only) |
658
+ | Tests | 40+ |
659
+
660
+ ---
661
+
662
+ ## 8. Risks and Mitigation
663
+
664
+ | Risk | Probability | Impact | Mitigation |
665
+ |------|-------------|--------|------------|
666
+ | Token estimation too inaccurate | Medium | Medium | Validate against tiktoken on 50 files, target ±10% |
667
+ | Compiled prompt too compressed — loses meaning | Medium | High | Validate with 8B model on 5 standard tasks; if quality drops, increase minimum budget |
668
+ | Ollama API changes | Low | Low | Graceful fallback to manual `--model-size` |
669
+ | User expects full toolkit features with SLM | Medium | Medium | Clear documentation: "SLM mode = safety + coding standards, not multi-agent orchestration" |
670
+ | Air-gapped environment can't run `ai-toolkit compile-slm` | Low | Medium | Pre-compile during `install` when network is available; compiled output is self-contained |
671
+ | Constitution text changes break compiled cache | Low | Low | Recompile on every `ai-toolkit update` |
672
+
673
+ ---
674
+
675
+ ## 9. Pre-Mortem
676
+
677
+ 1. **"Compiled prompt is too generic"** — without the full agent definitions, the SLM may produce generic code that doesn't match project conventions. Mitigation: Language rules and persona have highest priority after constitution — they provide project-specific context.
678
+ 2. **"Users expect /review to work with 8B model"** — Skill invocations won't be available via SLM providers that lack hook support. Mitigation: Compiled output includes skill *knowledge* as rules, not invocable commands. Clear docs: "Skills are compiled as coding standards, not slash commands."
679
+ 3. **"Model detects wrong size"** — Ollama model naming is inconsistent (`llama3.1:8b` vs `codellama:7b-instruct`). Mitigation: regex extracts any `\d+[bB]` pattern; fallback to `14b` if ambiguous.
680
+ 4. **"Other local inference tools emerge"** — Jan.ai, GPT4All, Tabby, etc. Mitigation: Raw markdown output works with any tool that accepts a system prompt file.
681
+ 5. **"Nobody uses the feature"** — SLM adoption among professional developers may be niche. Mitigation: Low effort (3-4 weeks), high signaling value ("we support air-gapped environments"), enterprise sales enabler.
682
+
683
+ ---
684
+
685
+ ## 10. Market Positioning
686
+
687
+ **Target users:**
688
+ 1. **Enterprise (air-gapped)** — financial services, defense, healthcare firms that cannot send code to cloud LLM APIs
689
+ 2. **Privacy-conscious solo devs** — developers who don't want code leaving their machine
690
+ 3. **Cost-sensitive teams** — startups that can't afford Anthropic/OpenAI API costs at scale
691
+ 4. **Offline-first** — developers working on trains, planes, or in regions with poor connectivity
692
+
693
+ **Competitive advantage:** No existing AI coding toolkit provides a compilation pipeline that adapts its instruction set to model capacity. This is a first-mover feature.
694
+
695
+ ---
696
+
697
+ ## 11. Next Actions
698
+
699
+ 1. [ ] Approve plan
700
+ 2. [ ] Implement token counter (1.1)
701
+ 3. [ ] Implement component parser + scorer (1.2)
702
+ 4. [ ] Implement compression engine (1.3)
703
+ 5. [ ] Implement budget packer + emitter (1.4, 1.5)
704
+ 6. [ ] Integrate profile into install.py + manifest.json (2.1)
705
+ 7. [ ] Create CLI command `compile-slm` (2.2)
706
+ 8. [ ] Add Ollama model detection (2.3)
707
+ 9. [ ] Add persona + language aware compilation (2.4, 2.5)
708
+ 10. [ ] Write integration guides for 4 platforms (3.1)
709
+ 11. [ ] Compile quality validator (3.2)
710
+ 12. [ ] Tests + documentation (3.3, 3.4)
711
+
712
+ ---
713
+
714
+ ## 12. Future
715
+
716
+ | Feature | Rationale |
717
+ |---------|-----------|
718
+ | Automatic recompile on file changes (file watcher) | v1 uses manual recompile + staleness warning |
719
+ | Quality benchmarks (run 5 standard tasks, measure output quality per budget tier) | Validate compilation quality empirically before shipping |
720
+ | Plugin-aware compilation (include memory-pack prompts if installed) | Depends on plugin system maturity |
721
+ | Model-specific prompt templates (different SLM families prefer different instruction styles) | Needs empirical testing across model families |
722
+ | `--profile offline-slm --enforce-git-hooks` (install git pre-commit hook for quality gates) | Compensates for stripped lifecycle hooks |
723
+
724
+ ---
725
+
726
+ ## 13. Cross-Plan Dependencies
727
+
728
+ This plan shares modification targets with two other proposed plans:
729
+
730
+ | Shared File | This Plan | Enterprise Config Plan | Local Dashboard Plan |
731
+ |-------------|-----------|----------------------|---------------------|
732
+ | `scripts/install.py` | +30 LOC (offline-slm profile) | +80 LOC (extends resolution) | — |
733
+ | `manifest.json` | +5 LOC (offline-slm profile) | +10 LOC (schema refs) | — |
734
+ | `bin/ai-toolkit.js` | +10 LOC (compile-slm command) | +40 LOC (config subcommands) | +15 LOC (ui command) |
735
+
736
+ **If implementing in parallel:** this plan has the smallest changes to shared files — merge first to minimize conflicts.
737
+
738
+ **Enterprise Config interaction:** If Enterprise Config ships, `compile-slm` should respect the `extends` chain — compile the merged config, not just local. Add a `--ignore-extends` flag for air-gapped environments without access to the base config.
739
+
740
+ ---
741
+
742
+ **Last Updated:** 2026-04-10