claude-toolkit 0.1.9

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 (85) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/LICENSE +21 -0
  3. package/README.md +126 -0
  4. package/bin/cli.ts +112 -0
  5. package/core/agents/ct-code-reviewer.md +123 -0
  6. package/core/agents/ct-github-workflow.md +137 -0
  7. package/core/commands/ct/code-quality.md +59 -0
  8. package/core/commands/ct/onboard.md +84 -0
  9. package/core/commands/ct/pr-review.md +104 -0
  10. package/core/commands/ct/pr-summary.md +59 -0
  11. package/core/commands/ct/proto-check.md +74 -0
  12. package/core/commands/ct/ticket.md +71 -0
  13. package/core/hooks/skill-eval.js +381 -0
  14. package/core/hooks/skill-eval.sh +35 -0
  15. package/core/hooks/skill-rules.schema.json +112 -0
  16. package/core/skills/systematic-debugging/SKILL.md +44 -0
  17. package/core/skills/testing-patterns/SKILL.md +52 -0
  18. package/core/skills/typescript-conventions/SKILL.md +57 -0
  19. package/core/skills/verification-before-completion/SKILL.md +42 -0
  20. package/docs/README.md +49 -0
  21. package/docs/agents/code-reviewer.md +76 -0
  22. package/docs/agents/github-workflow.md +98 -0
  23. package/docs/best-practices/solidjs/README.md +43 -0
  24. package/docs/best-practices/solidjs/anti-patterns.md +166 -0
  25. package/docs/best-practices/solidjs/component-patterns.md +131 -0
  26. package/docs/best-practices/solidjs/context-and-global-state.md +131 -0
  27. package/docs/best-practices/solidjs/control-flow.md +124 -0
  28. package/docs/best-practices/solidjs/data-fetching.md +205 -0
  29. package/docs/best-practices/solidjs/effects-and-lifecycle.md +113 -0
  30. package/docs/best-practices/solidjs/performance.md +100 -0
  31. package/docs/best-practices/solidjs/props-patterns.md +100 -0
  32. package/docs/best-practices/solidjs/reactivity-model.md +104 -0
  33. package/docs/best-practices/solidjs/signals-and-state.md +78 -0
  34. package/docs/best-practices/solidjs/stores-and-nested-state.md +111 -0
  35. package/docs/best-practices/solidjs/typescript-integration.md +186 -0
  36. package/docs/best-practices/typescript/README.md +45 -0
  37. package/docs/best-practices/typescript/any-and-unknown.md +73 -0
  38. package/docs/best-practices/typescript/deriving-vs-decoupling.md +83 -0
  39. package/docs/best-practices/typescript/discriminated-unions.md +75 -0
  40. package/docs/best-practices/typescript/enums-alternatives.md +72 -0
  41. package/docs/best-practices/typescript/essential-patterns.md +119 -0
  42. package/docs/best-practices/typescript/generics-patterns.md +105 -0
  43. package/docs/best-practices/typescript/micro-opinions.md +87 -0
  44. package/docs/best-practices/typescript/runtime-validation.md +62 -0
  45. package/docs/best-practices/typescript/satisfies-operator.md +100 -0
  46. package/docs/best-practices/typescript/tsconfig-cheat-sheet.md +129 -0
  47. package/docs/best-practices/typescript/type-organization.md +64 -0
  48. package/docs/best-practices/typescript/type-vs-interface.md +80 -0
  49. package/docs/commands/code-quality.md +42 -0
  50. package/docs/commands/onboard.md +72 -0
  51. package/docs/commands/pr-review.md +102 -0
  52. package/docs/commands/pr-summary.md +50 -0
  53. package/docs/commands/proto-check.md +59 -0
  54. package/docs/commands/ticket.md +56 -0
  55. package/docs/skills/systematic-debugging.md +70 -0
  56. package/docs/skills/testing-patterns.md +89 -0
  57. package/docs/skills/typescript-conventions.md +137 -0
  58. package/docs/skills/verification-before-completion.md +91 -0
  59. package/docs/stacks/cloudflare-d1-kv.md +110 -0
  60. package/docs/stacks/i18n-typesafe.md +141 -0
  61. package/docs/stacks/protobuf-contracts.md +85 -0
  62. package/docs/stacks/rust-wasm-patterns.md +106 -0
  63. package/docs/stacks/solidjs-patterns.md +110 -0
  64. package/docs/stacks/vanilla-extract-patterns.md +115 -0
  65. package/package.json +58 -0
  66. package/src/generator.ts +317 -0
  67. package/src/index.ts +30 -0
  68. package/src/types.ts +85 -0
  69. package/src/utils.ts +53 -0
  70. package/stacks/cloudflare/skills/cloudflare-d1-kv/SKILL.md +84 -0
  71. package/stacks/cloudflare/stack.json +26 -0
  72. package/stacks/i18n-typesafe/skills/i18n-typesafe/SKILL.md +64 -0
  73. package/stacks/i18n-typesafe/stack.json +25 -0
  74. package/stacks/protobuf/skills/protobuf-contracts/SKILL.md +78 -0
  75. package/stacks/protobuf/stack.json +25 -0
  76. package/stacks/rust-wasm/skills/rust-wasm-patterns/SKILL.md +76 -0
  77. package/stacks/rust-wasm/stack.json +26 -0
  78. package/stacks/solidjs/skills/solidjs-patterns/SKILL.md +66 -0
  79. package/stacks/solidjs/stack.json +52 -0
  80. package/stacks/vanilla-extract/skills/vanilla-extract-patterns/SKILL.md +76 -0
  81. package/stacks/vanilla-extract/stack.json +40 -0
  82. package/templates/claude-toolkit.config.ts +34 -0
  83. package/templates/configs/biome.base.json +35 -0
  84. package/templates/configs/tsconfig.base.json +16 -0
  85. package/templates/skill-rules.base.json +98 -0
@@ -0,0 +1,137 @@
1
+ # TypeScript Conventions
2
+
3
+ > Strict TypeScript patterns for type safety, readability, and maintainable codebases.
4
+
5
+ **Type:** Core Skill (always included)
6
+ **Source:** [`core/skills/typescript-conventions/SKILL.md`](../core/skills/typescript-conventions/SKILL.md)
7
+
8
+ ## Overview
9
+
10
+ Rules for writing TypeScript that leverages the type system fully. These assume strict mode is enabled and prioritize catching errors at compile time over runtime.
11
+
12
+ ## Key Patterns
13
+
14
+ ### Strict Mode
15
+
16
+ Enable all strict checks in `tsconfig.json`:
17
+
18
+ ```json
19
+ {
20
+ "compilerOptions": {
21
+ "strict": true,
22
+ "noUncheckedIndexedAccess": true,
23
+ "noUnusedLocals": true,
24
+ "noUnusedParameters": true
25
+ }
26
+ }
27
+ ```
28
+
29
+ Never disable strict checks for convenience.
30
+
31
+ ### No `any`
32
+
33
+ Never use `any`. It disables type checking entirely.
34
+
35
+ - Use `unknown` when the type is genuinely not known, then narrow before use
36
+ - Use generics when the type varies but has a consistent shape
37
+ - Use specific types when you know the data shape
38
+
39
+ ### Interface vs Type
40
+
41
+ - **Prefer `interface`** for object shapes -- extendable, clearer error messages
42
+ - **Use `type`** for unions, intersections, mapped types, and utility types
43
+
44
+ ```typescript
45
+ // Object shape: use interface
46
+ interface User {
47
+ id: string;
48
+ email: string;
49
+ role: UserRole;
50
+ }
51
+
52
+ // Union: use type
53
+ type UserRole = "admin" | "member" | "guest";
54
+ ```
55
+
56
+ ### `as const` for Literal Types
57
+
58
+ Use `as const` to narrow literal values and create readonly tuples:
59
+
60
+ ```typescript
61
+ const ROLES = ["admin", "member", "guest"] as const;
62
+ type Role = (typeof ROLES)[number]; // "admin" | "member" | "guest"
63
+ ```
64
+
65
+ ### Exhaustive Switch with `never`
66
+
67
+ Handle every case in a switch and use `never` to catch missing branches at compile time:
68
+
69
+ ```typescript
70
+ function getPermissions(role: UserRole): string[] {
71
+ switch (role) {
72
+ case "admin":
73
+ return ["read", "write", "delete"];
74
+ case "member":
75
+ return ["read", "write"];
76
+ case "guest":
77
+ return ["read"];
78
+ default: {
79
+ const _exhaustive: never = role;
80
+ throw new Error(`Unhandled role: ${_exhaustive}`);
81
+ }
82
+ }
83
+ }
84
+ ```
85
+
86
+ ### Discriminated Unions for State Modeling
87
+
88
+ Model states with different associated data as discriminated unions to make illegal states unrepresentable:
89
+
90
+ ```typescript
91
+ type AsyncState<T> =
92
+ | { status: "loading" }
93
+ | { status: "success"; data: T }
94
+ | { status: "error"; error: Error };
95
+ ```
96
+
97
+ ### Generic Constraints
98
+
99
+ Use `extends` to constrain generics, documenting expectations and catching misuse:
100
+
101
+ ```typescript
102
+ function findById<T extends { id: string }>(items: T[], id: string): T | undefined {
103
+ return items.find((item) => item.id === id);
104
+ }
105
+ ```
106
+
107
+ ## Anti-patterns
108
+
109
+ | Anti-pattern | Description |
110
+ |---|---|
111
+ | **Type assertions (`as`)** | Tells the compiler "trust me" -- use type guards and narrowing instead. |
112
+ | **Non-null assertion (`!`)** | Suppresses null checks. Handle the null case explicitly. |
113
+ | **Enum overuse** | Prefer string literal unions. Enums generate runtime code and have surprising behavior. |
114
+ | **`Object`, `Function`, `{}`** | Almost never what you want. Use specific interfaces or function signatures. |
115
+ | **`@ts-ignore`** | Suppressing errors without tracking means the error will be forgotten. |
116
+
117
+ ## Best Practices Reference
118
+
119
+ For deeper guidance on the patterns referenced above (sourced from Matt Pocock / Total TypeScript):
120
+
121
+ | Topic | Guide |
122
+ |---|---|
123
+ | Default to `type`, use `interface` for `extends` | [Type vs Interface](../best-practices/typescript/type-vs-interface.md) |
124
+ | Why enums are problematic, `as const` alternative | [Enums & Alternatives](../best-practices/typescript/enums-alternatives.md) |
125
+ | When `any` is acceptable (two exceptions) | [any & unknown](../best-practices/typescript/any-and-unknown.md) |
126
+ | State modeling with discriminated unions | [Discriminated Unions](../best-practices/typescript/discriminated-unions.md) |
127
+ | Three patterns for generics | [Generics Patterns](../best-practices/typescript/generics-patterns.md) |
128
+ | Recommended `tsconfig.json` settings | [TSConfig Cheat Sheet](../best-practices/typescript/tsconfig-cheat-sheet.md) |
129
+ | Branded types, assertion functions, type predicates | [Essential Patterns](../best-practices/typescript/essential-patterns.md) |
130
+
131
+ See the full collection: [TypeScript Best Practices](../best-practices/typescript/README.md)
132
+
133
+ ## Trigger Conditions
134
+
135
+ - **Keywords:** `typescript`, `type`, `interface`, `generic`
136
+ - **File patterns:** `**/*.d.ts`, `**/types/**`
137
+ - **Intent patterns:** "define/create type/interface"
@@ -0,0 +1,91 @@
1
+ # Verification Before Completion
2
+
3
+ > Evidence-based completion claims -- never say "done" without proof that the work is correct.
4
+
5
+ **Type:** Core Skill (always included)
6
+ **Source:** [`core/skills/verification-before-completion/SKILL.md`](../core/skills/verification-before-completion/SKILL.md)
7
+
8
+ ## Overview
9
+
10
+ The most common source of rework is claiming completion without verification. Every "done" claim must be backed by evidence that the code works correctly. "I wrote the code" is not evidence. "The tests pass, the types check, and here is the output" is evidence.
11
+
12
+ ## Verification Checklist
13
+
14
+ ### 1. Tests Pass
15
+
16
+ Run the full test suite (or related tests) and show the output. If any test fails, fix it before claiming complete.
17
+
18
+ ### 2. Type Checks Pass
19
+
20
+ Run the type checker with no errors (`tsc --noEmit` or equivalent). Zero errors, zero warnings on changed files.
21
+
22
+ ### 3. Linting Passes
23
+
24
+ Run the project's linter on changed files. Fix any violations introduced by your changes.
25
+
26
+ ### 4. The Feature Actually Works
27
+
28
+ For user-facing changes, demonstrate the feature works with actual output -- API responses, rendered UI, CLI output:
29
+
30
+ ```
31
+ $ curl -s localhost:3000/api/users/1 | jq .
32
+ {
33
+ "id": "1",
34
+ "name": "Alice",
35
+ "email": "alice@example.com"
36
+ }
37
+ ```
38
+
39
+ ### 5. Edge Cases Verified
40
+
41
+ Test boundaries and unusual inputs explicitly:
42
+
43
+ - **Empty inputs** -- empty strings, empty arrays, null, undefined
44
+ - **Boundary values** -- zero, negative numbers, maximum values, off-by-one
45
+ - **Invalid inputs** -- wrong types, malformed data, missing required fields
46
+ - **Concurrent access** -- simultaneous requests or operations
47
+ - **Error paths** -- network failures, database errors, permission denied
48
+
49
+ ### 6. Regression Check
50
+
51
+ - Run related tests, not just the tests you wrote
52
+ - Check integration points if you changed a shared utility, API contract, or database schema
53
+ - Smoke test the application if it has a running instance
54
+
55
+ ## Evidence Format
56
+
57
+ When reporting completion, include concrete evidence:
58
+
59
+ ```markdown
60
+ ## Completed: User authentication endpoint
61
+
62
+ ### Tests
63
+ - 12 tests passing (3 new, 9 existing)
64
+ - `npm test -- --grep "auth"` output: all green
65
+
66
+ ### Type check
67
+ - `tsc --noEmit`: 0 errors
68
+
69
+ ### Manual verification
70
+ - POST /api/auth/login with valid credentials: 200 + JWT token
71
+ - POST /api/auth/login with wrong password: 401 + error message
72
+ - POST /api/auth/login with locked account: 423 + lockout message
73
+
74
+ ### Edge cases verified
75
+ - Empty email: 400 validation error
76
+ - SQL injection attempt in email: properly escaped, no error
77
+ - Expired token refresh: 401 with clear message
78
+ ```
79
+
80
+ ## What This Prevents
81
+
82
+ - **"It works on my machine" failures** -- evidence shows it works in a verifiable way
83
+ - **Phantom completions** -- tasks marked done that are actually broken
84
+ - **Regression blindness** -- catching breakage before it reaches review or production
85
+ - **Incomplete implementations** -- edge cases and error handling are verified, not assumed
86
+
87
+ ## Trigger Conditions
88
+
89
+ - **Keywords:** `verify`, `check`, `confirm`, `done`, `complete`
90
+ - **Intent patterns:** "is it done", "verify it works"
91
+ - **Context patterns:** "before claiming", "make sure"
@@ -0,0 +1,110 @@
1
+ # Cloudflare D1 and KV Patterns
2
+
3
+ > Cloudflare D1 SQL database and KV cache patterns.
4
+
5
+ **Type:** Stack Skill (requires `cloudflare` stack)
6
+ **Source:** [`stacks/cloudflare/skills/cloudflare-d1-kv/SKILL.md`](../stacks/cloudflare/skills/cloudflare-d1-kv/SKILL.md)
7
+ **Directory Mappings:** `src/db/`, `migrations/`
8
+ **File Extensions:** `.sql`
9
+
10
+ ## Overview
11
+
12
+ D1 is Cloudflare's serverless SQLite database, and KV is an eventually-consistent key-value store. Together they provide primary data storage and read-heavy caching for Workers.
13
+
14
+ ## D1 Database
15
+
16
+ ### Prepared Statements
17
+
18
+ Always use prepared statements with `.bind()` -- never concatenate SQL strings.
19
+
20
+ ```rust
21
+ let stmt = db.prepare("SELECT * FROM users WHERE id = ?1")
22
+ .bind(&[id.into()])?;
23
+ let user = stmt.first::<User>(None).await?;
24
+ ```
25
+
26
+ ### Batch Operations
27
+
28
+ Execute multiple statements in a single round trip. Batch operations are transactional -- all succeed or all fail.
29
+
30
+ ```rust
31
+ let results = db.batch(vec![
32
+ db.prepare("INSERT INTO events ...").bind(&[...])?,
33
+ db.prepare("INSERT INTO event_members ...").bind(&[...])?,
34
+ ]).await?;
35
+ ```
36
+
37
+ ### Migration Workflow
38
+
39
+ ```bash
40
+ wrangler d1 migrations create DB "add_users_table" # Create migration
41
+ wrangler d1 migrations apply DB --local # Apply locally
42
+ wrangler d1 migrations apply DB --remote # Apply to remote
43
+ ```
44
+
45
+ ### Schema Conventions
46
+
47
+ - Use `TEXT` for IDs (UUIDs/nanoids, not auto-increment integers)
48
+ - Use `TEXT` for timestamps in ISO 8601 format
49
+ - Always add `created_at` and `updated_at` columns
50
+ - Create indexes for columns used in WHERE clauses and JOINs
51
+ - Use `IF NOT EXISTS` / `IF EXISTS` for idempotent migrations
52
+ - D1 has a **5MB response size limit** -- always use LIMIT
53
+
54
+ ## KV Namespace
55
+
56
+ ### Read-Through Caching Pattern
57
+
58
+ ```rust
59
+ async fn get_user_cached(kv: &KvStore, db: &D1Database, user_id: &str) -> Result<User> {
60
+ let cache_key = format!("user:{}", user_id);
61
+
62
+ // Try cache first
63
+ if let Some(cached) = kv.get(&cache_key).text().await? {
64
+ if let Ok(user) = serde_json::from_str::<User>(&cached) {
65
+ return Ok(user);
66
+ }
67
+ }
68
+
69
+ // Cache miss -- query DB, then populate cache with TTL
70
+ let user = /* query D1 */;
71
+ kv.put(&cache_key, &json)?.expiration_ttl(3600).execute().await?;
72
+ Ok(user)
73
+ }
74
+ ```
75
+
76
+ ### TTL Strategies
77
+
78
+ | Data Type | TTL | Rationale |
79
+ |---|---|---|
80
+ | User profile | 1 hour | Changes infrequently |
81
+ | Session data | 24 hours | Matches session lifetime |
82
+ | Config/settings | 5 minutes | Needs faster propagation |
83
+ | Public listings | 15 minutes | Balances freshness and load |
84
+
85
+ ### Key Naming Conventions
86
+
87
+ Use colon-separated hierarchical keys:
88
+ ```
89
+ user:{userId}
90
+ user:{userId}:profile
91
+ event:{eventId}
92
+ event:{eventId}:members
93
+ session:{sessionToken}
94
+ cache:feed:{userId}:page:{pageNum}
95
+ ```
96
+
97
+ ### Cache Invalidation
98
+
99
+ Invalidate on write operations by deleting the corresponding cache key after updating D1.
100
+
101
+ ## Anti-patterns
102
+
103
+ | Anti-pattern | Why it's wrong |
104
+ |---|---|
105
+ | **Unbounded queries** | Always use LIMIT. D1 has a 5MB response limit. |
106
+ | **Missing indexes** | D1 is SQLite; without indexes, every query is a full table scan. |
107
+ | **KV as primary data store** | KV is eventually consistent with no query capability. Use D1 for primary data. |
108
+ | **Ignoring batch operations** | Each D1 call is a network round trip. Batch for performance. |
109
+ | **KV cache without TTL** | Stale data without TTL persists indefinitely. |
110
+ | **Not testing migrations locally** | Always apply with `--local` before `--remote`. |
@@ -0,0 +1,141 @@
1
+ # Typesafe-i18n Patterns
2
+
3
+ > Typesafe-i18n internationalization patterns for SolidJS.
4
+
5
+ **Type:** Stack Skill (requires `i18n-typesafe` stack)
6
+ **Source:** [`stacks/i18n-typesafe/skills/i18n-typesafe/SKILL.md`](../stacks/i18n-typesafe/skills/i18n-typesafe/SKILL.md)
7
+ **Directory Mappings:** `src/locales/`, `src/i18n/`
8
+
9
+ ## Overview
10
+
11
+ typesafe-i18n provides fully type-safe translations with autocompletion. Translation keys are checked at compile time -- missing or misspelled keys cause TypeScript errors.
12
+
13
+ ## Setup
14
+
15
+ ### Directory Structure
16
+
17
+ ```text
18
+ src/i18n/
19
+ i18n-types.ts # Auto-generated types
20
+ i18n-util.ts # Auto-generated utilities
21
+ i18n-solid.tsx # SolidJS adapter
22
+ en/index.ts # Base locale (source of truth)
23
+ fr/index.ts # French translations
24
+ ```
25
+
26
+ ### Configuration (`.typesafe-i18n.json`)
27
+
28
+ ```json
29
+ {
30
+ "baseLocale": "en",
31
+ "adapter": "solid",
32
+ "outputPath": "src/i18n/{locale}/"
33
+ }
34
+ ```
35
+
36
+ ### Run the Generator
37
+
38
+ ```bash
39
+ npx typesafe-i18n # Watches base locale and regenerates types
40
+ ```
41
+
42
+ ## Base Locale
43
+
44
+ The base locale is the source of truth. All types are derived from it.
45
+
46
+ ```ts
47
+ // src/i18n/en/index.ts
48
+ const en = {
49
+ common: {
50
+ welcome: 'Welcome, {name:string}!',
51
+ itemCount: '{count:number} {{item|items}}',
52
+ save: 'Save',
53
+ },
54
+ auth: {
55
+ signIn: 'Sign in',
56
+ signOut: 'Sign out',
57
+ },
58
+ } satisfies BaseTranslation;
59
+ ```
60
+
61
+ ## Adding Translations
62
+
63
+ Other locales use the `Translation` type derived from the base locale. Missing keys or wrong parameter types cause compile errors.
64
+
65
+ ```ts
66
+ // src/i18n/fr/index.ts
67
+ const fr = {
68
+ common: {
69
+ welcome: 'Bienvenue, {name} !',
70
+ itemCount: '{count} {{article|articles}}',
71
+ save: 'Enregistrer',
72
+ },
73
+ auth: {
74
+ signIn: 'Se connecter',
75
+ signOut: 'Se deconnecter',
76
+ },
77
+ } satisfies Translation;
78
+ ```
79
+
80
+ ## Usage in Components
81
+
82
+ ```tsx
83
+ const { LL } = useI18nContext();
84
+
85
+ return (
86
+ <div>
87
+ <h1>{LL().events.title()}</h1>
88
+ <span>{LL().events.attendees({ count: event.memberCount })}</span>
89
+ </div>
90
+ );
91
+ ```
92
+
93
+ ### Provider Setup
94
+
95
+ ```tsx
96
+ <I18nProvider locale="en">
97
+ <Router />
98
+ </I18nProvider>
99
+ ```
100
+
101
+ ## Parameterized Translations
102
+
103
+ | Syntax | Example | Description |
104
+ | ------------------------ | ---------------------------- | ------------------------ |
105
+ | `{name:string}` | `'Hello {name:string}'` | Named string parameter |
106
+ | `{count:number}` | `'{count:number} items'` | Named number parameter |
107
+ | `{{singular\|plural}}` | `'{count} {{item\|items}}'` | Plural forms |
108
+ | `{0:string}` | `'Click {0:string}'` | Positional parameter |
109
+
110
+ ## Namespace Organization
111
+
112
+ Organize translations by feature/domain. Keep namespaces flat (one level deep):
113
+
114
+ ```ts
115
+ const en = {
116
+ common: { ... }, // Global
117
+ auth: { ... }, // Authentication
118
+ events: { ... }, // Events feature
119
+ profile: { ... }, // User profile
120
+ settings: { ... }, // Settings
121
+ admin: { ... }, // Admin panel
122
+ };
123
+ ```
124
+
125
+ ## Anti-patterns
126
+
127
+ | Anti-pattern | Why it's wrong |
128
+ | ------------------------------ | ------------------------------------------------------------------------------- |
129
+ | **Hardcoded strings** | Every user-visible string must go through `LL()`. |
130
+ | **Missing translations** | `Translation` type catches these at compile time -- run `tsc --noEmit` in CI. |
131
+ | **Interpolating HTML** | Do not embed HTML in translation strings. Use component composition. |
132
+ | **Dynamic key access** | `LL()[dynamicKey]()` bypasses type safety. Use conditional rendering. |
133
+ | **Forgetting to load locale** | Call `loadLocale()` before rendering. |
134
+ | **Over-splitting namespaces** | Too many small namespaces add overhead. Group by feature, not component. |
135
+
136
+ ## Best Practices Reference
137
+
138
+ | Topic | Guide |
139
+ | ---------------------------------------- | ------------------------------------------------------------------------------- |
140
+ | `satisfies` pattern used in translations | [The satisfies Operator](../best-practices/typescript/satisfies-operator.md) |
141
+ | i18n provider and context pattern | [Context & Global State](../best-practices/solidjs/context-and-global-state.md) |
@@ -0,0 +1,85 @@
1
+ # Protobuf Contracts
2
+
3
+ > Protocol Buffer definitions and code generation for frontend/backend contracts.
4
+
5
+ **Type:** Stack Skill (requires `protobuf` stack)
6
+ **Source:** [`stacks/protobuf/skills/protobuf-contracts/SKILL.md`](../stacks/protobuf/skills/protobuf-contracts/SKILL.md)
7
+ **Directory Mappings:** `proto/`
8
+ **File Extensions:** `.proto`
9
+
10
+ ## Overview
11
+
12
+ Protocol Buffers (proto3) define the API contract between frontend and backend. Protobuf provides compact binary serialization, type safety across languages, and backward-compatible schema evolution.
13
+
14
+ ## Proto3 Conventions
15
+
16
+ - Use **PascalCase** for message names, **snake_case** for field names
17
+ - Fields 1-15 use 1 byte (reserve for frequent fields), 16-2047 use 2 bytes
18
+ - **Never reuse** a field number after removing a field
19
+ - When removing fields, reserve the number AND name
20
+ - Enums must always start with `UNSPECIFIED = 0`
21
+
22
+ ## Message Patterns
23
+
24
+ ### Request/Response Pairs
25
+ ```protobuf
26
+ message GetUserRequest { string user_id = 1; }
27
+ message GetUserResponse { UserProfile user = 1; }
28
+ ```
29
+
30
+ ### Lists with Pagination
31
+ ```protobuf
32
+ message ListEventsRequest {
33
+ int32 page_size = 1;
34
+ string page_token = 2;
35
+ }
36
+ message ListEventsResponse {
37
+ repeated Event events = 1;
38
+ string next_page_token = 2;
39
+ int32 total_count = 3;
40
+ }
41
+ ```
42
+
43
+ ### Service Definitions
44
+ ```protobuf
45
+ service UserService {
46
+ rpc GetUser(GetUserRequest) returns (GetUserResponse);
47
+ rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);
48
+ rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
49
+ }
50
+ ```
51
+
52
+ ## Code Generation
53
+
54
+ | Target | Tool | Command |
55
+ |---|---|---|
56
+ | Frontend (TypeScript) | protoc-gen-ts | `buf generate --template buf.gen.ts.yaml` |
57
+ | Backend (Rust) | prost-build | Via `build.rs` with `prost_build::Config` |
58
+
59
+ ## Buf CLI Commands
60
+
61
+ | Command | Purpose |
62
+ |---|---|
63
+ | `buf lint` | Lint proto files |
64
+ | `buf format -w` | Format in place |
65
+ | `buf breaking --against .git#branch=main` | Check for breaking changes |
66
+ | `buf generate` | Run code generation |
67
+
68
+ ## Versioning Rules
69
+
70
+ 1. **Never remove or renumber fields** -- use `reserved` instead
71
+ 2. **Never change a field type** -- add a new field with the correct type
72
+ 3. **Enum values are forever** -- 0 must always be UNSPECIFIED
73
+ 4. **Adding fields is safe** -- new fields get default values in old clients
74
+ 5. **Run `buf breaking` before merging** -- catch breaking changes in CI
75
+
76
+ ## Anti-patterns
77
+
78
+ | Anti-pattern | Why it's wrong |
79
+ |---|---|
80
+ | **Reusing field numbers** | Causes data corruption. Always reserve removed field numbers. |
81
+ | **Overly nested messages** | Deep nesting hurts readability and evolution. Flatten where practical. |
82
+ | **Missing UNSPECIFIED enum** | Proto3 requires 0 as default. Without UNSPECIFIED, 0 maps to a real value. |
83
+ | **Using proto2 syntax** | Always use proto3 for new projects. |
84
+ | **Skipping buf lint** | Inconsistent naming compounds over time. |
85
+ | **Large messages** | Protobuf is not designed for multi-MB payloads. Use streaming or chunking. |
@@ -0,0 +1,106 @@
1
+ # Rust WASM Patterns
2
+
3
+ > Rust WASM patterns for Cloudflare Workers with worker-rs.
4
+
5
+ **Type:** Stack Skill (requires `rust-wasm` stack)
6
+ **Source:** [`stacks/rust-wasm/skills/rust-wasm-patterns/SKILL.md`](../stacks/rust-wasm/skills/rust-wasm-patterns/SKILL.md)
7
+ **Directory Mappings:** `worker/`, `worker/src/`
8
+ **File Extensions:** `.rs`, `.toml`
9
+
10
+ ## Overview
11
+
12
+ Cloudflare Workers can run Rust compiled to WebAssembly via the `worker` crate (worker-rs). The target is `wasm32-unknown-unknown`. Workers handle HTTP requests at the edge with low latency.
13
+
14
+ ## Project Structure
15
+
16
+ ```
17
+ worker/
18
+ Cargo.toml
19
+ src/
20
+ lib.rs # Entry point with main router
21
+ routes/
22
+ models/
23
+ error.rs # Custom error types
24
+ wrangler.toml # Cloudflare config
25
+ ```
26
+
27
+ ## Key Patterns
28
+
29
+ ### Request Routing
30
+
31
+ ```rust
32
+ #[event(fetch)]
33
+ async fn fetch(req: Request, env: Env, _ctx: Context) -> Result<Response> {
34
+ Router::new()
35
+ .get_async("/api/users/:id", get_user)
36
+ .post_async("/api/users", create_user)
37
+ .run(req, env)
38
+ .await
39
+ }
40
+ ```
41
+
42
+ ### Handler Pattern
43
+
44
+ ```rust
45
+ async fn get_user(req: Request, ctx: RouteContext<()>) -> Result<Response> {
46
+ let id = ctx.param("id")
47
+ .ok_or_else(|| Error::RustError("Missing id parameter".into()))?;
48
+ let db = ctx.env.d1("DB")?;
49
+ // ...
50
+ }
51
+ ```
52
+
53
+ ### Error Handling
54
+
55
+ Define a custom `AppError` enum that converts to `worker::Error`:
56
+
57
+ ```rust
58
+ pub enum AppError {
59
+ NotFound(String),
60
+ BadRequest(String),
61
+ Internal(String),
62
+ Unauthorized,
63
+ }
64
+
65
+ impl From<AppError> for WorkerError { ... }
66
+ ```
67
+
68
+ ### Env Bindings
69
+
70
+ Access Cloudflare services through the `Env` object:
71
+
72
+ | Binding | Access |
73
+ |---|---|
74
+ | D1 Database | `env.d1("DB")?` |
75
+ | KV Namespace | `env.kv("MY_KV")?` |
76
+ | R2 Bucket | `env.bucket("MY_BUCKET")?` |
77
+ | Secrets | `env.secret("API_KEY")?.to_string()` |
78
+ | Variables | `env.var("CONFIG_VAR")?.to_string()` |
79
+
80
+ ### Serde for JSON
81
+
82
+ Use `#[derive(Serialize, Deserialize)]` for request/response types. Parse request bodies with `req.json().await?` and respond with `Response::from_json(&data)`.
83
+
84
+ ## Cargo.toml Essentials
85
+
86
+ ```toml
87
+ [lib]
88
+ crate-type = ["cdylib"]
89
+
90
+ [dependencies]
91
+ worker = "0.4"
92
+ serde = { version = "1", features = ["derive"] }
93
+ serde_json = "1"
94
+ console_error_panic_hook = "0.1"
95
+ ```
96
+
97
+ ## Anti-patterns
98
+
99
+ | Anti-pattern | Why it's wrong |
100
+ |---|---|
101
+ | **Panics in production** | Always use `Result`. `unwrap()` and `expect()` crash the worker. |
102
+ | **Blocking operations** | WASM is single-threaded. All I/O must be `async`. |
103
+ | **Large binary sizes** | Keep dependencies minimal. Target under 1MB compressed. |
104
+ | **Ignoring memory limits** | Workers have 128MB memory. Stream large files, don't buffer. |
105
+ | **Raw SQL string concatenation** | Always use prepared statements with `bind()`. |
106
+ | **Missing CORS headers** | Workers serving APIs must handle OPTIONS preflight requests. |