claude-mcp-workflow 0.1.8 → 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 (56) hide show
  1. package/.claude-plugin/plugin.json +4 -2
  2. package/README.md +37 -0
  3. package/build/engine.d.ts +13 -1
  4. package/build/engine.d.ts.map +1 -1
  5. package/build/engine.js +41 -2
  6. package/build/engine.js.map +1 -1
  7. package/build/types.d.ts +20 -20
  8. package/build/types.js +1 -1
  9. package/build/types.js.map +1 -1
  10. package/hooks/hooks.json +4 -2
  11. package/hooks/workflow-cleanup.sh +8 -4
  12. package/hooks/workflow-start.sh +60 -32
  13. package/package.json +1 -1
  14. package/templates/bug-fix.yaml +98 -16
  15. package/templates/code-review.yaml +30 -12
  16. package/templates/coding.yaml +49 -4
  17. package/templates/debugging.yaml +39 -14
  18. package/templates/explore.yaml +48 -14
  19. package/templates/file-code.yaml +13 -4
  20. package/templates/file-review.yaml +25 -6
  21. package/templates/github-init.yaml +24 -8
  22. package/templates/investigate.yaml +13 -4
  23. package/templates/master.yaml +16 -13
  24. package/templates/new-feature.yaml +24 -26
  25. package/templates/planning.yaml +34 -7
  26. package/templates/reflection.yaml +11 -4
  27. package/templates/review-push.yaml +26 -7
  28. package/templates/skills/architecture/SKILL.md +131 -1
  29. package/templates/skills/aws-lambda/SKILL.md +9 -9
  30. package/templates/skills/browser-verify/SKILL.md +58 -0
  31. package/templates/skills/build-cmake/SKILL.md +24 -8
  32. package/templates/skills/ci-github-actions/SKILL.md +34 -18
  33. package/templates/skills/claude-code-config/SKILL.md +41 -19
  34. package/templates/skills/cleanup/SKILL.md +57 -0
  35. package/templates/skills/coding-skill-selector/SKILL.md +2 -1
  36. package/templates/skills/debug-bridge-scaffold/SKILL.md +98 -0
  37. package/templates/skills/domain-gamedev/SKILL.md +56 -6
  38. package/templates/skills/domain-pixi/SKILL.md +256 -7
  39. package/templates/skills/domain-reid/SKILL.md +39 -5
  40. package/templates/skills/domain-yolo/SKILL.md +18 -7
  41. package/templates/skills/ide-zed/SKILL.md +23 -0
  42. package/templates/skills/lang-as3/SKILL.md +7 -5
  43. package/templates/skills/lang-haxe/SKILL.md +538 -19
  44. package/templates/skills/lang-python/SKILL.md +6 -2
  45. package/templates/skills/math/SKILL.md +64 -2
  46. package/templates/skills/mcp-setup/SKILL.md +14 -2
  47. package/templates/skills/preferences/SKILL.md +10 -10
  48. package/templates/skills/skill-manager/SKILL.md +264 -0
  49. package/templates/skills/target-openfl-native/SKILL.md +52 -17
  50. package/templates/skills/target-openfl-native/references/build-and-versions.md +7 -4
  51. package/templates/skills/task-delegation/SKILL.md +76 -4
  52. package/templates/skills/web-reading/SKILL.md +33 -25
  53. package/templates/skills/workflow-authoring/SKILL.md +47 -12
  54. package/templates/subagent.yaml +29 -8
  55. package/templates/testing.yaml +64 -10
  56. package/templates/web-research.yaml +23 -13
@@ -9,8 +9,12 @@ description: Python language gotchas
9
9
 
10
10
  ```python
11
11
  results = [c for raw in data if (c := normalize(raw)) is not None]
12
- # c IS accessible outside the comprehension! (PEP 572 design)
12
+ # c IS accessible outside the comprehension (PEP 572 design)
13
+ # but only if the walrus actually ran: with an empty `data`, reading c
14
+ # raises NameError. It runs even for filtered-out elements (the walrus
15
+ # sits in the condition), so c holds the last *evaluated* value, not the
16
+ # last *kept* one.
13
17
  # Unlike regular loop variables, := leaks to enclosing scope
14
18
  ```
15
19
 
16
- Sonnet confidently says "c is NOT accessible" — this is wrong. The walrus operator in comprehensions intentionally binds in the containing scope.
20
+ The common confident claim "c is NOT accessible outside" is wrong the walrus operator in comprehensions intentionally binds in the containing scope.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: math
3
- description: Math overflow boundary gotchas
3
+ description: Math gotchas — integer overflow boundaries, cross-runtime float parity (tan/pow ULP drift), FP modulo-wrap pitfalls
4
4
  ---
5
5
 
6
6
  # Math — Verified Gotchas
@@ -10,5 +10,67 @@ description: Math overflow boundary gotchas
10
10
  | Type | Last fits | First overflow |
11
11
  |------|-----------|----------------|
12
12
  | Int64 | C(66, 33) = 7,219,428,434,016,265,740 | C(67, 33) |
13
+ | UInt64 | C(67, 33) = 14,226,520,737,620,288,370 | C(68, 34) |
13
14
 
14
- Sonnet consistently underestimates this boundary (says n=62, correct is n=66).
15
+ Models consistently underestimate this boundary (a common wrong answer is n=62; correct is n=66 for Int64).
16
+
17
+ **Result vs computation**: the table bounds the RESULT. Intermediate products in the usual `res = res * (n-k+i) / i` loop overflow earlier (the multiply happens before the divide) — the last few safe n need 128-bit intermediates or a divide-first formulation.
18
+
19
+ ## Cross-runtime trig: V8 `Math.tan` ≠ CPython `math.tan` by 1 ULP
20
+
21
+ When building bit-exact parity between TS/JS and Python implementations of
22
+ the same math, **`tan` is the single biggest offender**. V8 and CPython do
23
+ not share a single implementation (V8 ships its own fdlibm-derived routines;
24
+ CPython calls platform libm), and `tan`'s range reduction produces a
25
+ different LSB from naive `sin(x)/cos(x)` for some angles — which layer is
26
+ responsible varies by platform.
27
+
28
+ **Fix**: compute `tan(x)` as `sin(x) / cos(x)` in BOTH languages. `sin` and
29
+ `cos` round-tripped bit-identically across the tested runtimes.
30
+
31
+ | Op | V8 `Math.X` vs CPython `math.X` | Use? |
32
+ |---|---|---|
33
+ | `sin`, `cos` | bit-identical (observed) | yes |
34
+ | `sqrt` | bit-identical (IEEE-754 mandates correctly-rounded) | yes |
35
+ | `tan` | **1 ULP drift possible** | avoid — use `sin/cos` |
36
+ | `**` (pow) | 1-2 ULP drift possible | accept tolerance |
37
+ | `atan`, `atan2`, `exp`, `log` | 1-2 ULP drift possible | accept tolerance |
38
+
39
+ **Even after sin/cos swap**, `pow(x, y)` (e.g. `step_mult = floor + norm**exp`)
40
+ can still produce 1-ULP-different doubles between V8 and CPython for some
41
+ inputs. If the math identity is preserved (same algorithm, same constants,
42
+ sin/cos for tan), `math.isclose(rel_tol=1e-12, abs_tol=1e-9)` covers ~2 ULP
43
+ at typical magnitudes and is the right tolerance for "bit-exact in spirit".
44
+
45
+ **Concrete example**: a projectile-apex derivation
46
+ `apexAboveMidline = (range/4) * tan(angleRad)`. V8 emitted
47
+ `tan=0.32130439756415801744`; CPython emitted `tan=0.32130439756415796193`.
48
+ After swapping both to `sin(x)/cos(x)`, both emitted the second value.
49
+ Remaining rare failures (9/1000 seeds) came from `**1.8` in the step
50
+ multiplier — those needed the `isclose` tolerance.
51
+
52
+ ## Modulo-wrap round-trip is NOT identity for in-range floats — never gate "did it wrap?" on FP equality
53
+
54
+ `wrapped = lo + (((x - lo) % span) + span) % span` for `x` ALREADY in
55
+ `[lo, hi)` returns a value that differs from `x` by ~1 ULP(span) on a large
56
+ fraction of inputs. The `%` ops themselves are exact — `%` is
57
+ truncated-division remainder (C `fmod` semantics), which IEEE 754 requires
58
+ to be exact; note it is NOT the IEEE `remainder()` operation (round-nearest
59
+ quotient), a different op. The error comes from the surrounding `x-lo`,
60
+ `+span`, `lo+m` adds, each of which rounds. Measured: 41–67% of in-range
61
+ values fail `wrapped === x` depending on the window; with `lo` and `x` of
62
+ matching magnitude the subtraction is Sterbenz-exact and the identity HOLDS
63
+ (0/1e6 failures) — so the spurious rate silently depends on runtime state
64
+ (camera position), making it look fine in one regime and fire constantly in
65
+ another.
66
+
67
+ **Failure mode**: `if (wrapped !== x) onWrap()` as a "teleport happened"
68
+ detector fired the callback ~60 Hz for every entity instead of once per
69
+ recycle — and a simulation harness with the same window shape "validated"
70
+ the degenerate behavior convincingly.
71
+
72
+ **Right**: detect the wrap by RANGE, then normalize:
73
+ ```js
74
+ if (x < lo || x >= hi) { x = lo + (((x - lo) % span) + span) % span; onWrap(); }
75
+ ```
76
+ Also skips the modulo (and its FP noise re-write) in the common in-range case.
@@ -6,9 +6,16 @@ description: MCP server setup and troubleshooting
6
6
  ## Rules
7
7
 
8
8
  1. **NEVER guess package names** → `npm info <name>` to verify before installing
9
- 2. **Validate before adding** → `npm info` → `npx -y <pkg> --help` → `claude mcp add`
9
+ 2. **Validate before adding** → `npm info` → `npx -y <pkg> --help` → `claude mcp add`. Caveat: many MCP servers don't implement `--help` and just wait on stdio — wrap validation in `timeout 10 …` so it can't hang.
10
10
  3. **Think UX upfront** → headless mode, timeouts, flags — ask user BEFORE installing
11
- 4. **Minimize restarts** each MCP change = session restart. Get it right first time.
11
+ 4. **Restarts**: `/mcp` can reconnect already-registered servers, but registering a NEW server requires a session restart. Get the config right the first time.
12
+
13
+ ## Quick Facts
14
+
15
+ - Python servers: `claude mcp add <name> -- uvx <pkg>` — uvx launches PyPI packages over stdio, no venv management.
16
+ - Remote servers: `claude mcp add --transport http <name> <url>` (also `--transport sse` for legacy SSE servers).
17
+ - Scopes: `project` scope lives in `.mcp.json` at the repo root (checked in); `local` scope lives in `~/.claude.json` under that project's entry (NOT in the repo); `user` scope is global in `~/.claude.json`.
18
+ - Plugin-bundled servers get tool names `mcp__plugin_<plugin>_<server>__<tool>` — the full name must stay under the 64-char API limit, so keep plugin/server names short.
12
19
 
13
20
  ## Troubleshooting
14
21
 
@@ -16,3 +23,8 @@ description: MCP server setup and troubleshooting
16
23
  2. Run command manually to see error
17
24
  3. `npm whoami` — fix stale token if needed
18
25
  4. `npm info <pkg> deprecated` — check if abandoned
26
+
27
+ ## Browser MCP (playwright/chrome-devtools)
28
+
29
+ - **"Browser is already in use … use --isolated"** = the persistent Chrome profile (`~/Library/Caches/ms-playwright-mcp/mcp-chrome-*` on macOS, `~/.cache/ms-playwright-mcp/mcp-chrome-*` on Linux) is locked by a stale `SingletonLock` symlink (often pointing at an unrelated regular Chrome pid). The MCP server refuses even after `browser_close`.
30
+ - **Fix without killing the user's Chrome**: if more than one browser MCP server is configured, each has its own profile — switch to the other server rather than `kill`ing the pid the lock points at (it may be the user's real browser). Stay with ONE browser server per session; alternating between two hits the lock again.
@@ -5,11 +5,11 @@ description: User's general coding preferences
5
5
 
6
6
  ## User's personal coding preferences
7
7
 
8
- These rules are set by the user through direct feedback.
9
- They ALWAYS take priority over base skills.
8
+ Rules in this file ALWAYS take priority over base skills.
10
9
 
11
- <!-- Add your preferences here. The sections below are examples -->
12
- <!-- customize them to match your coding style. -->
10
+ <!-- Customize this file to match your coding style: the uncommented -->
11
+ <!-- rules below are shipped defaults keep, edit, or delete them. -->
12
+ <!-- Commented rules are examples to uncomment and adapt. -->
13
13
 
14
14
  ### Model usage
15
15
 
@@ -38,9 +38,9 @@ They ALWAYS take priority over base skills.
38
38
  ### Naming
39
39
 
40
40
  - Private fields (variables) must start with `_` prefix: `_count`, `_items`
41
+ - This applies to instance variables, NOT to methods or constants
42
+ - Public fields do NOT use underscore prefix
41
43
  <!-- - Event listener methods: use `Handler` suffix, not `on` prefix -->
42
- <!-- - This applies to instance variables, NOT to methods or constants -->
43
- <!-- - Public fields do NOT use underscore prefix -->
44
44
 
45
45
  ### Comments and documentation
46
46
 
@@ -53,10 +53,10 @@ They ALWAYS take priority over base skills.
53
53
  <!-- - No curly braces for single-line bodies -->
54
54
  <!-- - Combine `for` + `if` into `for (...) if (...) {` — preferred over `if (!cond) continue;` -->
55
55
 
56
- ### Error handling
57
-
58
- - Never silently swallow invalid state — throw exceptions instead of returning quietly
59
-
60
56
  ### Magic numbers
61
57
 
62
58
  <!-- - No magic number literals in logic — extract into a named constant -->
59
+
60
+ ### Error handling
61
+
62
+ - Never silently swallow invalid state — throw exceptions instead of returning quietly
@@ -0,0 +1,264 @@
1
+ ---
2
+ name: skill-manager
3
+ description: Create, install, update, optimize skills
4
+ ---
5
+
6
+ ## Skill lifecycle manager
7
+
8
+ This skill is HEAVY. Always run via subagent (Task tool), never in main context.
9
+
10
+ ### Model policy
11
+
12
+ - Use **Opus** or **Sonnet** for subagents
13
+ - **NEVER use Haiku** — insufficient for quality work
14
+ - Skills are optimized for Opus/Sonnet reasoning capabilities
15
+
16
+ **Model selection by task:**
17
+ - **OPTIMIZE skills** → Sonnet (filtering/editing, doesn't need deep reasoning)
18
+ - **CREATE skill from research** → Sonnet (research + writing)
19
+ - **Complex code generation** → Opus (when quality is critical)
20
+
21
+ ### ⛔ PROTECTED skills — NEVER modify or overwrite
22
+
23
+ Skills matching `preferences*` (`preferences/`, `preferences-<lang>/`,
24
+ any other `preferences-*` variant) are user-owned personal rules.
25
+
26
+ These are ONLY updated when the user gives direct feedback.
27
+ skill-manager must NEVER touch, overwrite, or regenerate them without
28
+ an explicit user request.
29
+
30
+ ### 1. FIND an existing skill
31
+
32
+ Search order:
33
+ A) Check awesome-agent-skills: https://github.com/VoltAgent/awesome-agent-skills
34
+ B) Check awesome-claude-code: https://github.com/hesreallyhim/awesome-claude-code
35
+ C) Check anthropics/skills: https://github.com/anthropics/skills
36
+ D) Search npm: `npm search claude skill <keyword>`
37
+ E) Search GitHub: `gh search repos "claude skill <keyword>"`
38
+
39
+ **IMPORTANT:** Subagents don't have access to skills. When launching a research subagent, include these web-reading rules in the prompt:
40
+
41
+ 1. For GitHub repos/issues/PRs → use `gh` CLI, not web fetch
42
+ 2. Fetch web pages via Jina Reader: `WebFetch("https://r.jina.ai/<url>", "<precise extraction prompt>")`
43
+ 3. If Jina fails → direct `WebFetch` with prompt: "Extract ONLY main article content as clean markdown. Ignore navigation, sidebars, headers, footers, ads."
44
+ 4. If page inaccessible → `WebSearch` for mirrors, docs, cached versions
45
+ 5. ALWAYS specify exactly what to extract — never "get the page" or "summarize"
46
+
47
+ ### 2. INSTALL an existing skill
48
+
49
+ ```bash
50
+ # From known repos
51
+ npx -y openskills install <owner/repo/skill-name> -g
52
+
53
+ # Or manually
54
+ # 1. Fetch the SKILL.md content
55
+ # 2. Write to ~/.claude/skills/<skill-name>/SKILL.md
56
+ # 3. Copy any scripts/, references/, assets/ if present
57
+ ```
58
+
59
+ After install, verify:
60
+ - SKILL.md has valid frontmatter (name, description)
61
+ - Description doesn't overlap with existing skills
62
+ - Fits the layered architecture: universal → lang → domain → target
63
+
64
+ ### 3. CREATE a new skill from scratch
65
+
66
+ Follow Anthropic's skill-creator principles:
67
+
68
+ A) **Size = f(content)** — can be 10 lines or 500, depends on how much Claude DOESN'T know
69
+ B) **CRITICAL: Don't teach what Claude already knows!**
70
+ C) **When in doubt — EXCLUDE** (easier to add later than to remove)
71
+ D) **Minimal code examples** — only to illustrate a gotcha, not full solutions
72
+ E) **Always add `description` to frontmatter** — max 5-6 words, as short as possible. Without it Claude won't load the skill.
73
+ F) **Do NOT add `disable-model-invocation`** — skills must be callable via Skill() tool. Discovery chain: workflow `think` state → domain mapping → `Skill(name)`.
74
+ G) Use progressive disclosure:
75
+ - SKILL.md body (<5k words) = loaded when triggered via Skill()
76
+ - references/ = loaded on demand
77
+
78
+ ### ⚠️ What to include vs exclude in skills
79
+
80
+ **NEVER include** (Claude already knows this):
81
+ - Basic syntax of mainstream languages
82
+ - Standard library functions that are well-documented
83
+ - Common design patterns (singleton, factory, observer)
84
+ - General programming principles (DRY, SOLID)
85
+ - Popular framework basics (React, ASP.NET, Django)
86
+ - **Well-known patterns with full examples** (multi-stage Docker builds, async/await)
87
+ - **Obvious best practices** (use .gitignore, validate input)
88
+ - **Standard CLI commands** (docker run, git commit, npm install)
89
+
90
+ **ALWAYS include** (Claude needs this):
91
+ - **Gotchas and pitfalls** — things Claude commonly gets wrong
92
+ - **Subtle differences** — from similar languages/frameworks
93
+ - **Non-obvious conventions** — that differ from common patterns
94
+ - **Version-specific changes** — recent updates Claude may not know
95
+ - **Integration quirks** — how things work together in practice
96
+ - **User's preferences** — always in preferences-* skills
97
+ - **Niche topics** — obscure APIs, legacy systems, specialized domains
98
+
99
+ **Process for creating a lang-* or domain-* skill:**
100
+
101
+ 1. Start with EMPTY file
102
+ 2. Research web for "gotchas", "common mistakes", "pitfalls" in this domain
103
+ 3. For each finding — two-model filter (Opus + Sonnet):
104
+ - Both models know it → SKIP (water)
105
+ - At least one doesn't know → INCLUDE
106
+ 4. Specific numbers/boundaries → always verify by computation, record exact values
107
+ 5. If nothing passes the filter → maybe this skill isn't needed
108
+
109
+ **Two-model consensus** (mirrors water-removal):
110
+ - Remove what BOTH models know
111
+ - Add what at LEAST ONE model doesn't know
112
+
113
+ **Gotcha vs Pattern — examples:**
114
+ ```
115
+ ✗ EXCLUDE: "Use multi-stage builds to reduce image size"
116
+ (well-known pattern, Claude knows this)
117
+
118
+ ✓ INCLUDE: "COPY --from=0 uses stage INDEX, not name — breaks if stages reordered"
119
+ (gotcha, easy to miss)
120
+
121
+ ✗ EXCLUDE: "Use async/await for asynchronous code"
122
+ (basic syntax)
123
+
124
+ ✓ INCLUDE: "ConfigureAwait(false) in library code — otherwise deadlock in UI"
125
+ (subtle gotcha, context-dependent)
126
+ ```
127
+
128
+ Structure:
129
+ ```
130
+ ~/.claude/skills/<skill-name>/
131
+ ├── SKILL.md # Required: frontmatter + instructions
132
+ ├── references/ # Optional: detailed docs, schemas
133
+ ├── scripts/ # Optional: executable helpers
134
+ └── assets/ # Optional: templates, samples
135
+ ```
136
+
137
+ Naming for layered architecture:
138
+ - Universal: `code-writing`, `architecture`, `testing`, `refactoring`
139
+ - Language: `lang-csharp`, `lang-haxe`, `lang-python`
140
+ - Domain: `domain-unity`, `domain-dotnet`, `domain-gamedev`
141
+ - Target: `target-hashlink`, `target-aspnet`, `target-webgl`
142
+
143
+ ### 4. CONVERT documentation into a skill
144
+
145
+ For turning language/framework docs into a skill:
146
+
147
+ A) Fetch documentation using web-reading chain
148
+ B) Extract:
149
+ - Core idioms and conventions
150
+ - Common patterns and anti-patterns
151
+ - API quick reference (signatures, not full docs)
152
+ - Gotchas and common mistakes
153
+ C) Structure as SKILL.md — focus on what Claude wouldn't know
154
+ D) Move detailed API references to references/ directory
155
+ E) Write precise description for auto-invocation
156
+
157
+ ### 5. ENRICH skill from observed error
158
+
159
+ Triggered by reflection when Claude makes a verifiable mistake.
160
+
161
+ 1. Identify the error and the skill it belongs to
162
+ 2. Research the correct answer: code verification → web docs → web search
163
+ 3. Verify the correct answer by running code (if possible)
164
+ 4. Add ONLY the verified correction to the existing skill
165
+ 5. Format: show the wrong thing and the right thing with exact values
166
+
167
+ Example flow: Claude writes `Fib(46) overflows Int32` → verification shows Fib(46) fits,
168
+ Fib(47) overflows → add verified table to math skill with exact numbers.
169
+
170
+ ### 6. UPDATE an existing skill (manual)
171
+
172
+ ```bash
173
+ # Via openskills (if installed from repo)
174
+ npx -y openskills update <skill-name>
175
+
176
+ # Or manually
177
+ # 1. Read current ~/.claude/skills/<skill-name>/SKILL.md
178
+ # 2. Identify what's missing or wrong
179
+ # 3. Edit with improvements
180
+ # 4. Verify description still fits
181
+ ```
182
+
183
+ ### 7. LIST and AUDIT current skills
184
+
185
+ ```bash
186
+ ls ~/.claude/skills/
187
+ ```
188
+
189
+ Check for:
190
+ - Overlapping descriptions between skills
191
+ - Skills that are too large (>500 lines)
192
+ - Missing skills for languages/domains being used
193
+ - Outdated information
194
+
195
+ ### 8. OPTIMIZE skills (on model version change)
196
+
197
+ When Claude version changes (e.g., 4.5 → 5.0), run optimization:
198
+
199
+ **Trigger:** User says "optimize skills" or new model version detected.
200
+
201
+ **Process for each skill:**
202
+
203
+ 1. Read the skill content
204
+ 2. For each piece of information, ask:
205
+ - "Does the NEW model already know this?" → REMOVE if yes
206
+ - "Is this a gotcha/pitfall that's still relevant?" → KEEP
207
+ - "Is this user's preference?" → NEVER TOUCH (preferences-*)
208
+ - "Has this API/convention changed?" → UPDATE from fresh research
209
+ 3. Re-test: does the skill still add value?
210
+ 4. If skill becomes nearly empty → consider deleting it
211
+
212
+ **What to keep regardless of model version:**
213
+ - User preferences (preferences-*)
214
+ - Behavioral/meta skills (reflection)
215
+ - Infrastructure skills (web-reading, mcp-setup)
216
+ - Recent version-specific changes (last 6-12 months)
217
+ - Niche domains (ANE, Re-ID pipelines)
218
+
219
+ **What to aggressively prune:**
220
+ - Basic syntax of mainstream languages
221
+ - Well-documented standard library functions
222
+ - General programming principles
223
+ - Popular framework basics
224
+
225
+ **Deduplicate with preferences:**
226
+ During optimization, check preferences-* skills for this language/domain.
227
+ If a rule exists in preferences-*, REMOVE it from the base skill.
228
+ User preferences always win — no need to duplicate.
229
+
230
+ Example: if preferences-haxe says "use final class", remove any mention
231
+ of final class conventions from lang-haxe.
232
+
233
+ **Log optimizations:**
234
+ After optimization, note in MEMORY.md:
235
+ - Date optimized
236
+ - Model version optimized for
237
+ - What was removed/kept/updated
238
+
239
+ ### 9. UPDATE selector domain mappings after creating new skills
240
+
241
+ **MANDATORY:** After creating or installing any new skill, update the domain mapping
242
+ in `~/.claude/skills/coding-skill-selector/SKILL.md` — one place.
243
+
244
+ Add the new skill to the appropriate section (by extension or by domain), e.g.:
245
+ ```
246
+ - NewDomain → `Skill("domain-newdomain")`
247
+ ```
248
+
249
+ **This single skill is loaded at the skill-gate states of all code-related workflows (coding, debugging, bug-fix, code-review, etc.).**
250
+
251
+ ### Language rule
252
+
253
+ All skills MUST be written in English only. Never mix languages in skill files.
254
+
255
+ ### Validation checklist
256
+
257
+ Before finishing any skill operation:
258
+ - [ ] Frontmatter has `name` + short `description` (no disable-model-invocation)
259
+ - [ ] Name is hyphen-case, max 64 chars
260
+ - [ ] SKILL.md ≤500 lines (size driven by content, not arbitrary target)
261
+ - [ ] Follows layered architecture (universal/lang/domain/target)
262
+ - [ ] Only gotchas/pitfalls — no basic patterns Claude already knows
263
+ - [ ] If skill is nearly empty → maybe it's not needed
264
+ - [ ] **selector domain mapping updated** (coding-skill-selector skill)
@@ -129,8 +129,10 @@ while (!_worker.isStopped() && waited < TIMEOUT_MS) {
129
129
  Sys.sleep(0.1);
130
130
  waited += 100;
131
131
  }
132
- if (waited < TIMEOUT_MS) {
133
- // Thread stopped cleanly — safe to close resources
132
+ if (_worker.isStopped()) {
133
+ // Thread stopped cleanly — safe to close resources.
134
+ // Re-check the flag, NOT the timer: the worker may have stopped
135
+ // during the final sleep, right as the timeout expired.
134
136
  try db.close() catch (e:Dynamic) {};
135
137
  }
136
138
  // Always null out regardless
@@ -143,11 +145,11 @@ _worker = null;
143
145
 
144
146
  ```haxe
145
147
  // WRONG — parent field nulled but still in __children → main thread renders it
146
- pitchAreaGroup.parent = null;
148
+ child.parent = null;
147
149
 
148
150
  // RIGHT — remove from __children, then null parent
149
- @:privateAccess parent.__children.remove(pitchAreaGroup);
150
- pitchAreaGroup.parent = null;
151
+ @:privateAccess parent.__children.remove(child);
152
+ child.parent = null;
151
153
  ```
152
154
 
153
155
  To restore, save the child index before removing and re-insert at the same position:
@@ -169,6 +171,39 @@ child.parent = savedParent;
169
171
 
170
172
  `Sys.exit()` calls C `exit()`. In worker threads, stdout buffer may not flush. Always call `Sys.stdout().flush()` before `Sys.exit()`.
171
173
 
174
+ ### Sys.exit() races hxcpp GC mutex destruction → `mutex lock failed: Invalid argument`
175
+
176
+ `Sys.exit()` → libc `exit()` → runs C++ static destructors, including hxcpp's GC mutexes (`sThreadPoolLock` in `hx::gc::Immix.cpp`, `g_threadInfoMutex` in `hx::Thread.cpp`). The GC worker thread is NOT stopped by `exit()`. Its next `pthread_mutex_lock` on a now-destroyed mutex returns EINVAL → libc++abi terminates with `mutex lock failed: Invalid argument`. Manifests differently per platform: Linux shows `terminate ... std::system_error ... Invalid argument`, Windows is silent or AV, macOS crashes at unit test exit.
177
+
178
+ Fix: after cooperative cleanup, skip C++ static destructors by calling `_Exit` (see below).
179
+
180
+ ### `_exit` from `<unistd.h>` is NOT available; use `_Exit` from `<cstdlib>`
181
+
182
+ hxcpp does NOT auto-include `<unistd.h>`. `untyped __cpp__("::_exit({0})", code)` fails with `error: no type named '_exit' in the global namespace`.
183
+
184
+ Use C99 `_Exit` (capital E) from `<cstdlib>` — skips C++ static destructors and atexit handlers, identical to `_exit` in effect, portable across Darwin/Linux/Windows MSVC.
185
+
186
+ ```haxe
187
+ // WRONG — <unistd.h> not included by hxcpp; compile error
188
+ untyped __cpp__("::_exit({0})", code);
189
+
190
+ // RIGHT — <cstdlib> is safe; _Exit skips static destructors
191
+ @:cppFileCode("#include <cstdlib>")
192
+ final class CleanExit {
193
+ public static function exit(code:Int):Void {
194
+ try Sys.stdout().flush() catch (_:Exception) {} // see "doesn't flush stdout" above
195
+ try Sys.stderr().flush() catch (_:Exception) {}
196
+ #if cpp
197
+ untyped __cpp__("std::_Exit({0})", code);
198
+ #else
199
+ Sys.exit(code);
200
+ #end
201
+ }
202
+ }
203
+ ```
204
+
205
+ **Warning**: `_Exit` skips ALL atexit handlers. Any pending writes (DB flushes, file saves) are lost. Only call after cooperative cleanup. Keep this as a small shared utility class.
206
+
172
207
  ## Extern Patterns (@:native)
173
208
 
174
209
  ### Pointer suffix for heap-allocated types
@@ -225,7 +260,7 @@ Including `<OpenGLES/EAGL.h>` or any header that pulls in `Foundation.h` inside
225
260
  #include <objc/runtime.h>
226
261
  #include <objc/message.h>
227
262
 
228
- static void* tm_get_eagl_context() {
263
+ static void* get_eagl_context() {
229
264
  Class cls = objc_getClass("EAGLContext");
230
265
  SEL sel = sel_registerName("currentContext");
231
266
  return ((void* (*)(id, SEL))objc_msgSend)((id)cls, sel);
@@ -279,25 +314,25 @@ No leading slashes in asset paths — `"/manifest/default.json"` crashes on some
279
314
 
280
315
  **GlowFilter on Label/Sprite container** — apply to the parent container (Label, Sprite), NOT to TextField directly. `label.filters = [new GlowFilter(...)]` works. `textField.filters` inside a Label wrapper does NOT produce visible results.
281
316
 
282
- **BitmapData.draw() does NOT capture filters** — `bmd.draw(stage)` uses the software renderer and skips GPU filters. Use `window.readPixels()` instead — reads from the GPU framebuffer and captures everything including filters. Debug bridge already uses readPixels with fallback to draw.
317
+ **BitmapData.draw() does NOT capture filters** — `bmd.draw(stage)` uses the software renderer and skips GPU filters. Use `window.readPixels()` instead — reads from the GPU framebuffer and captures everything including filters. Screenshot tooling (e.g. a debug bridge) should use readPixels with draw() as fallback.
283
318
 
284
319
  **Search codebase first** — before implementing text outlines, shadows, or effects, grep for existing `GlowFilter`/`DropShadowFilter` usage in the project. Likely already solved with correct params.
285
320
 
286
321
  **`DisplayObject.filters != null` forces `cacheAsBitmap = true`** — the getter is `return (__filters == null ? __cacheAsBitmap : true)`. Any non-null filters array (even a filter with alpha=0 or zero-radius) causes the object to render through the intermediate bitmap-cache path. Symptoms:
287
322
 
288
323
  - Setting `obj.cacheAsBitmap = false` has NO effect when `filters != null` — the getter still returns `true`.
289
- - At high render scales (video export, offscreen `BitmapData.draw` with large matrix), the intermediate cache bitmap can be sized wrong for the target, visually clipping the right/bottom of content (e.g. missing right post, missing background geometry).
324
+ - At high render scales (video export, offscreen `BitmapData.draw` with large matrix), the intermediate cache bitmap can be sized wrong for the target, visually clipping the right/bottom of content (elements near those edges silently disappear from the output).
290
325
 
291
326
  ```haxe
292
327
  // WRONG — unselected state keeps a zero-alpha filter "to avoid allocations"
293
- override function set_isSelected(value:Bool):Bool {
328
+ override private function set_isSelected(value:Bool):Bool {
294
329
  final alpha:Float = value ? 1 : 0;
295
330
  obj.filters = [new GlowFilter(color, alpha, 4, 4, 1)]; // still forces cacheAsBitmap
296
331
  return isSelected = value;
297
332
  }
298
333
 
299
334
  // RIGHT — null out filters when not needed
300
- override function set_isSelected(value:Bool):Bool {
335
+ override private function set_isSelected(value:Bool):Bool {
301
336
  obj.filters = value ? [new GlowFilter(color, 1, 4, 4, 1)] : null;
302
337
  return isSelected = value;
303
338
  }
@@ -343,7 +378,7 @@ bytes.blit(botOff, tmp, 0, rowStride); // tmp → bottom
343
378
 
344
379
  ### BitmapData.draw pixelRatio vs cache bitmaps (text blur on Windows)
345
380
 
346
- `BitmapData.draw()` sets `renderer.__pixelRatio = window.scale`. TextFields with filters (GlowFilter, DropShadowFilter) go through `__updateCacheBitmap` which creates the cache bitmap at `pixelRatio` resolution. On Windows (`window.scale=1`), cache bitmaps are 1x — if the draw matrix scales up (e.g. video export batchMatrix ~2x), the 1x cache is upscaled → blurry text.
381
+ `BitmapData.draw()` sets `renderer.__pixelRatio = window.scale`. TextFields with filters (GlowFilter, DropShadowFilter) go through `__updateCacheBitmap` which creates the cache bitmap at `pixelRatio` resolution. On Windows (`window.scale=1`), cache bitmaps are 1x — if the draw matrix scales up (e.g. a ~2x video-export draw matrix), the 1x cache is upscaled → blurry text.
347
382
 
348
383
  **Fix**: set `pixelRatio = max(window.scale, transform_scale)` in `BitmapData.draw()` so cache bitmaps are rasterized at the final output resolution. This fixes BOTH code paths — text with filters (cache bitmap) and text without filters (Context3DTextField.render).
349
384
 
@@ -391,7 +426,7 @@ graphics.endFill();
391
426
  shape.x = containerWidth - FADE_WIDTH; // gradient at edge, solid extends past it
392
427
  ```
393
428
 
394
- Key: solid rect goes PAST `containerWidth`, not before it. Parent mask clips the visual excess, but the fill covers any children that overshoot the boundary (e.g. scrollbar offset by `barPad`). Verify with `display_find` — check child positions and widths to confirm the cover extends past all children.
429
+ Key: solid rect goes PAST `containerWidth`, not before it. Parent mask clips the visual excess, but the fill covers any children that overshoot the boundary (e.g. scrollbar offset by `barPad`). Verify by inspecting the display tree (debug-bridge query, runtime trace) — check child positions and widths to confirm the cover extends past all children.
395
430
 
396
431
  ## Actuate (Tween Library)
397
432
 
@@ -442,7 +477,7 @@ OpenFL provides utility methods that are easy to miss. Use them instead of writi
442
477
  | `HXCPP_STACK_LINE` | Line numbers (implies above) | Medium |
443
478
  | `-debug` | All above + no optimization | ~80% |
444
479
 
445
- **Crash investigation builds**: When reproducing a crash via debug bridge, always add `-DHXCPP_CHECK_POINTER` to the build flags. Without it, a Null Object Reference is a silent segfault with no stack trace — useless for diagnosis. `-debug` includes it automatically, but if already building with `-debug`, you're covered.
480
+ **Crash investigation builds**: When building a binary to reproduce a crash, always add `-DHXCPP_CHECK_POINTER` to the build flags. Without it, a Null Object Reference is a silent segfault with no stack trace — useless for diagnosis. `-debug` includes it automatically, but if already building with `-debug`, you're covered.
446
481
 
447
482
  **Null function pointer = hard crash**: `var f:Void->Void = null; f();` → C++ NULL dereference, not catchable. Check before calling.
448
483
 
@@ -515,8 +550,8 @@ this.stage.addEventListener(Event.RESIZE, handler); // if 'this' is a DisplayOb
515
550
  Logical coords → `stage.__onMouse()` requires display-matrix input space, NOT stage coordinates:
516
551
 
517
552
  ```haxe
518
- // logical (1080×670) → stage global → display input
519
- final globalPoint:Point = sceneLayer.localToGlobal(new Point(logicalX, logicalY));
553
+ // logical (app coordinate space) → stage global → display input
554
+ final globalPoint:Point = contentRoot.localToGlobal(new Point(logicalX, logicalY));
520
555
  final inputPoint:Point = stage.__displayMatrix.transformPoint(globalPoint);
521
556
  stage.__onMouse(MouseEvent.MOUSE_DOWN, inputPoint.x, inputPoint.y, 0);
522
557
  ```
@@ -531,9 +566,9 @@ Display list hit-test order: **highest index first** (front-to-back). If a trans
531
566
 
532
567
  ### Scroll events bypass OS natural-scrolling inversion
533
568
 
534
- Real scroll events: OS/SDL applies natural scrolling → Lime → OpenFL. App compensates via `ScrollContainer.inverted` flag.
569
+ Real scroll events: OS/SDL applies natural scrolling → Lime → OpenFL. Apps typically compensate with their own inversion flag on the scroll component.
535
570
 
536
- Synthetic `stage.__onMouseWheel(deltaX, deltaY, mode)` bypasses OS/SDL, so the app's compensation causes **double inversion**. Fix: negate delta when `ScrollContainer.inverted` is true before passing to `__onMouseWheel`.
571
+ Synthetic `stage.__onMouseWheel(deltaX, deltaY, mode)` bypasses OS/SDL, so the app's compensation causes **double inversion**. Fix: when the app's inversion flag is active, negate the delta before passing it to `__onMouseWheel`.
537
572
 
538
573
  ### __onMouseWheel needs __mouseX/Y set first
539
574
 
@@ -25,10 +25,13 @@
25
25
 
26
26
  ## Cross-compilation
27
27
 
28
- | From To | Flag |
29
- |-----------|------|
30
- | macOSLinux | `-cpp` (Homebrew cross-toolchains) |
31
- | Any → Windows | `-mingw` |
28
+ hxcpp selects the toolchain via defines (`-D ...`). Haxe's `-cpp <dir>` only sets the C++ output directory — it is not a cross-compilation flag.
29
+
30
+ | FromTo | Define |
31
+ |-----------|--------|
32
+ | macOS → Linux | `-D linux` (needs a Linux cross-toolchain, e.g. via Homebrew) |
33
+ | Linux → Windows | `-D windows` (selects the MinGW-w64 cross toolchain) |
34
+ | Windows: MSVC → MinGW | `-D mingw` |
32
35
 
33
36
  ## CI/CD gotchas
34
37