claude-code-pilot 3.0.0 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -97
- package/bin/install.js +14 -14
- package/manifest.json +1 -1
- package/package.json +17 -5
- package/src/agents/doc-updater.md +1 -1
- package/src/agents/gan-evaluator.md +209 -0
- package/src/agents/gan-generator.md +131 -0
- package/src/agents/gan-planner.md +99 -0
- package/src/agents/harness-optimizer.md +35 -0
- package/src/agents/loop-operator.md +36 -0
- package/src/agents/opensource-forker.md +198 -0
- package/src/agents/opensource-packager.md +249 -0
- package/src/agents/opensource-sanitizer.md +188 -0
- package/src/agents/performance-optimizer.md +446 -0
- package/src/available-rules/README.md +1 -1
- package/src/commands/{aside.md → ccp/aside.md} +14 -13
- package/src/commands/{build-fix.md → ccp/build-fix.md} +5 -0
- package/src/commands/{checkpoint.md → ccp/checkpoint.md} +12 -7
- package/src/commands/{code-review.md → ccp/code-review.md} +5 -0
- package/src/commands/{context-budget.md → ccp/context-budget.md} +2 -1
- package/src/commands/{cpp-build.md → ccp/cpp-build.md} +6 -5
- package/src/commands/{cpp-review.md → ccp/cpp-review.md} +7 -6
- package/src/commands/{cpp-test.md → ccp/cpp-test.md} +6 -5
- package/src/commands/ccp/docs-update.md +48 -0
- package/src/commands/{docs.md → ccp/docs.md} +4 -3
- package/src/commands/{e2e.md → ccp/e2e.md} +7 -6
- package/src/commands/{eval.md → ccp/eval.md} +10 -5
- package/src/commands/{evolve.md → ccp/evolve.md} +3 -3
- package/src/commands/{go-build.md → ccp/go-build.md} +6 -5
- package/src/commands/{go-review.md → ccp/go-review.md} +7 -6
- package/src/commands/{go-test.md → ccp/go-test.md} +6 -5
- package/src/commands/{gradle-build.md → ccp/gradle-build.md} +1 -0
- package/src/commands/{harness-audit.md → ccp/harness-audit.md} +6 -1
- package/src/commands/{kotlin-build.md → ccp/kotlin-build.md} +6 -5
- package/src/commands/{kotlin-review.md → ccp/kotlin-review.md} +7 -6
- package/src/commands/{kotlin-test.md → ccp/kotlin-test.md} +6 -5
- package/src/commands/{learn.md → ccp/learn.md} +7 -2
- package/src/commands/{model-route.md → ccp/model-route.md} +6 -1
- package/src/commands/{orchestrate.md → ccp/orchestrate.md} +4 -3
- package/src/commands/{plan.md → ccp/plan.md} +6 -5
- package/src/commands/ccp/profile-user.md +46 -0
- package/src/commands/{prompt-optimize.md → ccp/prompt-optimize.md} +3 -2
- package/src/commands/{prune.md → ccp/prune.md} +4 -4
- package/src/commands/{python-review.md → ccp/python-review.md} +7 -6
- package/src/commands/{quality-gate.md → ccp/quality-gate.md} +6 -1
- package/src/commands/{refactor-clean.md → ccp/refactor-clean.md} +5 -0
- package/src/commands/{resume-session.md → ccp/resume-session.md} +9 -8
- package/src/commands/ccp/review.md +37 -0
- package/src/commands/{rules-distill.md → ccp/rules-distill.md} +2 -1
- package/src/commands/{rust-build.md → ccp/rust-build.md} +6 -5
- package/src/commands/{rust-review.md → ccp/rust-review.md} +7 -6
- package/src/commands/{rust-test.md → ccp/rust-test.md} +6 -5
- package/src/commands/{save-session.md → ccp/save-session.md} +2 -1
- package/src/commands/ccp/secure-phase.md +35 -0
- package/src/commands/{sessions.md → ccp/sessions.md} +29 -24
- package/src/commands/{setup-pm.md → ccp/setup-pm.md} +1 -0
- package/src/commands/{setup-refresh.md → ccp/setup-refresh.md} +4 -3
- package/src/commands/{setup.md → ccp/setup.md} +24 -23
- package/src/commands/{skill-create.md → ccp/skill-create.md} +8 -8
- package/src/commands/{skill-health.md → ccp/skill-health.md} +5 -5
- package/src/commands/{tdd.md → ccp/tdd.md} +9 -8
- package/src/commands/{test-coverage.md → ccp/test-coverage.md} +5 -0
- package/src/commands/{tool-guide.md → ccp/tool-guide.md} +2 -1
- package/src/commands/{update-codemaps.md → ccp/update-codemaps.md} +5 -0
- package/src/commands/{update-docs.md → ccp/update-docs.md} +5 -0
- package/src/commands/{verify.md → ccp/verify.md} +5 -0
- package/src/commands/ccp/workstreams.md +68 -0
- package/src/examples/CLAUDE.md +4 -4
- package/src/examples/django-api-CLAUDE.md +5 -5
- package/src/examples/go-microservice-CLAUDE.md +6 -6
- package/src/examples/rust-api-CLAUDE.md +4 -4
- package/src/examples/saas-nextjs-CLAUDE.md +8 -8
- package/src/hooks/session-start.js +1 -1
- package/src/pilot/references/mcp-servers.json +1 -1
- package/src/pilot/workflows/docs-update.md +1165 -0
- package/src/pilot/workflows/help.md +48 -56
- package/src/pilot/workflows/profile-user.md +452 -0
- package/src/pilot/workflows/review.md +244 -0
- package/src/pilot/workflows/secure-phase.md +164 -0
- package/src/rules/common/code-review.md +124 -0
- package/src/rules/zh/README.md +108 -0
- package/src/rules/zh/agents.md +50 -0
- package/src/rules/zh/code-review.md +124 -0
- package/src/rules/zh/coding-style.md +48 -0
- package/src/rules/zh/development-workflow.md +44 -0
- package/src/rules/zh/git-workflow.md +24 -0
- package/src/rules/zh/hooks.md +30 -0
- package/src/rules/zh/patterns.md +31 -0
- package/src/rules/zh/performance.md +55 -0
- package/src/rules/zh/security.md +29 -0
- package/src/rules/zh/testing.md +29 -0
- package/src/skills/autonomous-agent-harness/SKILL.md +267 -0
- package/src/skills/autonomous-loops/SKILL.md +610 -0
- package/src/skills/bun-runtime/SKILL.md +84 -0
- package/src/skills/content-hash-cache-pattern/SKILL.md +161 -0
- package/src/skills/context-budget/SKILL.md +3 -3
- package/src/skills/continuous-learning-v2/SKILL.md +4 -4
- package/src/skills/continuous-learning-v2/agents/observer.md +1 -1
- package/src/skills/cost-aware-llm-pipeline/SKILL.md +183 -0
- package/src/skills/design-system/SKILL.md +82 -0
- package/src/skills/eval-harness/SKILL.md +270 -0
- package/src/skills/flutter-dart-code-review/SKILL.md +435 -0
- package/src/skills/gan-style-harness/SKILL.md +278 -0
- package/src/skills/git-workflow/SKILL.md +715 -0
- package/src/skills/hexagonal-architecture/SKILL.md +276 -0
- package/src/skills/iterative-retrieval/SKILL.md +211 -0
- package/src/skills/laravel-plugin-discovery/SKILL.md +229 -0
- package/src/skills/nextjs-turbopack/SKILL.md +44 -0
- package/src/skills/nuxt4-patterns/SKILL.md +100 -0
- package/src/skills/opensource-pipeline/SKILL.md +255 -0
- package/src/skills/perl-security/SKILL.md +503 -0
- package/src/skills/project-flow-ops/SKILL.md +111 -0
- package/src/skills/project-guidelines-example/SKILL.md +349 -0
- package/src/skills/prompt-optimizer/SKILL.md +38 -38
- package/src/skills/pytorch-patterns/SKILL.md +396 -0
- package/src/skills/regex-vs-llm-structured-text/SKILL.md +220 -0
- package/src/skills/repo-scan/SKILL.md +78 -0
- package/src/skills/rules-distill/SKILL.md +264 -0
- package/src/skills/rules-distill/scripts/scan-rules.sh +58 -0
- package/src/skills/rules-distill/scripts/scan-skills.sh +129 -0
- package/src/skills/swift-concurrency-6-2/SKILL.md +216 -0
- package/src/skills/token-budget-advisor/SKILL.md +133 -0
- package/src/skills/verification-loop/SKILL.md +1 -1
- package/src/skills/workspace-surface-audit/SKILL.md +125 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: content-hash-cache-pattern
|
|
3
|
+
description: Cache expensive file processing results using SHA-256 content hashes — path-independent, auto-invalidating, with service layer separation.
|
|
4
|
+
origin: ECC
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Content-Hash File Cache Pattern
|
|
8
|
+
|
|
9
|
+
Cache expensive file processing results (PDF parsing, text extraction, image analysis) using SHA-256 content hashes as cache keys. Unlike path-based caching, this approach survives file moves/renames and auto-invalidates when content changes.
|
|
10
|
+
|
|
11
|
+
## When to Activate
|
|
12
|
+
|
|
13
|
+
- Building file processing pipelines (PDF, images, text extraction)
|
|
14
|
+
- Processing cost is high and same files are processed repeatedly
|
|
15
|
+
- Need a `--cache/--no-cache` CLI option
|
|
16
|
+
- Want to add caching to existing pure functions without modifying them
|
|
17
|
+
|
|
18
|
+
## Core Pattern
|
|
19
|
+
|
|
20
|
+
### 1. Content-Hash Based Cache Key
|
|
21
|
+
|
|
22
|
+
Use file content (not path) as the cache key:
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
import hashlib
|
|
26
|
+
from pathlib import Path
|
|
27
|
+
|
|
28
|
+
_HASH_CHUNK_SIZE = 65536 # 64KB chunks for large files
|
|
29
|
+
|
|
30
|
+
def compute_file_hash(path: Path) -> str:
|
|
31
|
+
"""SHA-256 of file contents (chunked for large files)."""
|
|
32
|
+
if not path.is_file():
|
|
33
|
+
raise FileNotFoundError(f"File not found: {path}")
|
|
34
|
+
sha256 = hashlib.sha256()
|
|
35
|
+
with open(path, "rb") as f:
|
|
36
|
+
while True:
|
|
37
|
+
chunk = f.read(_HASH_CHUNK_SIZE)
|
|
38
|
+
if not chunk:
|
|
39
|
+
break
|
|
40
|
+
sha256.update(chunk)
|
|
41
|
+
return sha256.hexdigest()
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Why content hash?** File rename/move = cache hit. Content change = automatic invalidation. No index file needed.
|
|
45
|
+
|
|
46
|
+
### 2. Frozen Dataclass for Cache Entry
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from dataclasses import dataclass
|
|
50
|
+
|
|
51
|
+
@dataclass(frozen=True, slots=True)
|
|
52
|
+
class CacheEntry:
|
|
53
|
+
file_hash: str
|
|
54
|
+
source_path: str
|
|
55
|
+
document: ExtractedDocument # The cached result
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 3. File-Based Cache Storage
|
|
59
|
+
|
|
60
|
+
Each cache entry is stored as `{hash}.json` — O(1) lookup by hash, no index file required.
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
import json
|
|
64
|
+
from typing import Any
|
|
65
|
+
|
|
66
|
+
def write_cache(cache_dir: Path, entry: CacheEntry) -> None:
|
|
67
|
+
cache_dir.mkdir(parents=True, exist_ok=True)
|
|
68
|
+
cache_file = cache_dir / f"{entry.file_hash}.json"
|
|
69
|
+
data = serialize_entry(entry)
|
|
70
|
+
cache_file.write_text(json.dumps(data, ensure_ascii=False), encoding="utf-8")
|
|
71
|
+
|
|
72
|
+
def read_cache(cache_dir: Path, file_hash: str) -> CacheEntry | None:
|
|
73
|
+
cache_file = cache_dir / f"{file_hash}.json"
|
|
74
|
+
if not cache_file.is_file():
|
|
75
|
+
return None
|
|
76
|
+
try:
|
|
77
|
+
raw = cache_file.read_text(encoding="utf-8")
|
|
78
|
+
data = json.loads(raw)
|
|
79
|
+
return deserialize_entry(data)
|
|
80
|
+
except (json.JSONDecodeError, ValueError, KeyError):
|
|
81
|
+
return None # Treat corruption as cache miss
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 4. Service Layer Wrapper (SRP)
|
|
85
|
+
|
|
86
|
+
Keep the processing function pure. Add caching as a separate service layer.
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
def extract_with_cache(
|
|
90
|
+
file_path: Path,
|
|
91
|
+
*,
|
|
92
|
+
cache_enabled: bool = True,
|
|
93
|
+
cache_dir: Path = Path(".cache"),
|
|
94
|
+
) -> ExtractedDocument:
|
|
95
|
+
"""Service layer: cache check -> extraction -> cache write."""
|
|
96
|
+
if not cache_enabled:
|
|
97
|
+
return extract_text(file_path) # Pure function, no cache knowledge
|
|
98
|
+
|
|
99
|
+
file_hash = compute_file_hash(file_path)
|
|
100
|
+
|
|
101
|
+
# Check cache
|
|
102
|
+
cached = read_cache(cache_dir, file_hash)
|
|
103
|
+
if cached is not None:
|
|
104
|
+
logger.info("Cache hit: %s (hash=%s)", file_path.name, file_hash[:12])
|
|
105
|
+
return cached.document
|
|
106
|
+
|
|
107
|
+
# Cache miss -> extract -> store
|
|
108
|
+
logger.info("Cache miss: %s (hash=%s)", file_path.name, file_hash[:12])
|
|
109
|
+
doc = extract_text(file_path)
|
|
110
|
+
entry = CacheEntry(file_hash=file_hash, source_path=str(file_path), document=doc)
|
|
111
|
+
write_cache(cache_dir, entry)
|
|
112
|
+
return doc
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Key Design Decisions
|
|
116
|
+
|
|
117
|
+
| Decision | Rationale |
|
|
118
|
+
|----------|-----------|
|
|
119
|
+
| SHA-256 content hash | Path-independent, auto-invalidates on content change |
|
|
120
|
+
| `{hash}.json` file naming | O(1) lookup, no index file needed |
|
|
121
|
+
| Service layer wrapper | SRP: extraction stays pure, cache is a separate concern |
|
|
122
|
+
| Manual JSON serialization | Full control over frozen dataclass serialization |
|
|
123
|
+
| Corruption returns `None` | Graceful degradation, re-processes on next run |
|
|
124
|
+
| `cache_dir.mkdir(parents=True)` | Lazy directory creation on first write |
|
|
125
|
+
|
|
126
|
+
## Best Practices
|
|
127
|
+
|
|
128
|
+
- **Hash content, not paths** — paths change, content identity doesn't
|
|
129
|
+
- **Chunk large files** when hashing — avoid loading entire files into memory
|
|
130
|
+
- **Keep processing functions pure** — they should know nothing about caching
|
|
131
|
+
- **Log cache hit/miss** with truncated hashes for debugging
|
|
132
|
+
- **Handle corruption gracefully** — treat invalid cache entries as misses, never crash
|
|
133
|
+
|
|
134
|
+
## Anti-Patterns to Avoid
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
# BAD: Path-based caching (breaks on file move/rename)
|
|
138
|
+
cache = {"/path/to/file.pdf": result}
|
|
139
|
+
|
|
140
|
+
# BAD: Adding cache logic inside the processing function (SRP violation)
|
|
141
|
+
def extract_text(path, *, cache_enabled=False, cache_dir=None):
|
|
142
|
+
if cache_enabled: # Now this function has two responsibilities
|
|
143
|
+
...
|
|
144
|
+
|
|
145
|
+
# BAD: Using dataclasses.asdict() with nested frozen dataclasses
|
|
146
|
+
# (can cause issues with complex nested types)
|
|
147
|
+
data = dataclasses.asdict(entry) # Use manual serialization instead
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## When to Use
|
|
151
|
+
|
|
152
|
+
- File processing pipelines (PDF parsing, OCR, text extraction, image analysis)
|
|
153
|
+
- CLI tools that benefit from `--cache/--no-cache` options
|
|
154
|
+
- Batch processing where the same files appear across runs
|
|
155
|
+
- Adding caching to existing pure functions without modifying them
|
|
156
|
+
|
|
157
|
+
## When NOT to Use
|
|
158
|
+
|
|
159
|
+
- Data that must always be fresh (real-time feeds)
|
|
160
|
+
- Cache entries that would be extremely large (consider streaming instead)
|
|
161
|
+
- Results that depend on parameters beyond file content (e.g., different extraction configs)
|
|
@@ -14,7 +14,7 @@ Analyze token overhead across every loaded component in a Claude Code session an
|
|
|
14
14
|
- You've recently added many skills, agents, or MCP servers
|
|
15
15
|
- You want to know how much context headroom you actually have
|
|
16
16
|
- Planning to add more components and need to know if there's room
|
|
17
|
-
- Running `/context-budget` command (this skill backs it)
|
|
17
|
+
- Running `/ccp:context-budget` command (this skill backs it)
|
|
18
18
|
|
|
19
19
|
## How It Works
|
|
20
20
|
|
|
@@ -106,7 +106,7 @@ In verbose mode, additionally output per-file token counts, line-by-line breakdo
|
|
|
106
106
|
|
|
107
107
|
**Basic audit**
|
|
108
108
|
```
|
|
109
|
-
User: /context-budget
|
|
109
|
+
User: /ccp:context-budget
|
|
110
110
|
Skill: Scans setup → 16 agents (12,400 tokens), 28 skills (6,200), 87 MCP tools (43,500), 2 CLAUDE.md (1,200)
|
|
111
111
|
Flags: 3 heavy agents, 14 MCP servers (3 CLI-replaceable)
|
|
112
112
|
Top saving: remove 3 MCP servers → -27,500 tokens (47% overhead reduction)
|
|
@@ -114,7 +114,7 @@ Skill: Scans setup → 16 agents (12,400 tokens), 28 skills (6,200), 87 MCP tool
|
|
|
114
114
|
|
|
115
115
|
**Verbose mode**
|
|
116
116
|
```
|
|
117
|
-
User: /context-budget --verbose
|
|
117
|
+
User: /ccp:context-budget --verbose
|
|
118
118
|
Skill: Full report + per-file breakdown showing planner.md (213 lines, 1,840 tokens),
|
|
119
119
|
MCP tool list with per-tool sizes, duplicated rule lines side by side
|
|
120
120
|
```
|
|
@@ -112,7 +112,7 @@ Session Activity (in a git repo)
|
|
|
112
112
|
| * grep-before-edit.yaml (0.6) [global] |
|
|
113
113
|
+---------------------------------------------+
|
|
114
114
|
|
|
|
115
|
-
| /evolve clusters + /promote
|
|
115
|
+
| /ccp:evolve clusters + /promote
|
|
116
116
|
v
|
|
117
117
|
+---------------------------------------------+
|
|
118
118
|
| projects/<hash>/evolved/ (project-scoped) |
|
|
@@ -201,7 +201,7 @@ mkdir -p ~/.claude/homunculus/{instincts/{personal,inherited},evolved/{agents,sk
|
|
|
201
201
|
|
|
202
202
|
```bash
|
|
203
203
|
/instinct-status # Show learned instincts (project + global)
|
|
204
|
-
/evolve
|
|
204
|
+
/ccp:evolve # Cluster related instincts into skills/commands
|
|
205
205
|
/instinct-export # Export instincts to file
|
|
206
206
|
/instinct-import # Import instincts from others
|
|
207
207
|
/promote # Promote project instincts to global scope
|
|
@@ -213,7 +213,7 @@ mkdir -p ~/.claude/homunculus/{instincts/{personal,inherited},evolved/{agents,sk
|
|
|
213
213
|
| Command | Description |
|
|
214
214
|
|---------|-------------|
|
|
215
215
|
| `/instinct-status` | Show all instincts (project-scoped + global) with confidence |
|
|
216
|
-
| `/evolve` | Cluster related instincts into skills/commands, suggest promotions |
|
|
216
|
+
| `/ccp:evolve` | Cluster related instincts into skills/commands, suggest promotions |
|
|
217
217
|
| `/instinct-export` | Export instincts (filterable by scope/domain) |
|
|
218
218
|
| `/instinct-import <file>` | Import instincts with scope control |
|
|
219
219
|
| `/promote [id]` | Promote project instincts to global scope |
|
|
@@ -306,7 +306,7 @@ python3 instinct-cli.py promote
|
|
|
306
306
|
python3 instinct-cli.py promote --dry-run
|
|
307
307
|
```
|
|
308
308
|
|
|
309
|
-
The `/evolve` command also suggests promotion candidates.
|
|
309
|
+
The `/ccp:evolve` command also suggests promotion candidates.
|
|
310
310
|
|
|
311
311
|
## Confidence Scoring
|
|
312
312
|
|
|
@@ -154,7 +154,7 @@ An instinct should be promoted from project-scoped to global when:
|
|
|
154
154
|
2. Each instance has confidence **>= 0.8**
|
|
155
155
|
3. The domain is in the global-friendly list (security, general-best-practices, workflow)
|
|
156
156
|
|
|
157
|
-
Promotion is handled by the `instinct-cli.py promote` command or the `/evolve` analysis.
|
|
157
|
+
Promotion is handled by the `instinct-cli.py promote` command or the `/ccp:evolve` analysis.
|
|
158
158
|
|
|
159
159
|
## Important Guidelines
|
|
160
160
|
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cost-aware-llm-pipeline
|
|
3
|
+
description: Cost optimization patterns for LLM API usage — model routing by task complexity, budget tracking, retry logic, and prompt caching.
|
|
4
|
+
origin: ECC
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Cost-Aware LLM Pipeline
|
|
8
|
+
|
|
9
|
+
Patterns for controlling LLM API costs while maintaining quality. Combines model routing, budget tracking, retry logic, and prompt caching into a composable pipeline.
|
|
10
|
+
|
|
11
|
+
## When to Activate
|
|
12
|
+
|
|
13
|
+
- Building applications that call LLM APIs (Claude, GPT, etc.)
|
|
14
|
+
- Processing batches of items with varying complexity
|
|
15
|
+
- Need to stay within a budget for API spend
|
|
16
|
+
- Optimizing cost without sacrificing quality on complex tasks
|
|
17
|
+
|
|
18
|
+
## Core Concepts
|
|
19
|
+
|
|
20
|
+
### 1. Model Routing by Task Complexity
|
|
21
|
+
|
|
22
|
+
Automatically select cheaper models for simple tasks, reserving expensive models for complex ones.
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
MODEL_SONNET = "claude-sonnet-4-6"
|
|
26
|
+
MODEL_HAIKU = "claude-haiku-4-5-20251001"
|
|
27
|
+
|
|
28
|
+
_SONNET_TEXT_THRESHOLD = 10_000 # chars
|
|
29
|
+
_SONNET_ITEM_THRESHOLD = 30 # items
|
|
30
|
+
|
|
31
|
+
def select_model(
|
|
32
|
+
text_length: int,
|
|
33
|
+
item_count: int,
|
|
34
|
+
force_model: str | None = None,
|
|
35
|
+
) -> str:
|
|
36
|
+
"""Select model based on task complexity."""
|
|
37
|
+
if force_model is not None:
|
|
38
|
+
return force_model
|
|
39
|
+
if text_length >= _SONNET_TEXT_THRESHOLD or item_count >= _SONNET_ITEM_THRESHOLD:
|
|
40
|
+
return MODEL_SONNET # Complex task
|
|
41
|
+
return MODEL_HAIKU # Simple task (3-4x cheaper)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2. Immutable Cost Tracking
|
|
45
|
+
|
|
46
|
+
Track cumulative spend with frozen dataclasses. Each API call returns a new tracker — never mutates state.
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from dataclasses import dataclass
|
|
50
|
+
|
|
51
|
+
@dataclass(frozen=True, slots=True)
|
|
52
|
+
class CostRecord:
|
|
53
|
+
model: str
|
|
54
|
+
input_tokens: int
|
|
55
|
+
output_tokens: int
|
|
56
|
+
cost_usd: float
|
|
57
|
+
|
|
58
|
+
@dataclass(frozen=True, slots=True)
|
|
59
|
+
class CostTracker:
|
|
60
|
+
budget_limit: float = 1.00
|
|
61
|
+
records: tuple[CostRecord, ...] = ()
|
|
62
|
+
|
|
63
|
+
def add(self, record: CostRecord) -> "CostTracker":
|
|
64
|
+
"""Return new tracker with added record (never mutates self)."""
|
|
65
|
+
return CostTracker(
|
|
66
|
+
budget_limit=self.budget_limit,
|
|
67
|
+
records=(*self.records, record),
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def total_cost(self) -> float:
|
|
72
|
+
return sum(r.cost_usd for r in self.records)
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def over_budget(self) -> bool:
|
|
76
|
+
return self.total_cost > self.budget_limit
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 3. Narrow Retry Logic
|
|
80
|
+
|
|
81
|
+
Retry only on transient errors. Fail fast on authentication or bad request errors.
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from anthropic import (
|
|
85
|
+
APIConnectionError,
|
|
86
|
+
InternalServerError,
|
|
87
|
+
RateLimitError,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
_RETRYABLE_ERRORS = (APIConnectionError, RateLimitError, InternalServerError)
|
|
91
|
+
_MAX_RETRIES = 3
|
|
92
|
+
|
|
93
|
+
def call_with_retry(func, *, max_retries: int = _MAX_RETRIES):
|
|
94
|
+
"""Retry only on transient errors, fail fast on others."""
|
|
95
|
+
for attempt in range(max_retries):
|
|
96
|
+
try:
|
|
97
|
+
return func()
|
|
98
|
+
except _RETRYABLE_ERRORS:
|
|
99
|
+
if attempt == max_retries - 1:
|
|
100
|
+
raise
|
|
101
|
+
time.sleep(2 ** attempt) # Exponential backoff
|
|
102
|
+
# AuthenticationError, BadRequestError etc. → raise immediately
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 4. Prompt Caching
|
|
106
|
+
|
|
107
|
+
Cache long system prompts to avoid resending them on every request.
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
messages = [
|
|
111
|
+
{
|
|
112
|
+
"role": "user",
|
|
113
|
+
"content": [
|
|
114
|
+
{
|
|
115
|
+
"type": "text",
|
|
116
|
+
"text": system_prompt,
|
|
117
|
+
"cache_control": {"type": "ephemeral"}, # Cache this
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"type": "text",
|
|
121
|
+
"text": user_input, # Variable part
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Composition
|
|
129
|
+
|
|
130
|
+
Combine all four techniques in a single pipeline function:
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
def process(text: str, config: Config, tracker: CostTracker) -> tuple[Result, CostTracker]:
|
|
134
|
+
# 1. Route model
|
|
135
|
+
model = select_model(len(text), estimated_items, config.force_model)
|
|
136
|
+
|
|
137
|
+
# 2. Check budget
|
|
138
|
+
if tracker.over_budget:
|
|
139
|
+
raise BudgetExceededError(tracker.total_cost, tracker.budget_limit)
|
|
140
|
+
|
|
141
|
+
# 3. Call with retry + caching
|
|
142
|
+
response = call_with_retry(lambda: client.messages.create(
|
|
143
|
+
model=model,
|
|
144
|
+
messages=build_cached_messages(system_prompt, text),
|
|
145
|
+
))
|
|
146
|
+
|
|
147
|
+
# 4. Track cost (immutable)
|
|
148
|
+
record = CostRecord(model=model, input_tokens=..., output_tokens=..., cost_usd=...)
|
|
149
|
+
tracker = tracker.add(record)
|
|
150
|
+
|
|
151
|
+
return parse_result(response), tracker
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Pricing Reference (2025-2026)
|
|
155
|
+
|
|
156
|
+
| Model | Input ($/1M tokens) | Output ($/1M tokens) | Relative Cost |
|
|
157
|
+
|-------|---------------------|----------------------|---------------|
|
|
158
|
+
| Haiku 4.5 | $0.80 | $4.00 | 1x |
|
|
159
|
+
| Sonnet 4.6 | $3.00 | $15.00 | ~4x |
|
|
160
|
+
| Opus 4.5 | $15.00 | $75.00 | ~19x |
|
|
161
|
+
|
|
162
|
+
## Best Practices
|
|
163
|
+
|
|
164
|
+
- **Start with the cheapest model** and only route to expensive models when complexity thresholds are met
|
|
165
|
+
- **Set explicit budget limits** before processing batches — fail early rather than overspend
|
|
166
|
+
- **Log model selection decisions** so you can tune thresholds based on real data
|
|
167
|
+
- **Use prompt caching** for system prompts over 1024 tokens — saves both cost and latency
|
|
168
|
+
- **Never retry on authentication or validation errors** — only transient failures (network, rate limit, server error)
|
|
169
|
+
|
|
170
|
+
## Anti-Patterns to Avoid
|
|
171
|
+
|
|
172
|
+
- Using the most expensive model for all requests regardless of complexity
|
|
173
|
+
- Retrying on all errors (wastes budget on permanent failures)
|
|
174
|
+
- Mutating cost tracking state (makes debugging and auditing difficult)
|
|
175
|
+
- Hardcoding model names throughout the codebase (use constants or config)
|
|
176
|
+
- Ignoring prompt caching for repetitive system prompts
|
|
177
|
+
|
|
178
|
+
## When to Use
|
|
179
|
+
|
|
180
|
+
- Any application calling Claude, OpenAI, or similar LLM APIs
|
|
181
|
+
- Batch processing pipelines where cost adds up quickly
|
|
182
|
+
- Multi-model architectures that need intelligent routing
|
|
183
|
+
- Production systems that need budget guardrails
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: design-system
|
|
3
|
+
description: Use this skill to generate or audit design systems, check visual consistency, and review PRs that touch styling.
|
|
4
|
+
origin: ECC
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Design System — Generate & Audit Visual Systems
|
|
8
|
+
|
|
9
|
+
## When to Use
|
|
10
|
+
|
|
11
|
+
- Starting a new project that needs a design system
|
|
12
|
+
- Auditing an existing codebase for visual consistency
|
|
13
|
+
- Before a redesign — understand what you have
|
|
14
|
+
- When the UI looks "off" but you can't pinpoint why
|
|
15
|
+
- Reviewing PRs that touch styling
|
|
16
|
+
|
|
17
|
+
## How It Works
|
|
18
|
+
|
|
19
|
+
### Mode 1: Generate Design System
|
|
20
|
+
|
|
21
|
+
Analyzes your codebase and generates a cohesive design system:
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
1. Scan CSS/Tailwind/styled-components for existing patterns
|
|
25
|
+
2. Extract: colors, typography, spacing, border-radius, shadows, breakpoints
|
|
26
|
+
3. Research 3 competitor sites for inspiration (via browser MCP)
|
|
27
|
+
4. Propose a design token set (JSON + CSS custom properties)
|
|
28
|
+
5. Generate DESIGN.md with rationale for each decision
|
|
29
|
+
6. Create an interactive HTML preview page (self-contained, no deps)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Output: `DESIGN.md` + `design-tokens.json` + `design-preview.html`
|
|
33
|
+
|
|
34
|
+
### Mode 2: Visual Audit
|
|
35
|
+
|
|
36
|
+
Scores your UI across 10 dimensions (0-10 each):
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
1. Color consistency — are you using your palette or random hex values?
|
|
40
|
+
2. Typography hierarchy — clear h1 > h2 > h3 > body > caption?
|
|
41
|
+
3. Spacing rhythm — consistent scale (4px/8px/16px) or arbitrary?
|
|
42
|
+
4. Component consistency — do similar elements look similar?
|
|
43
|
+
5. Responsive behavior — fluid or broken at breakpoints?
|
|
44
|
+
6. Dark mode — complete or half-done?
|
|
45
|
+
7. Animation — purposeful or gratuitous?
|
|
46
|
+
8. Accessibility — contrast ratios, focus states, touch targets
|
|
47
|
+
9. Information density — cluttered or clean?
|
|
48
|
+
10. Polish — hover states, transitions, loading states, empty states
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Each dimension gets a score, specific examples, and a fix with exact file:line.
|
|
52
|
+
|
|
53
|
+
### Mode 3: AI Slop Detection
|
|
54
|
+
|
|
55
|
+
Identifies generic AI-generated design patterns:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
- Gratuitous gradients on everything
|
|
59
|
+
- Purple-to-blue defaults
|
|
60
|
+
- "Glass morphism" cards with no purpose
|
|
61
|
+
- Rounded corners on things that shouldn't be rounded
|
|
62
|
+
- Excessive animations on scroll
|
|
63
|
+
- Generic hero with centered text over stock gradient
|
|
64
|
+
- Sans-serif font stack with no personality
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Examples
|
|
68
|
+
|
|
69
|
+
**Generate for a SaaS app:**
|
|
70
|
+
```
|
|
71
|
+
/design-system generate --style minimal --palette earth-tones
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Audit existing UI:**
|
|
75
|
+
```
|
|
76
|
+
/design-system audit --url http://localhost:3000 --pages / /pricing /docs
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Check for AI slop:**
|
|
80
|
+
```
|
|
81
|
+
/design-system slop-check
|
|
82
|
+
```
|