claude-toolkit 0.15.0 → 0.17.0-rc.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.
Files changed (70) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +55 -14
  3. package/bin/cli.ts +75 -19
  4. package/core/skills/ct-typescript-conventions/SKILL.md +59 -1
  5. package/package.json +6 -7
  6. package/src/generator.ts +66 -27
  7. package/src/refresh-hint.ts +95 -0
  8. package/templates/skill-rules.base.json +29 -6
  9. package/bin/postinstall.mjs +0 -69
  10. package/docs/README.md +0 -59
  11. package/docs/agents/code-reviewer.md +0 -76
  12. package/docs/agents/github-workflow.md +0 -98
  13. package/docs/best-practices/capacitor/README.md +0 -64
  14. package/docs/best-practices/capacitor/capacitor-8.md +0 -60
  15. package/docs/best-practices/capacitor/capgo-setup.md +0 -151
  16. package/docs/best-practices/capacitor/channels-and-rollouts.md +0 -101
  17. package/docs/best-practices/capacitor/live-updates-ota.md +0 -75
  18. package/docs/best-practices/capacitor/security-encryption.md +0 -68
  19. package/docs/best-practices/solidjs/README.md +0 -43
  20. package/docs/best-practices/solidjs/anti-patterns.md +0 -166
  21. package/docs/best-practices/solidjs/component-patterns.md +0 -131
  22. package/docs/best-practices/solidjs/context-and-global-state.md +0 -131
  23. package/docs/best-practices/solidjs/control-flow.md +0 -124
  24. package/docs/best-practices/solidjs/data-fetching.md +0 -205
  25. package/docs/best-practices/solidjs/effects-and-lifecycle.md +0 -113
  26. package/docs/best-practices/solidjs/performance.md +0 -100
  27. package/docs/best-practices/solidjs/props-patterns.md +0 -100
  28. package/docs/best-practices/solidjs/reactivity-model.md +0 -104
  29. package/docs/best-practices/solidjs/signals-and-state.md +0 -78
  30. package/docs/best-practices/solidjs/stores-and-nested-state.md +0 -111
  31. package/docs/best-practices/solidjs/typescript-integration.md +0 -186
  32. package/docs/best-practices/testing/README.md +0 -84
  33. package/docs/best-practices/testing/playwright-e2e.md +0 -649
  34. package/docs/best-practices/testing/storybook-interaction.md +0 -455
  35. package/docs/best-practices/testing/vitest-unit.md +0 -451
  36. package/docs/best-practices/typescript/README.md +0 -45
  37. package/docs/best-practices/typescript/any-and-unknown.md +0 -73
  38. package/docs/best-practices/typescript/deriving-vs-decoupling.md +0 -83
  39. package/docs/best-practices/typescript/discriminated-unions.md +0 -75
  40. package/docs/best-practices/typescript/enums-alternatives.md +0 -72
  41. package/docs/best-practices/typescript/essential-patterns.md +0 -119
  42. package/docs/best-practices/typescript/generics-patterns.md +0 -105
  43. package/docs/best-practices/typescript/micro-opinions.md +0 -87
  44. package/docs/best-practices/typescript/runtime-validation.md +0 -62
  45. package/docs/best-practices/typescript/satisfies-operator.md +0 -100
  46. package/docs/best-practices/typescript/tsconfig-cheat-sheet.md +0 -129
  47. package/docs/best-practices/typescript/type-organization.md +0 -64
  48. package/docs/best-practices/typescript/type-vs-interface.md +0 -80
  49. package/docs/commands/code-quality.md +0 -36
  50. package/docs/commands/onboard.md +0 -63
  51. package/docs/commands/pr-review.md +0 -91
  52. package/docs/commands/pr-summary.md +0 -50
  53. package/docs/commands/proto-check.md +0 -59
  54. package/docs/commands/ticket.md +0 -56
  55. package/docs/skills/code-style.md +0 -26
  56. package/docs/skills/systematic-debugging.md +0 -70
  57. package/docs/skills/testing-patterns.md +0 -140
  58. package/docs/skills/typescript-conventions.md +0 -191
  59. package/docs/skills/verification-before-completion.md +0 -103
  60. package/docs/stacks/capacitor-ota.md +0 -145
  61. package/docs/stacks/cloudflare-d1-kv.md +0 -144
  62. package/docs/stacks/esnext-idioms.md +0 -25
  63. package/docs/stacks/i18n-typesafe.md +0 -141
  64. package/docs/stacks/playwright-patterns.md +0 -179
  65. package/docs/stacks/protobuf-contracts.md +0 -85
  66. package/docs/stacks/rust-wasm-patterns.md +0 -106
  67. package/docs/stacks/solidjs-patterns.md +0 -110
  68. package/docs/stacks/storybook-patterns.md +0 -177
  69. package/docs/stacks/vanilla-extract-patterns.md +0 -115
  70. package/docs/stacks/vite-vitest-patterns.md +0 -485
@@ -0,0 +1,95 @@
1
+ /**
2
+ * The "keep .claude/ in sync" hint printed after a bare CLI run. The toolkit never
3
+ * edits the consumer's package.json (a committed file); it only says what to add.
4
+ * Wording rule: no URLs and no filename literals with a TLD-like extension, since
5
+ * Socket's URL-strings detector reads both as links.
6
+ */
7
+
8
+ /** Script body a consumer adds. `|| exit 0` keeps an install working when bun is missing. */
9
+ export const REFRESH_COMMAND = "claude-toolkit refresh || exit 0";
10
+ /** Script name suggested when the lifecycle script already exists. */
11
+ export const REFRESH_SCRIPT_NAME = "claude-toolkit:refresh";
12
+ /** First release that no longer regenerates .claude/ from a dependency install script. */
13
+ export const INSTALL_SCRIPT_REMOVED_IN = "0.17.0";
14
+
15
+ export type PackageManager = "bun" | "npm" | "pnpm" | "yarn";
16
+
17
+ export interface RefreshHintInput {
18
+ /** `scripts` from the project's package.json ({} when it has none). */
19
+ scripts: Record<string, unknown>;
20
+ /** `packageManager` from the toolkit config. */
21
+ packageManager: PackageManager;
22
+ /** True when the project uses Yarn 2+ (a `.yarnrc.yml` exists). */
23
+ yarnBerry: boolean;
24
+ /** `.claude/.toolkit-version` as it was before this run, or null. */
25
+ previousVersion: string | null;
26
+ }
27
+
28
+ /**
29
+ * When each package manager runs the project's own root lifecycle scripts, verified
30
+ * 2026-09-28 with a root project whose `prepare` and `postinstall` append to a file:
31
+ * bun 1.3.11 prepare on install, add and update
32
+ * npm 10.9.3, 11.20.0, 12.1.0 prepare on a plain install only (not install <pkg>, not update)
33
+ * pnpm 10.34.5, 11.28.0, 12.6.0 prepare on install and update, not on add
34
+ * Yarn 4.18.1 never prepare; postinstall whenever the dependency tree changes
35
+ */
36
+ const CAVEATS: Record<PackageManager | "yarn-berry", string | null> = {
37
+ bun: null,
38
+ npm: 'npm runs "prepare" only on a plain "npm install"; after "npm install <pkg>" or "npm update", run "bunx claude-toolkit refresh".',
39
+ pnpm: 'pnpm skips "prepare" on "pnpm add"; after upgrading claude-toolkit that way, run "bunx claude-toolkit refresh".',
40
+ yarn: null,
41
+ "yarn-berry":
42
+ 'Yarn 2+ never runs "prepare" for your own project; "postinstall" runs whenever your dependencies change.',
43
+ };
44
+
45
+ /** Compare x.y.z numerically. A prerelease counts as its release: 0.17.0-rc.0 is not before 0.17.0. */
46
+ export function isBefore(version: string, floor: string): boolean {
47
+ const parts = (v: string) =>
48
+ (v.split("-")[0] ?? "").split(".").map((n) => Number.parseInt(n, 10) || 0);
49
+ const a = parts(version);
50
+ const b = parts(floor);
51
+ for (let i = 0; i < 3; i++) {
52
+ const x = a[i] ?? 0;
53
+ const y = b[i] ?? 0;
54
+ if (x !== y) return x < y;
55
+ }
56
+ return false;
57
+ }
58
+
59
+ /** True when some package.json script already runs `claude-toolkit refresh`. */
60
+ export function hasRefreshScript(scripts: Record<string, unknown>): boolean {
61
+ return Object.values(scripts).some(
62
+ (s) => typeof s === "string" && s.includes("claude-toolkit refresh"),
63
+ );
64
+ }
65
+
66
+ /** Lines of the hint, or [] when a script already runs `claude-toolkit refresh`. */
67
+ export function buildRefreshHint(input: RefreshHintInput): string[] {
68
+ const { scripts, packageManager, yarnBerry, previousVersion } = input;
69
+ const lifecycle = yarnBerry ? "postinstall" : "prepare";
70
+ // Yarn 2+ never runs "prepare", so only a refresh reachable from "postinstall" counts there.
71
+ const satisfied = yarnBerry
72
+ ? /claude-toolkit[ :]refresh/.test(String(scripts.postinstall ?? ""))
73
+ : hasRefreshScript(scripts);
74
+ if (satisfied) return [];
75
+
76
+ const runner = yarnBerry ? "yarn" : packageManager;
77
+ const lines: string[] = [];
78
+ if (previousVersion !== null && isBefore(previousVersion, INSTALL_SCRIPT_REMOVED_IN)) {
79
+ lines.push(
80
+ `Automatic regeneration on install was removed in ${INSTALL_SCRIPT_REMOVED_IN} (it relied on a dependency install script).`,
81
+ );
82
+ }
83
+ lines.push('Keep .claude/ in sync after toolkit upgrades — add to your package.json "scripts":');
84
+ if (scripts[lifecycle] === undefined) {
85
+ lines.push(` "${lifecycle}": "${REFRESH_COMMAND}"`);
86
+ } else {
87
+ lines.push(` "${REFRESH_SCRIPT_NAME}": "${REFRESH_COMMAND}"`);
88
+ lines.push(
89
+ `and append "&& ${runner} run ${REFRESH_SCRIPT_NAME}" to your existing "${lifecycle}" script.`,
90
+ );
91
+ }
92
+ const caveat = CAVEATS[yarnBerry ? "yarn-berry" : packageManager];
93
+ if (caveat !== null) lines.push(caveat);
94
+ return lines;
95
+ }
@@ -43,14 +43,37 @@
43
43
  }
44
44
  },
45
45
  "ct-typescript-conventions": {
46
- "description": "TypeScript strict mode and conventions",
46
+ "description": "TypeScript strict mode, conventions, and TS7 compiler selection",
47
47
  "priority": 5,
48
48
  "triggers": {
49
- "keywords": ["typescript", "type", "interface", "generic", "strict mode"],
50
- "keywordPatterns": ["\\btype\\b", "\\binterface\\b", "\\bgeneric\\b"],
51
- "pathPatterns": ["**/*.d.ts", "**/types/**", "**/types.ts"],
52
- "intentPatterns": ["(?:define|create).*(?:type|interface)", "(?:type).*(?:error|issue)"],
53
- "contentPatterns": ["interface ", "type ", ": unknown", "as const"]
49
+ "keywords": [
50
+ "typescript",
51
+ "type",
52
+ "interface",
53
+ "generic",
54
+ "strict mode",
55
+ "tsc",
56
+ "tsgo",
57
+ "tsconfig",
58
+ "typecheck",
59
+ "compiler"
60
+ ],
61
+ "keywordPatterns": [
62
+ "\\btype\\b",
63
+ "\\binterface\\b",
64
+ "\\bgeneric\\b",
65
+ "\\btsc\\b",
66
+ "\\btsconfig\\b",
67
+ "\\bts\\s?7\\b"
68
+ ],
69
+ "pathPatterns": ["**/*.d.ts", "**/types/**", "**/types.ts", "**/tsconfig*.json"],
70
+ "intentPatterns": [
71
+ "(?:define|create).*(?:type|interface)",
72
+ "(?:type).*(?:error|issue)",
73
+ "(?:run|fix).*type.?check",
74
+ "(?:upgrade|migrate|update).*typescript"
75
+ ],
76
+ "contentPatterns": ["interface ", "type ", ": unknown", "as const", "compilerOptions"]
54
77
  },
55
78
  "excludePatterns": ["issue type", "type of bug"]
56
79
  },
@@ -1,69 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * claude-toolkit postinstall
5
- *
6
- * Runs in the consumer project after install. If a claude-toolkit.config.ts
7
- * exists, it regenerates .claude/ — but only when the installed toolkit version
8
- * differs from the one that last generated it, so it fires on a toolkit update,
9
- * not on every install.
10
- *
11
- * Guarantees:
12
- * - Never fails the consumer's install (all errors swallowed; always exit 0).
13
- * - Never runs inside the toolkit's own repo (dev install).
14
- * - Never creates or edits the committed config — only regenerates .claude/.
15
- * - Writes no committed files when there's no config (prints a one-line nudge).
16
- */
17
-
18
- import { spawnSync } from "node:child_process";
19
- import { existsSync, readFileSync } from "node:fs";
20
- import { dirname, join, resolve } from "node:path";
21
- import { fileURLToPath } from "node:url";
22
-
23
- function readJsonSafe(path) {
24
- try {
25
- return JSON.parse(readFileSync(path, "utf8"));
26
- } catch {
27
- return null;
28
- }
29
- }
30
-
31
- try {
32
- const toolkitDir = resolve(dirname(fileURLToPath(import.meta.url)), "..");
33
- // INIT_CWD is set by npm/bun/pnpm/yarn to the dir where install was invoked.
34
- const consumerRoot = resolve(process.env.INIT_CWD || process.cwd());
35
-
36
- // 1. Skip when running inside the toolkit's own repo (dev install).
37
- if (consumerRoot === toolkitDir) process.exit(0);
38
- const consumerPkg = readJsonSafe(join(consumerRoot, "package.json"));
39
- if (consumerPkg?.name === "claude-toolkit") process.exit(0);
40
-
41
- // 2. No config -> stay hands-off; just nudge once. Never write committed files.
42
- const hasConfig =
43
- existsSync(join(consumerRoot, "claude-toolkit.config.ts")) ||
44
- existsSync(join(consumerRoot, "claude-toolkit.config.js"));
45
- if (!hasConfig) {
46
- console.log(
47
- '[claude-toolkit] Run "bunx claude-toolkit" to set up your Claude Code config (.claude/).',
48
- );
49
- process.exit(0);
50
- }
51
-
52
- // 3. Only regenerate when the toolkit version changed since the last generation.
53
- const toolkitVersion = readJsonSafe(join(toolkitDir, "package.json"))?.version;
54
- const markerPath = join(consumerRoot, ".claude", ".toolkit-version");
55
- const lastVersion = existsSync(markerPath) ? readFileSync(markerPath, "utf8").trim() : null;
56
- if (toolkitVersion && lastVersion === toolkitVersion) process.exit(0);
57
-
58
- // 4. Regenerate via the CLI (reuses config loading + clean rebuild). Best-effort:
59
- // spawnSync sets `.error` if bun is missing — we ignore it rather than fail.
60
- spawnSync("bun", [join(toolkitDir, "bin", "cli.ts"), "postinstall"], {
61
- cwd: consumerRoot,
62
- stdio: "inherit",
63
- env: { ...process.env, INIT_CWD: consumerRoot },
64
- });
65
- } catch {
66
- // Never break the consumer's install over config regeneration.
67
- }
68
-
69
- process.exit(0);
package/docs/README.md DELETED
@@ -1,59 +0,0 @@
1
- # claude-toolkit Documentation
2
-
3
- Complete reference for all skills, commands, and agents provided by claude-toolkit.
4
-
5
- ## Setup
6
-
7
- Run `bunx claude-toolkit` in your project — on the first run it creates `claude-toolkit.config.ts` (pre-filled from stack detection) and generates `.claude/`. Run it again anytime to regenerate; add `--update` to pull newly-detected stacks into the config. `.claude/` also regenerates automatically on install when the toolkit version changes. See the [README](../README.md#cli-commands) for the full CLI.
8
-
9
- ## Core Skills
10
-
11
- Skills that are always included regardless of stack configuration.
12
-
13
- | Skill | Description |
14
- | -------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
15
- | [ct-systematic-debugging](skills/systematic-debugging.md) | Four-phase methodology for diagnosing and fixing bugs without guesswork |
16
- | [ct-testing-patterns](skills/testing-patterns.md) | Framework-agnostic TDD practices, mocking strategies, and test organization |
17
- | [ct-typescript-conventions](skills/typescript-conventions.md) | Strict TypeScript patterns for type safety and maintainability |
18
- | [ct-verification-before-completion](skills/verification-before-completion.md) | Evidence-based completion claims with structured verification checklist |
19
- | [ct-code-style](skills/code-style.md) | Code structure & style: guard clauses, lookup tables, no magic values |
20
-
21
- ## Commands
22
-
23
- Slash commands available in Claude Code sessions.
24
-
25
- | Command | Description |
26
- | ----------------------------------------- | -------------------------------------------------------------------------- |
27
- | [/ct:code-quality](commands/code-quality.md) | Run lint, typecheck, and format checks with structured reporting |
28
- | [/ct:pr-review](commands/pr-review.md) | Checklist-based code review against project standards |
29
- | [/ct:pr-summary](commands/pr-summary.md) | Generate a structured PR summary from branch diff and commits |
30
- | [/ct:onboard](commands/onboard.md) | Systematically explore and understand a codebase area |
31
- | [/ct:ticket](commands/ticket.md) | Work end-to-end on a ticket: understand, explore, plan, implement, deliver |
32
- | [/ct:proto-check](commands/proto-check.md) | Validate protobuf definitions, lint, breaking changes, and code generation |
33
-
34
- ## Agents
35
-
36
- Specialized agents with dedicated models and review capabilities.
37
-
38
- | Agent | Model | Description |
39
- | -------------------------------------------- | ------ | -------------------------------------------------------------------------- |
40
- | [ct-code-reviewer](agents/ct-code-reviewer.md) | Opus | Senior code reviewer with stack-aware analysis and severity-based feedback |
41
- | [ct-github-workflow](agents/ct-github-workflow.md) | Sonnet | Git workflow assistant for branching, commits, and PR creation |
42
-
43
- ## Stack Skills
44
-
45
- Stack-specific skills activated based on your `claude-toolkit.config.ts` configuration.
46
-
47
- | Skill | Stack | Description |
48
- | -------------------------------------------------------------- | ----------------- | ------------------------------------------------------------------------------ |
49
- | [ct-solidjs-patterns](stacks/solidjs-patterns.md) | `solidjs` | Reactivity, signals, effects, component patterns, and props handling |
50
- | [ct-vite-vitest-patterns](stacks/vite-vitest-patterns.md) | `vite` | Vite build config, plugins, env vars, Vitest testing, coverage, browser mode |
51
- | [ct-vanilla-extract-patterns](stacks/vanilla-extract-patterns.md) | `vanilla-extract` | Type-safe CSS with zero runtime: styles, recipes, themes, sprinkles |
52
- | [ct-rust-wasm-patterns](stacks/rust-wasm-patterns.md) | `rust-wasm` | Rust WASM for Cloudflare Workers: routing, handlers, env bindings |
53
- | [ct-protobuf-contracts](stacks/protobuf-contracts.md) | `protobuf` | Protocol Buffers for API contracts: schema design, versioning, code generation |
54
- | [ct-cloudflare-d1-kv](stacks/cloudflare-d1-kv.md) | `cloudflare` | D1 database and KV cache: queries, migrations, caching patterns |
55
- | [ct-i18n-typesafe](stacks/i18n-typesafe.md) | `i18n-typesafe` | Type-safe internationalization with compile-time key checking |
56
- | [ct-playwright-patterns](stacks/playwright-patterns.md) | `playwright` | E2E testing with Page Objects, fixtures, auth, network mocking, CI/CD |
57
- | [ct-storybook-patterns](stacks/storybook-patterns.md) | `storybook` | Interaction testing, CSF 3, play functions, a11y, visual regression |
58
- | [ct-capacitor-ota](stacks/capacitor-ota.md) | `capacitor` | Capacitor 8 native runtime and Capgo OTA live updates, channels, encryption |
59
- | [ct-esnext-idioms](stacks/esnext-idioms.md) | `esnext` | Modern ECMAScript runtime idioms: Temporal, iterator helpers, using, structuredClone |
@@ -1,76 +0,0 @@
1
- # Code Reviewer Agent
2
-
3
- > Senior code reviewer with stack-aware analysis.
4
-
5
- **Type:** Agent
6
- **Model:** Opus (highest capability)
7
- **Source:** [`core/agents/ct-code-reviewer.md`](../core/agents/ct-code-reviewer.md)
8
-
9
- ## Overview
10
-
11
- A senior code reviewer agent that thoroughly reviews code changes, providing actionable feedback organized by severity. It adapts review criteria to the project's stack and conventions.
12
-
13
- ## Review Process
14
-
15
- 1. **Read the full diff** and all changed files in their entirety -- understands surrounding context, not just changed lines
16
- 2. **Identify the stack** by reading project config files -- adapts criteria accordingly
17
- 3. **Apply the review checklist** to every changed file
18
- 4. **Compile findings** with severity levels and specific file/line references
19
-
20
- ## Review Checklist
21
-
22
- ### Critical Issues
23
-
24
- | Category | Checks |
25
- | --- | --- |
26
- | **Logic Correctness** | Off-by-one errors, inverted conditions, unhandled edge cases, race conditions, incorrect state transitions, dead code |
27
- | **Error Handling** | Swallowed errors, missing context in error messages, leaked resources, unhandled crashes, missing error boundaries |
28
- | **Security** | SQL/XSS/command injection, missing auth, secrets in code, CORS issues, missing rate limiting |
29
-
30
- ### Warnings
31
-
32
- | Category | Checks |
33
- | --- | --- |
34
- | **Type Safety** | `any` usage, unsafe casts, missing null checks, implicit coercions, overly broad generics |
35
- | **Performance** | Unnecessary re-renders, N+1 queries, missing pagination, sync-when-should-be-async, memory leaks |
36
- | **Testing** | New behavior without tests, implementation-detail tests, missing edge cases, flaky patterns |
37
-
38
- ### Suggestions
39
-
40
- | Category | Checks |
41
- | --- | --- |
42
- | **Naming and Readability** | Misleading names, abbreviations, functions doing too much, deep nesting, comments describing "what" instead of "why" |
43
-
44
- ## Output Format
45
-
46
- ```markdown
47
- ## Code Review
48
-
49
- **Reviewed:** {files or PR description}
50
- **Verdict:** APPROVE | REQUEST_CHANGES | COMMENT
51
-
52
- ### Critical ({count})
53
- ### Warnings ({count})
54
- ### Suggestions ({count})
55
- ### Looks Good
56
- ### Summary
57
- ```
58
-
59
- ## Best Practices Reference
60
-
61
- Stack-aware review informed by these guides:
62
-
63
- | Review Area | Guide |
64
- | --- | --- |
65
- | `any` usage, type safety patterns | [any & unknown](../best-practices/typescript/any-and-unknown.md) |
66
- | `type` vs `interface` conventions | [Type vs Interface](../best-practices/typescript/type-vs-interface.md) |
67
- | SolidJS-specific mistakes (destructuring, effects) | [SolidJS Anti-Patterns](../best-practices/solidjs/anti-patterns.md) |
68
- | Props reactivity issues | [SolidJS Props Patterns](../best-practices/solidjs/props-patterns.md) |
69
-
70
- ## Principles
71
-
72
- - **Be specific** -- "This catch block on line 42 swallows the database connection error" is useful; "This could be improved" is not
73
- - **Distinguish severity honestly** -- not everything is critical, not everything is a suggestion
74
- - **Acknowledge good work** -- reviews that only list problems are incomplete
75
- - **Stay in scope** -- review the changes, not the entire codebase
76
- - **Offer alternatives, not just objections** -- suggest a fix or direction for every problem flagged
@@ -1,98 +0,0 @@
1
- # GitHub Workflow Agent
2
-
3
- > Git workflow assistant for branching, commits, and PRs.
4
-
5
- **Type:** Agent
6
- **Model:** Sonnet
7
- **Source:** [`core/agents/ct-github-workflow.md`](../core/agents/ct-github-workflow.md)
8
-
9
- ## Overview
10
-
11
- A Git workflow assistant that helps with branch management, commit formatting, and pull request creation following consistent conventions.
12
-
13
- ## Branch Naming
14
-
15
- Format: `{prefix}/{short-description}`
16
-
17
- | Prefix | Use Case | Example |
18
- |---|---|---|
19
- | `feat` | New feature | `feat/user-avatar-upload` |
20
- | `fix` | Bug fix | `fix/login-redirect-loop` |
21
- | `chore` | Maintenance, deps, config | `chore/upgrade-eslint-9` |
22
- | `refactor` | Code restructuring | `refactor/extract-auth-service` |
23
- | `docs` | Documentation only | `docs/api-authentication` |
24
- | `test` | Test additions or fixes | `test/payment-edge-cases` |
25
- | `hotfix` | Urgent production fix | `hotfix/null-crash-checkout` |
26
-
27
- **Rules:** lowercase with hyphens, under 4 words, specific enough to identify at a glance.
28
-
29
- ## Conventional Commits
30
-
31
- Format: `{type}({scope}): {description}`
32
-
33
- | Type | When |
34
- |---|---|
35
- | `feat` | New feature visible to users |
36
- | `fix` | Bug fix |
37
- | `refactor` | Code change with no behavior difference |
38
- | `test` | Adding or updating tests |
39
- | `docs` | Documentation changes |
40
- | `chore` | Build, CI, dependency updates |
41
- | `perf` | Performance improvement |
42
- | `style` | Formatting, whitespace (no logic change) |
43
-
44
- **Examples:**
45
- ```
46
- feat(auth): add JWT refresh token rotation
47
- fix(cart): prevent duplicate items on rapid clicks
48
- refactor(api): extract validation middleware from route handlers
49
- chore(deps): upgrade next.js to 15.1
50
- ```
51
-
52
- **Rules:**
53
- - Scope is optional but encouraged (module or feature area)
54
- - Description starts lowercase, imperative mood ("add" not "added")
55
- - Body explains "why" not "what"
56
- - Breaking changes: add `!` after type/scope (e.g., `feat(api)!: change auth response format`)
57
-
58
- ## PR Creation Workflow
59
-
60
- ### 1. Pre-flight Checks
61
- - Tests pass
62
- - Types check
63
- - No lint errors
64
- - No merge conflicts
65
-
66
- ### 2. PR Title
67
- Same conventional format as commits, under 70 characters.
68
-
69
- ### 3. PR Description
70
- ```markdown
71
- ## Summary
72
- {1-3 bullet points: what and why}
73
-
74
- ## Changes
75
- - {Grouped list of meaningful changes}
76
-
77
- ## Testing
78
- - [ ] {How to test}
79
- - [ ] {Edge cases verified}
80
-
81
- ## Notes
82
- {Trade-offs, follow-up work, deployment considerations}
83
- ```
84
-
85
- ### 4. Pre-Open Checklist
86
- - Branch up to date with base
87
- - All tests pass
88
- - Types check cleanly
89
- - No lint errors
90
- - PR title follows conventional format
91
- - Changes are focused (one concern per PR)
92
-
93
- ## Principles
94
-
95
- - **Small PRs** -- if a PR touches more than 10 files or 300 lines, consider splitting
96
- - **One concern per PR** -- do not mix a feature with a refactor with a dependency upgrade
97
- - **Commit history matters** -- each commit should be a logical, buildable unit
98
- - **PR description is for the reviewer** -- write it to save their time
@@ -1,64 +0,0 @@
1
- # Capacitor & OTA Best Practices
2
-
3
- > A curated collection of best practices for Capacitor 8 native apps and Capgo over-the-air (OTA) live updates, sourced from official Capacitor documentation, the Capgo docs and blog, and the plugin maintainers as of June 2026.
4
-
5
- Capacitor wraps a web app (your `webDir` bundle) in a native iOS/Android shell. **OTA** lets you replace that web bundle on installed devices in minutes — without an app store review cycle. Capgo (`@capgo/capacitor-updater`) is the live-update layer that delivers, verifies, and rolls back those bundles.
6
-
7
- ```
8
- ┌─────────────────────────────┐
9
- │ Native shell (store) │ ← Capacitor core + plugins; ships via App Store / Play
10
- │ ┌───────────────────────┐ │ Changes here REQUIRE a new binary.
11
- │ │ Web bundle (OTA) │ │ ← JS / HTML / CSS; swapped by Capgo in minutes.
12
- │ │ notifyAppReady() ✓ │ │ Changes here ship over the air.
13
- │ └───────────────────────┘ │
14
- └─────────────────────────────┘
15
- ```
16
-
17
- ## The Two Layers — and the Golden Rule
18
-
19
- | Layer | What it is | How it ships | Review latency |
20
- | -------------- | ------------------------------------------- | --------------------------- | ------------------- |
21
- | **Native** | Capacitor core, plugins, native deps | App Store / Google Play | Hours to days |
22
- | **Web (OTA)** | Your compiled `webDir` (JS/HTML/CSS/assets) | Capgo channel swap | Minutes |
23
-
24
- **Golden rule:** OTA the web layer only. If a change needs a native API the installed shell doesn't have — a new plugin, a native dependency, a Capacitor major bump — it **must** go through the store first. OTA-ing a native contract mismatch crashes the app. Every other rule in this guide follows from this one.
25
-
26
- ## When to Use Which Channel
27
-
28
- | Question | Answer |
29
- | ----------------------------------------------------------------- | --------------------------------------- |
30
- | Did I change native code, add a plugin, or bump Capacitor major? | **Store binary** (then OTA on top) |
31
- | Bug fix / copy change / styling / feature in JS only? | **OTA** to `production` |
32
- | Needs QA sign-off before users see it? | **OTA** to `staging`, promote later |
33
- | Testing on dev/emulator builds? | **OTA** to `development` |
34
- | Need to undo a bad release right now? | **Channel rollback** (crown icon) |
35
-
36
- ## Technology Versions (as of June 2026)
37
-
38
- | Tool | Version | Notes |
39
- | -------------------------- | ------- | ---------------------------------------------------------------- |
40
- | `@capacitor/core` & CLI | ^8.3.x | 8.3.1 (2026-04-16); Node 22+ required |
41
- | `@capacitor/ios` | ^8.3.x | iOS 15.0 target, Xcode 26+, SPM default for new projects |
42
- | `@capacitor/android` | ^8.3.x | minSdk 24, compileSdk/targetSdk 36, Gradle 8.14.3, Kotlin 2.2.20 |
43
- | `@capgo/capacitor-updater` | ^8.x | Major tracks Capacitor major; v8 stores channel locally |
44
- | `@capgo/cli` | latest | `npx @capgo/cli@latest …` — pin in CI |
45
-
46
- ## Shared Principles
47
-
48
- 1. **`notifyAppReady()` is non-negotiable.** Call it at the top of bootstrap. Without it, every OTA bundle auto-rolls back after `appReadyTimeout`.
49
- 2. **Match the bundle to the shell.** A web bundle is only valid against the native version that shipped it. Use channel version gates to prevent mismatches.
50
- 3. **Stage every rollout.** Canary to ~10%, widen over 24h. Instant rollback beats instant deploy.
51
- 4. **Sign your bundles.** End-to-end encryption (RSA-2048 + AES-256) means only your users can read an update — keep the private key out of git.
52
- 5. **Keep the cloud in control of production.** Omit `defaultChannel` from production binaries so the dashboard default governs rollout and rollback.
53
- 6. **Monitor before you widen.** Watch the `appReady` / `downloadFailed` ratio; a spike is your signal to roll back.
54
- 7. **Pin tooling.** Unpinned `@capgo/cli@latest` in CI can change upload behavior between runs.
55
-
56
- ## Guides
57
-
58
- | Guide | Summary |
59
- | ------------------------------------------------- | ------------------------------------------------------------------------------- |
60
- | [Capacitor 8 Platform](capacitor-8.md) | Version floor, breaking changes, SPM-by-default, SystemBars, upgrade checklist. |
61
- | [Live Updates & OTA Strategy](live-updates-ota.md) | What to OTA vs ship native, performance, delta updates, scheduling. |
62
- | [Capgo Setup & API](capgo-setup.md) | Plugin install, config, `notifyAppReady`, autoUpdate modes, manual flow, CLI. |
63
- | [Channels & Staged Rollouts](channels-and-rollouts.md) | Channel ladder, precedence, canary rollouts, rollback, monitoring. |
64
- | [Security & Encryption](security-encryption.md) | E2E encryption (v2), key management, code signing, store compliance. |
@@ -1,60 +0,0 @@
1
- # Capacitor 8 Platform
2
-
3
- > Capacitor 8 raised the platform floor across the board. Get the toolchain right before touching OTA — a mismatched native baseline is the first thing that breaks live updates.
4
-
5
- Latest at time of writing: **8.3.1** (2026-04-16). 8.3.0 (2026-03-25) and 8.2.0 (2026-03-06) precede it.
6
-
7
- ## Minimum Requirements
8
-
9
- | Area | Requirement |
10
- | ------- | --------------------------------------------------------------------------- |
11
- | Node | **22+** (latest LTS recommended) |
12
- | iOS | Xcode **26.0+**, deployment target **15.0** |
13
- | Android | Android Studio Otter (2025.2.1)+, `minSdk 24`, `compileSdk 36`, `targetSdk 36` |
14
- | Gradle | Android Gradle plugin **8.13.0**, wrapper **8.14.3**, Kotlin **2.2.20** |
15
-
16
- ## Headline Changes
17
-
18
- ### Swift Package Manager is the default (iOS)
19
-
20
- New iOS projects scaffold with **SPM instead of CocoaPods**. Existing CocoaPods projects keep working — the ecosystem is migrating, not forcing a cutover. 8.3.0 added experimental config for `swift-tools-version` and support for SPM package traits in the generated `Package.swift`.
21
-
22
- ### Edge-to-edge via the SystemBars plugin (Android)
23
-
24
- An internal `SystemBars` plugin now handles status/navigation bar appearance for immersive layouts automatically, with a public API for fine control. It version-gates behavior and coexists with `@capacitor/status-bar`. Consequently the old config flag **`android.adjustMarginsForEdgeToEdge` was removed** — use SystemBars instead.
25
-
26
- ## Breaking Changes Checklist
27
-
28
- When upgrading to Capacitor 8:
29
-
30
- - [ ] **Node 22+** on every dev machine and CI runner.
31
- - [ ] **Android config syntax:** Gradle properties now require `=` (e.g. `compileSdk = 36`, not `compileSdk 36`).
32
- - [ ] **Android layout rename:** `bridge_layout_main.xml` → `capacitor_bridge_layout_main.xml`.
33
- - [ ] **Android resize:** add `density` to `configChanges` in `AndroidManifest.xml` to stop the WebView reloading on resize.
34
- - [ ] **Remove `android.adjustMarginsForEdgeToEdge`** from `capacitor.config` — replaced by SystemBars.
35
- - [ ] **iOS `appendUserAgent`:** the fixed concatenation may need a leading space to preserve your intended user-agent string.
36
- - [ ] **iOS lifecycle:** the framework now emits `viewDidAppear` / `viewWillTransition` — delete any custom extensions that duplicated this.
37
-
38
- ## 8.2–8.3 Notable Fixes
39
-
40
- These land automatically on patch upgrades but are worth knowing because they touch OTA-adjacent behavior:
41
-
42
- - **Android `server.url` with paths** is now parsed correctly (8.3.0) — relevant if you point the WebView at a custom/self-hosted update host.
43
- - **Android `isNewBinary()`** handles a null `versionName` (8.3.1) — the check that decides whether a native update invalidates OTA bundles.
44
- - **HTTP `fetch`** handles `URL` objects and form-data boundary extraction (8.3.0/8.3.1).
45
- - **CLI** inlines CSS sourcemaps alongside JS (8.3.0) and respects `CAPACITOR_COCOAPODS_PATH` (8.3.1).
46
-
47
- ## Keeping Native and OTA in Lockstep
48
-
49
- The single most important interaction: **a native upgrade invalidates incompatible OTA bundles.** `resetWhenUpdate: true` (the Capgo default) wipes downloaded bundles when the native app updates, so users fall back to the bundle baked into the new binary rather than running a stale OTA bundle against new native code. Keep it on unless you have a specific reason not to.
50
-
51
- When you bump Capacitor or add a plugin:
52
-
53
- 1. Ship a new store binary with the updated native layer.
54
- 2. Bump your bundle's version so old shells don't pull a bundle meant for the new native contract.
55
- 3. Use channel version gates (`--disable-auto-update major|minor`) to enforce the boundary.
56
-
57
- ## See Also
58
-
59
- - [Live Updates & OTA Strategy](live-updates-ota.md) — what's safe to OTA on top of a given binary
60
- - [Channels & Staged Rollouts](channels-and-rollouts.md) — version gates that enforce the native/web contract