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
package/src/types.ts ADDED
@@ -0,0 +1,85 @@
1
+ /** Available stack identifiers */
2
+ export type StackName =
3
+ | "solidjs"
4
+ | "vanilla-extract"
5
+ | "rust-wasm"
6
+ | "protobuf"
7
+ | "cloudflare"
8
+ | "i18n-typesafe"
9
+ | (string & {});
10
+
11
+ /** Hook configuration for post-tool-use automation */
12
+ export interface HookConfig {
13
+ /** Formatter command (e.g., "bun run prettier --write") */
14
+ formatter?: string;
15
+ /** Test runner command (e.g., "bun run vitest run") */
16
+ testRunner?: string;
17
+ /** Type checker command (e.g., "bun run tsc --noEmit") */
18
+ typeCheck?: string;
19
+ /** Additional check commands (e.g., ["cargo check --target wasm32-unknown-unknown"]) */
20
+ extraChecks?: string[];
21
+ /** Dependency install command (e.g., "bun install") — inferred from packageManager if omitted */
22
+ installCommand?: string;
23
+ }
24
+
25
+ /** Git workflow configuration */
26
+ export interface GitConfig {
27
+ /** Branch name prefix (e.g., "wq" → "wq/feature-name") */
28
+ branchPrefix?: string;
29
+ /** Branches protected from direct edits */
30
+ protectedBranches?: string[];
31
+ /** Commit format (default: conventional commits) */
32
+ commitFormat?: "conventional" | "freeform";
33
+ }
34
+
35
+ /** Project metadata used in CLAUDE.md generation */
36
+ export interface ProjectInfo {
37
+ /** Project name */
38
+ name?: string;
39
+ /** Short project description */
40
+ description?: string;
41
+ /** Key directories and their purpose */
42
+ directories?: Record<string, string>;
43
+ /** Common dev commands */
44
+ commands?: Record<string, string>;
45
+ }
46
+
47
+ /** Main toolkit configuration */
48
+ export interface ClaudeToolkitConfig {
49
+ /** Stack packs to activate */
50
+ stacks: StackName[];
51
+ /** Package manager to use */
52
+ packageManager: "bun" | "npm" | "pnpm" | "yarn";
53
+ /** Hook automation config */
54
+ hooks?: HookConfig;
55
+ /** Directory → skill mappings (merged with stack defaults) */
56
+ directoryMappings?: Record<string, string>;
57
+ /** Git workflow config */
58
+ git?: GitConfig;
59
+ /** Project info for CLAUDE.md generation */
60
+ project?: ProjectInfo;
61
+ /** Additional custom skills to include (paths relative to project root) */
62
+ customSkills?: string[];
63
+ /** Skills to exclude from core set */
64
+ excludeSkills?: string[];
65
+ /** Whether to scaffold base configs (biome.json, tsconfig.json) on init. Default: true */
66
+ scaffoldConfigs?: boolean;
67
+ }
68
+
69
+ /** Stack pack metadata (loaded from stack.json) */
70
+ export interface StackPack {
71
+ name: string;
72
+ description: string;
73
+ defaultMappings: Record<string, string>;
74
+ fileExtensions: string[];
75
+ hookOverrides?: Partial<HookConfig>;
76
+ }
77
+
78
+ /** Resolved configuration after merging core + stacks + project config */
79
+ export interface ResolvedConfig {
80
+ config: ClaudeToolkitConfig;
81
+ skills: string[];
82
+ directoryMappings: Record<string, string>;
83
+ hooks: HookConfig;
84
+ stacks: StackPack[];
85
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,53 @@
1
+ import { existsSync } from "node:fs";
2
+ import {
3
+ copyFile,
4
+ mkdir,
5
+ readdir,
6
+ readFile,
7
+ writeFile,
8
+ } from "node:fs/promises";
9
+ import { dirname, join } from "node:path";
10
+
11
+ /** Recursively copy a directory */
12
+ export async function copyDir(src: string, dest: string): Promise<void> {
13
+ await mkdir(dest, { recursive: true });
14
+ const entries = await readdir(src, { withFileTypes: true });
15
+ for (const entry of entries) {
16
+ const srcPath = join(src, entry.name);
17
+ const destPath = join(dest, entry.name);
18
+ if (entry.isDirectory()) {
19
+ await copyDir(srcPath, destPath);
20
+ } else {
21
+ await mkdir(dirname(destPath), { recursive: true });
22
+ await copyFile(srcPath, destPath);
23
+ }
24
+ }
25
+ }
26
+
27
+ /** Write a file, creating parent directories as needed */
28
+ export async function writeFileEnsureDir(
29
+ filePath: string,
30
+ content: string,
31
+ ): Promise<void> {
32
+ await mkdir(dirname(filePath), { recursive: true });
33
+ await writeFile(filePath, content, "utf-8");
34
+ }
35
+
36
+ /** Read JSON file with type */
37
+ export async function readJson<T>(filePath: string): Promise<T> {
38
+ const content = await readFile(filePath, "utf-8");
39
+ return JSON.parse(content) as T;
40
+ }
41
+
42
+ /** Check if a path exists */
43
+ export function exists(filePath: string): boolean {
44
+ return existsSync(filePath);
45
+ }
46
+
47
+ /** Simple template replacement: {{key}} → value */
48
+ export function renderTemplate(
49
+ template: string,
50
+ vars: Record<string, string>,
51
+ ): string {
52
+ return template.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] ?? "");
53
+ }
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: ct-cloudflare-d1-kv
3
+ description: Cloudflare D1 SQL database and KV cache patterns
4
+ ---
5
+
6
+ # D1 and KV Patterns
7
+
8
+ ## D1 Conventions
9
+
10
+ Always use prepared statements with `bind()`. Never concatenate SQL.
11
+
12
+ ```rust
13
+ let stmt = db.prepare("SELECT * FROM users WHERE id = ?1").bind(&[id.into()])?;
14
+ let user = stmt.first::<User>(None).await?;
15
+ ```
16
+
17
+ Batch related queries in a single round trip (transactional -- all succeed or all fail):
18
+
19
+ ```rust
20
+ let results = db.batch(vec![
21
+ db.prepare("INSERT INTO events (id, name) VALUES (?1, ?2)").bind(&[id.into(), name.into()])?,
22
+ db.prepare("INSERT INTO event_members (event_id, user_id) VALUES (?1, ?2)").bind(&[id.into(), uid.into()])?,
23
+ ]).await?;
24
+ ```
25
+
26
+ ### Schema Rules
27
+
28
+ - `TEXT` for IDs (UUIDs/nanoids, not auto-increment).
29
+ - `TEXT` for timestamps in ISO 8601.
30
+ - Always add `created_at` and `updated_at` columns.
31
+ - Always index columns used in WHERE/JOIN.
32
+ - Use `IF NOT EXISTS`/`IF EXISTS` for idempotent migrations.
33
+
34
+ ### Migration Workflow
35
+
36
+ ```bash
37
+ wrangler d1 migrations create DB "add_users_table"
38
+ # Edit migrations/0001_add_users_table.sql, then:
39
+ wrangler d1 migrations apply DB --local # test locally first
40
+ wrangler d1 migrations apply DB --remote
41
+ ```
42
+
43
+ ## KV Conventions
44
+
45
+ KV is eventually-consistent. Use for read-heavy caching only, not primary data.
46
+
47
+ ### Read-Through Cache
48
+
49
+ ```rust
50
+ async fn get_cached(kv: &KvStore, db: &D1Database, id: &str) -> Result<User> {
51
+ let key = format!("user:{}", id);
52
+ if let Some(cached) = kv.get(&key).text().await? {
53
+ if let Ok(user) = serde_json::from_str::<User>(&cached) { return Ok(user); }
54
+ }
55
+ let user = db.prepare("SELECT * FROM users WHERE id = ?1")
56
+ .bind(&[id.into()])?.first::<User>(None).await?.ok_or(AppError::NotFound)?;
57
+ kv.put(&key, &serde_json::to_string(&user)?)?.expiration_ttl(3600).execute().await?;
58
+ Ok(user)
59
+ }
60
+ ```
61
+
62
+ Invalidate on writes: `kv.delete(&format!("user:{}", id)).await?;`
63
+
64
+ ### Key Naming
65
+
66
+ Colon-separated hierarchical: `user:{id}`, `user:{id}:profile`, `cache:feed:{uid}:page:{n}`
67
+
68
+ ### TTL Guidelines
69
+
70
+ | Data | TTL | Reason |
71
+ |------|-----|--------|
72
+ | User profile | 1h | Infrequent changes |
73
+ | Session | 24h | Matches session lifetime |
74
+ | Config | 5min | Needs fast propagation |
75
+ | Public listings | 15min | Freshness vs load balance |
76
+
77
+ ## Anti-Patterns
78
+
79
+ 1. **Unbounded queries** -- Always LIMIT. D1 has 5MB response cap.
80
+ 2. **Missing indexes** -- D1 is SQLite; no index = full table scan.
81
+ 3. **KV as primary store** -- Eventually consistent, no queries. Cache only.
82
+ 4. **Skipping batch** -- Each D1 call is a network round trip.
83
+ 5. **KV without TTL** -- Stale data persists indefinitely.
84
+ 6. **Untested migrations** -- Always `--local` before `--remote`.
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "ct-cloudflare-d1-kv",
3
+ "description": "Cloudflare D1 database and KV cache patterns",
4
+ "defaultMappings": {
5
+ "src/db": "ct-cloudflare-d1-kv",
6
+ "migrations": "ct-cloudflare-d1-kv"
7
+ },
8
+ "fileExtensions": ["sql"],
9
+ "skillRules": {
10
+ "ct-cloudflare-d1-kv": {
11
+ "description": "Cloudflare D1 SQL and KV cache patterns",
12
+ "priority": 7,
13
+ "triggers": {
14
+ "keywords": ["d1", "kv", "cloudflare", "wrangler", "database", "cache", "sql", "migration"],
15
+ "keywordPatterns": ["\\bd1\\b", "\\bkv\\b", "\\bwrangler\\b", "\\bmigration\\b"],
16
+ "pathPatterns": ["**/migrations/**", "**/*.sql", "**/db/**", "**/wrangler.toml"],
17
+ "intentPatterns": [
18
+ "(?:create|add|run).*(?:migration|query|table)",
19
+ "(?:cache|store|fetch).*(?:data|value|key)"
20
+ ],
21
+ "contentPatterns": ["D1Database", "KVNamespace", "env\\.DB", "env\\.KV", "prepared\\("]
22
+ },
23
+ "relatedSkills": ["ct-rust-wasm-patterns"]
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,64 @@
1
+ ---
2
+ name: ct-i18n-typesafe
3
+ description: Typesafe-i18n internationalization patterns for SolidJS
4
+ ---
5
+
6
+ # Typesafe-i18n Patterns
7
+
8
+ Fully type-safe translations. Missing/misspelled keys cause TypeScript errors at compile time.
9
+
10
+ ## Base Locale (Source of Truth)
11
+
12
+ All types are derived from the base locale. Other locales implement `Translation` (type-checked against base).
13
+
14
+ ```ts
15
+ // src/i18n/en/index.ts
16
+ const en = {
17
+ common: {
18
+ welcome: 'Welcome, {name:string}!',
19
+ itemCount: '{count:number} {{item|items}}',
20
+ save: 'Save',
21
+ cancel: 'Cancel',
22
+ },
23
+ events: {
24
+ title: 'Events',
25
+ create: 'Create event',
26
+ noEvents: 'No events yet',
27
+ attendees: '{count:number} {{attendee|attendees}}',
28
+ },
29
+ } satisfies BaseTranslation;
30
+ ```
31
+
32
+ Other locales mirror this structure with `satisfies Translation`. Missing keys or wrong param types cause compile errors.
33
+
34
+ ## Usage in Components
35
+
36
+ ```tsx
37
+ const { LL } = useI18nContext();
38
+ // Simple: LL().common.save()
39
+ // Params: LL().common.welcome({ name: 'Alice' })
40
+ // Plural: LL().events.attendees({ count: 3 }) -> "3 attendees"
41
+ ```
42
+
43
+ Wrap app in `<I18nProvider locale="en">` after calling `loadLocale('en')`.
44
+
45
+ ## Plural Rules
46
+
47
+ `{{singular|plural}}` selected by preceding number param. For complex plural languages (e.g. Arabic): `{{one|two|many}}`.
48
+
49
+ ## Parameterized Translations
50
+
51
+ Types are inferred from base locale: `{name:string}`, `{count:number}`. TypeScript enforces correct params at call sites.
52
+
53
+ ## Organization
54
+
55
+ Organize by feature (common, auth, events), one level deep. Avoid deep nesting -- it makes keys verbose.
56
+
57
+ ## Anti-Patterns
58
+
59
+ 1. **Hardcoded strings** -- Every user-visible string goes through `LL()`.
60
+ 2. **Missing translations** -- Caught at compile time, but only if `tsc --noEmit` runs in CI.
61
+ 3. **HTML in translations** -- Use component composition instead.
62
+ 4. **Dynamic key access** -- `LL()[dynamicKey]()` bypasses type safety. Use conditional rendering.
63
+ 5. **Forgetting loadLocale** -- Must call before rendering or get runtime errors.
64
+ 6. **Over-splitting namespaces** -- Group by feature, not by component.
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "ct-i18n-typesafe",
3
+ "description": "Typesafe internationalization with typesafe-i18n",
4
+ "defaultMappings": {
5
+ "src/locales": "ct-i18n-typesafe",
6
+ "src/i18n": "ct-i18n-typesafe"
7
+ },
8
+ "fileExtensions": [],
9
+ "skillRules": {
10
+ "ct-i18n-typesafe": {
11
+ "description": "Typesafe-i18n internationalization patterns",
12
+ "priority": 6,
13
+ "triggers": {
14
+ "keywords": ["i18n", "translation", "locale", "typesafe-i18n", "localization", "translate"],
15
+ "keywordPatterns": ["\\bi18n\\b", "\\blocale\\b", "\\btranslat"],
16
+ "pathPatterns": ["**/locales/**", "**/i18n/**"],
17
+ "intentPatterns": [
18
+ "(?:add|create).*(?:translation|text|locale)",
19
+ "(?:translat).*(?:key|string)"
20
+ ],
21
+ "contentPatterns": ["useI18nContext", "LL\\.", "baseLocale", "Locales"]
22
+ }
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,78 @@
1
+ ---
2
+ name: ct-protobuf-contracts
3
+ description: Protocol Buffer definitions and code generation for frontend/backend contracts
4
+ ---
5
+
6
+ # Protobuf Contracts
7
+
8
+ Proto3 contracts between frontend (TypeScript via protoc-gen-ts) and backend (Rust via prost).
9
+
10
+ ## Conventions
11
+
12
+ - PascalCase messages, snake_case fields.
13
+ - Fields 1-15 cost 1 byte -- reserve for frequent fields.
14
+ - Enums always start with `UNSPECIFIED = 0`.
15
+ - Package with versioning: `package myapp.v1;`
16
+
17
+ ## Message Patterns
18
+
19
+ ```protobuf
20
+ message UserProfile {
21
+ string id = 1;
22
+ string email = 2;
23
+ string display_name = 3;
24
+ optional string avatar_url = 4;
25
+ }
26
+
27
+ // Request/Response pairs
28
+ message GetUserRequest { string user_id = 1; }
29
+ message GetUserResponse { UserProfile user = 1; }
30
+
31
+ // Pagination
32
+ message ListEventsRequest { int32 page_size = 1; string page_token = 2; }
33
+ message ListEventsResponse { repeated Event events = 1; string next_page_token = 2; int32 total_count = 3; }
34
+
35
+ // Reserved fields -- never reuse removed field numbers
36
+ message Event {
37
+ reserved 3, 8;
38
+ reserved "old_field";
39
+ string id = 1;
40
+ string name = 2;
41
+ }
42
+ ```
43
+
44
+ ## Service Definitions
45
+
46
+ ```protobuf
47
+ service UserService {
48
+ rpc GetUser(GetUserRequest) returns (GetUserResponse);
49
+ rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);
50
+ rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
51
+ }
52
+ ```
53
+
54
+ ## Code Generation
55
+
56
+ Frontend: `buf generate --template buf.gen.ts.yaml`
57
+ Backend (build.rs):
58
+ ```rust
59
+ prost_build::Config::new()
60
+ .type_attribute(".", "#[derive(serde::Serialize, serde::Deserialize)]")
61
+ .compile_protos(&["proto/user.proto"], &["proto/"])?;
62
+ ```
63
+
64
+ ## Versioning Rules
65
+
66
+ - Never remove/renumber fields -- use `reserved`.
67
+ - Never change field types -- add a new field.
68
+ - Adding fields and enum values is safe.
69
+ - Run `buf breaking --against .git#branch=main` before merging.
70
+
71
+ ## Anti-Patterns
72
+
73
+ 1. **Reusing field numbers** -- Causes data corruption. Always reserve removed numbers.
74
+ 2. **Deep nesting** -- Hurts readability and evolution. Flatten where practical.
75
+ 3. **Missing UNSPECIFIED** -- Proto3 default is 0; without UNSPECIFIED it maps to a real value.
76
+ 4. **Proto2 syntax** -- Always proto3 for new projects.
77
+ 5. **Skipping buf lint** -- Inconsistent naming compounds. Lint early.
78
+ 6. **Large messages** -- Not for multi-MB payloads. Use streaming/chunking.
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "ct-protobuf-contracts",
3
+ "description": "Protobuf contracts between frontend and backend",
4
+ "defaultMappings": {
5
+ "proto": "ct-protobuf-contracts"
6
+ },
7
+ "fileExtensions": ["proto"],
8
+ "skillRules": {
9
+ "ct-protobuf-contracts": {
10
+ "description": "Protocol Buffer definitions and code generation",
11
+ "priority": 8,
12
+ "triggers": {
13
+ "keywords": ["protobuf", "proto", "protocol buffer", "grpc", "prost", "protoc", "buf"],
14
+ "keywordPatterns": ["\\bproto\\b", "\\bprotobuf\\b", "\\bprost\\b", "\\bbuf\\b"],
15
+ "pathPatterns": ["**/*.proto", "**/proto/**", "**/*.pb.ts"],
16
+ "intentPatterns": [
17
+ "(?:define|create|add).*(?:message|service|rpc|contract)",
18
+ "(?:proto|protobuf).*(?:schema|type|definition)"
19
+ ],
20
+ "contentPatterns": ["syntax.*proto3", "message\\s+\\w+", "service\\s+\\w+", "rpc\\s+\\w+"]
21
+ },
22
+ "relatedSkills": ["ct-rust-wasm-patterns"]
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,76 @@
1
+ ---
2
+ name: ct-rust-wasm-patterns
3
+ description: Rust WASM patterns for Cloudflare Workers with worker-rs
4
+ ---
5
+
6
+ # Rust WASM Patterns (Cloudflare Workers)
7
+
8
+ Target: `wasm32-unknown-unknown`. Crate type: `cdylib`. Always set `console_error_panic_hook`.
9
+
10
+ ## Routing and Handlers
11
+
12
+ ```rust
13
+ #[event(fetch)]
14
+ async fn fetch(req: Request, env: Env, _ctx: Context) -> Result<Response> {
15
+ console_error_panic_hook::set_once();
16
+ Router::new()
17
+ .get_async("/api/users/:id", get_user)
18
+ .post_async("/api/users", create_user)
19
+ .run(req, env).await
20
+ }
21
+
22
+ async fn get_user(req: Request, ctx: RouteContext<()>) -> Result<Response> {
23
+ let id = ctx.param("id").ok_or_else(|| Error::RustError("Missing id".into()))?;
24
+ let db = ctx.env.d1("DB")?;
25
+ match db.prepare("SELECT * FROM users WHERE id = ?1").bind(&[id.into()])?.first::<User>(None).await? {
26
+ Some(user) => Response::from_json(&user),
27
+ None => Response::error("Not found", 404),
28
+ }
29
+ }
30
+ ```
31
+
32
+ ## Error Handling
33
+
34
+ Define a custom error type converting to `worker::Error`:
35
+
36
+ ```rust
37
+ #[derive(Debug)]
38
+ pub enum AppError { NotFound(String), BadRequest(String), Internal(String), Unauthorized }
39
+
40
+ impl From<AppError> for worker::Error {
41
+ fn from(e: AppError) -> Self { worker::Error::RustError(format!("{:?}", e)) }
42
+ }
43
+ ```
44
+
45
+ ## Env Bindings
46
+
47
+ ```rust
48
+ let db = env.d1("DB")?; // D1
49
+ let kv = env.kv("MY_KV")?; // KV
50
+ let bucket = env.bucket("MY_BUCKET")?; // R2
51
+ let key = env.secret("API_KEY")?.to_string(); // Secrets
52
+ let val = env.var("CONFIG_VAR")?.to_string(); // Vars
53
+ ```
54
+
55
+ ## Serde Conventions
56
+
57
+ ```rust
58
+ #[derive(Serialize, Deserialize, Debug)]
59
+ pub struct User {
60
+ pub id: String,
61
+ pub email: String,
62
+ #[serde(skip_serializing_if = "Option::is_none")]
63
+ pub avatar_url: Option<String>,
64
+ }
65
+ ```
66
+
67
+ Parse body: `let body: CreateUserRequest = req.json().await?;`
68
+
69
+ ## Anti-Patterns
70
+
71
+ 1. **Panics in production** -- Always `Result`, never `unwrap()`/`expect()`.
72
+ 2. **Blocking ops** -- WASM is single-threaded. All I/O must be `async`.
73
+ 3. **Large binaries** -- Minimal deps, use `wasm-opt`, target <1MB compressed.
74
+ 4. **Buffering large files** -- 128MB memory limit. Stream, don't buffer.
75
+ 5. **Raw SQL concatenation** -- Always `bind()` prepared statements.
76
+ 6. **Missing CORS** -- Handle OPTIONS preflight for API workers.
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "ct-rust-wasm-patterns",
3
+ "description": "Rust WASM for Cloudflare Workers with worker-rs",
4
+ "defaultMappings": {
5
+ "worker": "ct-rust-wasm-patterns",
6
+ "worker/src": "ct-rust-wasm-patterns"
7
+ },
8
+ "fileExtensions": ["rs", "toml"],
9
+ "skillRules": {
10
+ "ct-rust-wasm-patterns": {
11
+ "description": "Rust WASM patterns for Cloudflare Workers",
12
+ "priority": 8,
13
+ "triggers": {
14
+ "keywords": ["rust", "wasm", "worker", "cargo", "wasm-bindgen", "worker-rs", "wrangler"],
15
+ "keywordPatterns": ["\\brust\\b", "\\bwasm\\b", "\\bcargo\\b", "\\bworker\\b"],
16
+ "pathPatterns": ["**/*.rs", "**/Cargo.toml", "**/worker/**"],
17
+ "intentPatterns": [
18
+ "(?:create|build|add).*(?:endpoint|route|handler|worker)",
19
+ "(?:rust|wasm).*(?:function|module|binding)"
20
+ ],
21
+ "contentPatterns": ["worker::.*", "wasm_bindgen", "pub async fn", "Result<", "#\\[worker::"]
22
+ },
23
+ "relatedSkills": ["ct-protobuf-contracts", "ct-cloudflare-d1-kv"]
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,66 @@
1
+ ---
2
+ name: ct-solidjs-patterns
3
+ description: SolidJS reactivity, signals, effects, and component patterns
4
+ ---
5
+
6
+ # SolidJS Patterns
7
+
8
+ Components run **once**. Only reactive expressions re-execute. This is not React.
9
+
10
+ ## Primitives
11
+
12
+ ```tsx
13
+ const [count, setCount] = createSignal(0); // always call: count()
14
+ const doubled = createMemo(() => count() * 2); // cached derived value
15
+ createEffect(() => console.log(count())); // side effect on change
16
+ const [data] = createResource(userId, fetchUser); // async: data(), data.loading, data.error
17
+ ```
18
+
19
+ ## Control Flow
20
+
21
+ ```tsx
22
+ <Show when={ok()} fallback={<Fallback />}><Content /></Show>
23
+ <For each={items()}>{(item, i) => <div>{item.name} at {i()}</div>}</For>
24
+ <Switch fallback={<Default />}>
25
+ <Match when={state() === "loading"}><Spinner /></Match>
26
+ <Match when={state() === "error"}><Error /></Match>
27
+ </Switch>
28
+ ```
29
+
30
+ ## Props
31
+
32
+ **CRITICAL: Never destructure props.** Destructuring breaks reactivity.
33
+
34
+ ```tsx
35
+ // WRONG -- reads once, never updates
36
+ const Comp = ({ name }) => <div>{name}</div>;
37
+
38
+ // CORRECT
39
+ const Comp = (props) => <div>{props.name}</div>;
40
+ ```
41
+
42
+ `mergeProps` for defaults, `splitProps` to separate groups:
43
+
44
+ ```tsx
45
+ const merged = mergeProps({ color: "blue" }, props);
46
+ const [local, others] = splitProps(props, ["class", "style"]);
47
+ ```
48
+
49
+ ## Stores
50
+
51
+ `createStore` for deep nested state with path-based updates:
52
+
53
+ ```tsx
54
+ const [state, setState] = createStore({ user: { settings: { theme: "dark" } } });
55
+ setState("user", "settings", "theme", "light");
56
+ setState("items", items => [...items, newItem]);
57
+ ```
58
+
59
+ ## Anti-Patterns
60
+
61
+ 1. **Destructuring props** -- Breaks reactivity. Always `props.x`.
62
+ 2. **createEffect for derived values** -- Use `createMemo` instead.
63
+ 3. **Treating it like React** -- No re-render cycle. Only reactive expressions update.
64
+ 4. **Manual keys in For** -- `<For>` is keyed by reference automatically.
65
+ 5. **Signals outside reactive context** -- `count()` at top level captures once. Wrap in JSX or effects.
66
+ 6. **Forgetting to call signals** -- `count` is a getter, `count()` is the value.
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "ct-solidjs-patterns",
3
+ "description": "SolidJS reactivity, components, and resource patterns",
4
+ "defaultMappings": {
5
+ "src/components": "ct-solidjs-patterns",
6
+ "src/hooks": "ct-solidjs-patterns",
7
+ "src/pages": "ct-solidjs-patterns"
8
+ },
9
+ "fileExtensions": ["tsx", "jsx"],
10
+ "skillRules": {
11
+ "ct-solidjs-patterns": {
12
+ "description": "SolidJS reactivity, signals, effects, and component patterns",
13
+ "priority": 8,
14
+ "triggers": {
15
+ "keywords": [
16
+ "solid",
17
+ "solidjs",
18
+ "signal",
19
+ "createSignal",
20
+ "createEffect",
21
+ "createMemo",
22
+ "createResource",
23
+ "Show",
24
+ "For",
25
+ "Switch",
26
+ "Match"
27
+ ],
28
+ "keywordPatterns": [
29
+ "\\bcreateSignal\\b",
30
+ "\\bcreateEffect\\b",
31
+ "\\bcreateResource\\b",
32
+ "\\bSolid\\b"
33
+ ],
34
+ "pathPatterns": ["**/*.tsx", "**/*.jsx", "**/components/**"],
35
+ "intentPatterns": [
36
+ "(?:create|build|add).*(?:component|page|view)",
37
+ "(?:reactive|signal|effect|memo)"
38
+ ],
39
+ "contentPatterns": [
40
+ "createSignal",
41
+ "createEffect",
42
+ "createMemo",
43
+ "createResource",
44
+ "<Show",
45
+ "<For",
46
+ "<Switch"
47
+ ]
48
+ },
49
+ "relatedSkills": ["ct-vanilla-extract-patterns", "ct-testing-patterns"]
50
+ }
51
+ }
52
+ }