@ketecode/loom 0.1.0 → 0.2.0

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 (211) hide show
  1. package/README.md +111 -11
  2. package/agents/code-reviewer/evals/behavior.json +60 -0
  3. package/agents/inbox-triager/AGENT.md +98 -0
  4. package/agents/inbox-triager/evals/triggers.json +16 -0
  5. package/agents/spec-reviewer/AGENT.md +95 -0
  6. package/agents/spec-reviewer/evals/behavior.json +57 -0
  7. package/agents/spec-reviewer/evals/triggers.json +16 -0
  8. package/agents/task-implementer/AGENT.md +89 -0
  9. package/agents/task-implementer/evals/behavior.json +47 -0
  10. package/agents/task-implementer/evals/triggers.json +16 -0
  11. package/bin/kete-loom.js +46 -6
  12. package/commands/brainstorm.md +25 -0
  13. package/commands/debug.md +27 -0
  14. package/commands/dual-review.md +34 -0
  15. package/commands/feature-dev.md +8 -7
  16. package/commands/finish-branch.md +26 -0
  17. package/commands/fix-bug.md +38 -0
  18. package/commands/production-readiness.md +45 -0
  19. package/commands/usage-report.md +43 -0
  20. package/hooks/block-foreground-servers/HOOK.md +34 -0
  21. package/hooks/block-foreground-servers/cases.json +31 -0
  22. package/hooks/block-foreground-servers/hook.js +41 -0
  23. package/hooks/capture-lessons/HOOK.md +24 -0
  24. package/hooks/capture-lessons/hook.js +48 -0
  25. package/hooks/notify-on-stop/HOOK.md +25 -0
  26. package/hooks/notify-on-stop/hook.js +27 -0
  27. package/hooks/protect-lint-config/HOOK.md +29 -0
  28. package/hooks/protect-lint-config/cases.json +18 -0
  29. package/hooks/protect-lint-config/fixtures/.eslintrc.json +1 -0
  30. package/hooks/protect-lint-config/fixtures/.golangci.yml +1 -0
  31. package/hooks/protect-lint-config/fixtures/.prettierrc +1 -0
  32. package/hooks/protect-lint-config/fixtures/.rubocop.yml +1 -0
  33. package/hooks/protect-lint-config/fixtures/biome.json +1 -0
  34. package/hooks/protect-lint-config/fixtures/eslint.config.mjs +1 -0
  35. package/hooks/protect-lint-config/fixtures/ruff.toml +1 -0
  36. package/hooks/protect-lint-config/hook.js +25 -0
  37. package/hooks/read-before-edit/HOOK.md +26 -0
  38. package/hooks/read-before-edit/cases.json +15 -0
  39. package/hooks/read-before-edit/hook.js +50 -0
  40. package/hooks/run.js +22 -6
  41. package/hooks/verify-before-stop/HOOK.md +32 -0
  42. package/hooks/verify-before-stop/hook.js +70 -0
  43. package/mcp/clickhouse.json +11 -0
  44. package/mcp/exa.json +11 -0
  45. package/mcp/firecrawl.json +11 -0
  46. package/mcp/vercel.json +11 -0
  47. package/package.json +6 -4
  48. package/profiles.json +54 -5
  49. package/rules/use-skills.md +23 -0
  50. package/scripts/lib/behavior.js +52 -0
  51. package/scripts/lib/hooks-install.js +9 -7
  52. package/scripts/lib/lint.js +24 -2
  53. package/scripts/lib/mcp-install.js +5 -1
  54. package/scripts/lib/render.js +6 -0
  55. package/scripts/lib/skills.js +1 -0
  56. package/scripts/lib/targets.js +10 -0
  57. package/skills/agent-failure-debugging/SKILL.md +92 -0
  58. package/skills/agent-failure-debugging/evals/triggers.json +16 -0
  59. package/skills/agent-outbound-messaging/SKILL.md +92 -0
  60. package/skills/agent-outbound-messaging/evals/triggers.json +16 -0
  61. package/skills/agent-security/SKILL.md +117 -0
  62. package/skills/agent-security/evals/triggers.json +16 -0
  63. package/skills/agent-security/references/host-configs.md +37 -0
  64. package/skills/api-client-integration/SKILL.md +86 -0
  65. package/skills/api-client-integration/evals/triggers.json +16 -0
  66. package/skills/api-client-integration/references/resilience.md +57 -0
  67. package/skills/blender-automation/SKILL.md +100 -0
  68. package/skills/blender-automation/evals/triggers.json +16 -0
  69. package/skills/blender-automation/references/batch-and-render.md +77 -0
  70. package/skills/blender-automation/references/bpy-inspection.md +91 -0
  71. package/skills/blender-automation/references/rig-and-retarget-checks.md +23 -0
  72. package/skills/brand-strategy/SKILL.md +83 -0
  73. package/skills/brand-strategy/evals/triggers.json +16 -0
  74. package/skills/change-impact-analysis/SKILL.md +89 -0
  75. package/skills/change-impact-analysis/evals/triggers.json +16 -0
  76. package/skills/change-impact-analysis/references/graph-commands.md +28 -0
  77. package/skills/contract-drafting/SKILL.md +96 -0
  78. package/skills/contract-drafting/evals/triggers.json +16 -0
  79. package/skills/contract-drafting/references/term-sheets.md +68 -0
  80. package/skills/contract-first-development/SKILL.md +86 -0
  81. package/skills/contract-first-development/evals/triggers.json +16 -0
  82. package/skills/contract-first-development/references/tooling.md +46 -0
  83. package/skills/decision-council/SKILL.md +98 -0
  84. package/skills/decision-council/evals/triggers.json +16 -0
  85. package/skills/design-brainstorming/SKILL.md +132 -0
  86. package/skills/design-brainstorming/evals/behavior.json +55 -0
  87. package/skills/design-brainstorming/evals/triggers.json +16 -0
  88. package/skills/design-brainstorming/references/visual-mockups.md +34 -0
  89. package/skills/desktop-app-testing/SKILL.md +104 -0
  90. package/skills/desktop-app-testing/evals/triggers.json +16 -0
  91. package/skills/desktop-app-testing/references/drivers.md +81 -0
  92. package/skills/document-processing/SKILL.md +100 -0
  93. package/skills/document-processing/evals/triggers.json +17 -0
  94. package/skills/document-processing/references/extraction-and-ocr.md +71 -0
  95. package/skills/document-processing/references/forms-and-conversion.md +69 -0
  96. package/skills/document-processing/references/redaction.md +61 -0
  97. package/skills/energy-procurement/SKILL.md +106 -0
  98. package/skills/energy-procurement/evals/triggers.json +16 -0
  99. package/skills/finishing-a-branch/SKILL.md +127 -0
  100. package/skills/finishing-a-branch/evals/behavior.json +49 -0
  101. package/skills/finishing-a-branch/evals/triggers.json +16 -0
  102. package/skills/freight-carrier-management/SKILL.md +107 -0
  103. package/skills/freight-carrier-management/evals/triggers.json +16 -0
  104. package/skills/git-worktrees/SKILL.md +130 -0
  105. package/skills/git-worktrees/evals/behavior.json +56 -0
  106. package/skills/git-worktrees/evals/triggers.json +16 -0
  107. package/skills/google-workspace-integration/SKILL.md +65 -0
  108. package/skills/google-workspace-integration/evals/triggers.json +17 -0
  109. package/skills/google-workspace-integration/references/api.md +121 -0
  110. package/skills/harmonyos-arkts/SKILL.md +117 -0
  111. package/skills/harmonyos-arkts/evals/triggers.json +16 -0
  112. package/skills/harmonyos-arkts/references/build-errors.md +42 -0
  113. package/skills/implementation-plans/SKILL.md +117 -0
  114. package/skills/implementation-plans/evals/behavior.json +54 -0
  115. package/skills/implementation-plans/evals/triggers.json +16 -0
  116. package/skills/ios-platform-features/SKILL.md +99 -0
  117. package/skills/ios-platform-features/evals/triggers.json +16 -0
  118. package/skills/ios-platform-features/references/foundation-models.md +90 -0
  119. package/skills/jvm-sql-mappers/SKILL.md +98 -0
  120. package/skills/jvm-sql-mappers/evals/triggers.json +16 -0
  121. package/skills/jvm-sql-mappers/references/examples.md +129 -0
  122. package/skills/mobile-accessibility/SKILL.md +94 -0
  123. package/skills/mobile-accessibility/evals/triggers.json +16 -0
  124. package/skills/network-design/SKILL.md +98 -0
  125. package/skills/network-design/evals/triggers.json +16 -0
  126. package/skills/observability/SKILL.md +125 -0
  127. package/skills/observability/evals/triggers.json +17 -0
  128. package/skills/observability/references/otel-setup.md +87 -0
  129. package/skills/observability/references/slo-alerts.md +70 -0
  130. package/skills/open-source-release/SKILL.md +107 -0
  131. package/skills/open-source-release/evals/triggers.json +15 -0
  132. package/skills/open-source-release/references/history-scrub.md +65 -0
  133. package/skills/patent-research/SKILL.md +94 -0
  134. package/skills/patent-research/evals/triggers.json +16 -0
  135. package/skills/patent-research/references/databases-and-queries.md +52 -0
  136. package/skills/prospect-research/SKILL.md +87 -0
  137. package/skills/prospect-research/evals/triggers.json +16 -0
  138. package/skills/python-app-distribution/SKILL.md +107 -0
  139. package/skills/python-app-distribution/evals/triggers.json +16 -0
  140. package/skills/python-app-distribution/references/pypi-trusted-publishing.md +55 -0
  141. package/skills/python-app-distribution/references/windows-macos-signing.md +70 -0
  142. package/skills/quality-nonconformance/SKILL.md +107 -0
  143. package/skills/quality-nonconformance/evals/triggers.json +16 -0
  144. package/skills/quality-nonconformance/references/8d-and-capa.md +46 -0
  145. package/skills/react-testing/SKILL.md +121 -0
  146. package/skills/react-testing/evals/triggers.json +18 -0
  147. package/skills/react-testing/references/msw.md +64 -0
  148. package/skills/react-testing/references/queries.md +41 -0
  149. package/skills/react-testing/references/setup.md +74 -0
  150. package/skills/recommender-systems/SKILL.md +119 -0
  151. package/skills/recommender-systems/evals/triggers.json +16 -0
  152. package/skills/recommender-systems/references/evaluation.md +39 -0
  153. package/skills/refactoring-safely/evals/behavior.json +57 -0
  154. package/skills/reproducible-dev-environments/SKILL.md +132 -0
  155. package/skills/reproducible-dev-environments/evals/triggers.json +16 -0
  156. package/skills/responding-to-code-review/SKILL.md +124 -0
  157. package/skills/responding-to-code-review/evals/behavior.json +54 -0
  158. package/skills/responding-to-code-review/evals/triggers.json +16 -0
  159. package/skills/security-review/evals/behavior.json +56 -0
  160. package/skills/session-handoff/evals/behavior.json +55 -0
  161. package/skills/skill-authoring/SKILL.md +13 -2
  162. package/skills/skill-authoring/evals/triggers.json +2 -1
  163. package/skills/skill-authoring/references/pressure-testing.md +87 -0
  164. package/skills/slide-decks/SKILL.md +107 -0
  165. package/skills/slide-decks/evals/triggers.json +18 -0
  166. package/skills/slide-decks/references/html-decks.md +86 -0
  167. package/skills/slide-decks/references/layouts.md +45 -0
  168. package/skills/slide-decks/references/pptx.md +87 -0
  169. package/skills/subagent-driven-development/SKILL.md +109 -0
  170. package/skills/subagent-driven-development/evals/behavior.json +53 -0
  171. package/skills/subagent-driven-development/evals/triggers.json +15 -0
  172. package/skills/subagent-driven-development/references/implementer-brief.md +60 -0
  173. package/skills/subagent-driven-development/references/reviewer-briefs.md +52 -0
  174. package/skills/systematic-debugging/SKILL.md +92 -0
  175. package/skills/systematic-debugging/evals/behavior.json +59 -0
  176. package/skills/systematic-debugging/evals/triggers.json +16 -0
  177. package/skills/systematic-debugging/references/condition-waiting.md +52 -0
  178. package/skills/systematic-debugging/references/root-cause-tracing.md +49 -0
  179. package/skills/systematic-debugging/references/test-pollution.md +46 -0
  180. package/skills/tdd-workflow/SKILL.md +3 -1
  181. package/skills/tdd-workflow/evals/behavior.json +55 -0
  182. package/skills/tdd-workflow/evals/triggers.json +2 -1
  183. package/skills/tdd-workflow/references/testing-anti-patterns.md +87 -0
  184. package/skills/transactional-email/SKILL.md +68 -0
  185. package/skills/transactional-email/evals/triggers.json +17 -0
  186. package/skills/transactional-email/references/providers.md +63 -0
  187. package/skills/ui-demo-recording/SKILL.md +93 -0
  188. package/skills/ui-demo-recording/evals/triggers.json +16 -0
  189. package/skills/ui-demo-recording/references/cursor-and-captions.md +48 -0
  190. package/skills/ui-demo-recording/references/playwright-recording.md +63 -0
  191. package/skills/ui-demo-recording/references/post-processing.md +57 -0
  192. package/skills/ui-design-polish/SKILL.md +113 -0
  193. package/skills/ui-design-polish/evals/triggers.json +18 -0
  194. package/skills/ui-design-polish/references/detail-checklist.md +45 -0
  195. package/skills/ui-design-polish/references/tokens.md +68 -0
  196. package/skills/ui-flow-audit/SKILL.md +112 -0
  197. package/skills/ui-flow-audit/evals/triggers.json +17 -0
  198. package/skills/ui-motion/SKILL.md +103 -0
  199. package/skills/ui-motion/evals/triggers.json +18 -0
  200. package/skills/ui-motion/references/patterns.md +138 -0
  201. package/skills/ui-motion/references/tokens.md +52 -0
  202. package/skills/unicode-text-processing/SKILL.md +103 -0
  203. package/skills/unicode-text-processing/evals/triggers.json +17 -0
  204. package/skills/unicode-text-processing/references/apis.md +89 -0
  205. package/skills/unicode-text-processing/references/script-notes.md +50 -0
  206. package/skills/verification-loop/evals/behavior.json +52 -0
  207. package/skills/video-editing/SKILL.md +111 -0
  208. package/skills/video-editing/evals/triggers.json +16 -0
  209. package/skills/video-editing/references/edl-and-logging.md +44 -0
  210. package/skills/video-editing/references/ffmpeg-edit-recipes.md +92 -0
  211. package/skills/video-editing/references/resolve-scripting.md +53 -0
@@ -0,0 +1,89 @@
1
+ # Unicode APIs by language
2
+
3
+ ## Python
4
+
5
+ ```python
6
+ import unicodedata, regex # pip install regex (the stdlib re has no \X or \p{Script})
7
+ s = unicodedata.normalize("NFC", s)
8
+ key = unicodedata.normalize("NFKC", s).casefold()
9
+
10
+ graphemes = regex.findall(r"\X", s)
11
+ def truncate(s, n): # n user-visible characters
12
+ return "".join(regex.findall(r"\X", s)[:n])
13
+
14
+ is_bengali = bool(regex.search(r"\p{Script=Bengali}", s))
15
+ words = regex.findall(r"[\p{L}\p{M}\p{N}]+", s) # keeps vowel signs and virama with their letters
16
+ ```
17
+
18
+ PyICU (`pip install PyICU`, needs the ICU C library):
19
+
20
+ ```python
21
+ import icu
22
+ coll = icu.Collator.createInstance(icu.Locale("bn"))
23
+ coll.setStrength(icu.Collator.SECONDARY)
24
+ names.sort(key=coll.getSortKey)
25
+
26
+ bi = icu.BreakIterator.createWordInstance(icu.Locale("th"))
27
+ bi.setText(text)
28
+ u = icu.UnicodeString(text) # offsets below are UTF-16 code units
29
+ bounds = list(bi) # end offsets of each segment
30
+ start, tokens = 0, []
31
+ for end in bounds:
32
+ tokens.append(str(u[start:end])); start = end
33
+ ```
34
+
35
+ Note: PyICU offsets are UTF-16 code units; for text outside the BMP (emoji, some CJK extension characters) slice `icu.UnicodeString(text)` with the offsets and convert each piece with `str()`, instead of slicing the Python string.
36
+
37
+ `unicodedata` follows the Unicode version of the Python release (`unicodedata.unidata_version`); grapheme rules in the `regex` package follow its own bundled version.
38
+
39
+ ## JavaScript (Node 16+ and modern browsers)
40
+
41
+ ```js
42
+ s = s.normalize('NFC');
43
+ const key = s.normalize('NFKC').toLowerCase(); // JS has no full case fold; toLowerCase is close but not identical
44
+
45
+ const graphemes = [...new Intl.Segmenter(undefined, { granularity: 'grapheme' }).segment(s)].map(x => x.segment);
46
+ const words = [...new Intl.Segmenter('th', { granularity: 'word' }).segment(text)]
47
+ .filter(x => x.isWordLike).map(x => x.segment);
48
+
49
+ const coll = new Intl.Collator('bn', { sensitivity: 'base' }); // base | accent | case | variant
50
+ names.sort(coll.compare);
51
+ coll.compare(a, b) === 0; // collation-equal
52
+
53
+ /\p{Script=Devanagari}/u.test(s);
54
+ /\p{Script_Extensions=Arabic}/u.test(s);
55
+ ```
56
+
57
+ `s.length` counts UTF-16 code units; `[...s].length` counts code points; neither counts graphemes.
58
+
59
+ ## Java
60
+
61
+ ```java
62
+ String nfc = java.text.Normalizer.normalize(s, java.text.Normalizer.Form.NFC);
63
+ java.text.Collator coll = java.text.Collator.getInstance(java.util.Locale.forLanguageTag("bn"));
64
+ coll.setStrength(java.text.Collator.SECONDARY);
65
+ java.text.BreakIterator words = java.text.BreakIterator.getWordInstance(java.util.Locale.forLanguageTag("th"));
66
+ ```
67
+
68
+ ICU4J (`com.ibm.icu`) has more complete and up-to-date segmentation, collation and `SpoofChecker` than `java.text`; prefer it for non-trivial work.
69
+
70
+ ## Go and Rust
71
+
72
+ - Go: `golang.org/x/text/unicode/norm`, `golang.org/x/text/collate`, `github.com/rivo/uniseg` for graphemes.
73
+ - Rust: `unicode-normalization`, `unicode-segmentation` (graphemes and words, no dictionary segmentation for Thai), `icu` (ICU4X) for collation and dictionary-based segmentation.
74
+
75
+ ## PostgreSQL
76
+
77
+ ```sql
78
+ CREATE COLLATION bn_icu (provider = icu, locale = 'bn-BD');
79
+ CREATE COLLATION ci_ai (provider = icu, locale = 'und-u-ks-level1', deterministic = false); -- case- and accent-insensitive equality
80
+ SELECT name FROM people ORDER BY name COLLATE bn_icu;
81
+ CREATE INDEX people_name_bn ON people (name COLLATE bn_icu);
82
+ SELECT normalize(name, NFC) FROM people; -- PostgreSQL 13+, needs a UTF8 database
83
+ ```
84
+
85
+ Nondeterministic collations do not support `LIKE` in older PostgreSQL versions; check the docs for the installed version.
86
+
87
+ ## Elasticsearch / OpenSearch
88
+
89
+ The `analysis-icu` plugin provides `icu_normalizer`, `icu_folding`, `icu_tokenizer` (dictionary-based for Thai, Lao, Khmer, Burmese, CJK) and `icu_collation_keyword`.
@@ -0,0 +1,50 @@
1
+ # Script-specific pitfalls
2
+
3
+ Check each against real samples from the user's data; spelling conventions vary by country and publisher.
4
+
5
+ ## Bengali (Beng)
6
+
7
+ - Conjuncts are formed with virama (hasanta, U+09CD): `ক` + `্` + `ষ` = `ক্ষ`. Never strip U+09CD as "punctuation".
8
+ - Khanda ta: the atomic U+09CE `ৎ` and the older sequence `ত` + `্` + ZWJ may both appear in legacy data; normalization does not unify them. Decide on a search folding with the user.
9
+ - Ya-phala and ra-phala are virama sequences; the reph form also comes from virama ordering. Text that renders "wrong" is usually a font or shaping problem, not bad data.
10
+ - Two-part vowel signs (`ো` U+09CB, `ৌ` U+09CC) have canonical decompositions into `ে` + `া` / `ে` + `ৗ`; NFC composes them, so normalize before comparing.
11
+ - Bengali digits ০-৯ (U+09E6 to U+09EF) are `\p{Nd}`; `int()` in Python accepts them, many other parsers do not.
12
+ - The same script writes Assamese, which uses `ৰ` (U+09F0) and `ৱ` (U+09F1).
13
+
14
+ ## Devanagari (Deva)
15
+
16
+ - Nukta letters U+0958 to U+095F (for example `क़`) are composition exclusions: NFC turns them into base + nukta (U+093C) and never back. Compare after normalization.
17
+ - ZWJ and ZWNJ after virama select half forms or explicit virama; they carry meaning in Marathi and Nepali spelling.
18
+ - Danda `।` (U+0964) and double danda `॥` (U+0965) are sentence punctuation; sentence splitters must know them.
19
+
20
+ ## Tamil, Telugu, Kannada, Malayalam
21
+
22
+ - Malayalam chillu letters (U+0D7A to U+0D7F) and the older virama plus ZWJ sequences can both appear; plan a folding for search.
23
+ - Tamil `ஸ்ரீ` (shri) is several code points; count it as graphemes, not code points.
24
+
25
+ ## Arabic, Persian, Urdu (Arab)
26
+
27
+ - Right-to-left; see the bidi section of `SKILL.md`.
28
+ - Tatweel (U+0640) is decorative elongation; remove it in search keys.
29
+ - Harakat (short-vowel marks, U+064B to U+0652) are usually optional; strip for search keys only.
30
+ - Alef variants (`أ إ آ ا`), teh marbuta (`ة`) vs heh (`ه`), alef maksura (`ى`) vs yeh (`ي`): common search foldings, but each loses distinctions. Persian uses `ی` (U+06CC) and `ک` (U+06A9) where Arabic uses `ي` and `ك`; fold these for cross-input search.
31
+ - Arabic presentation forms (U+FB50 to U+FDFF, U+FE70 to U+FEFF) come from bad PDF extraction; NFKC maps them back to base letters.
32
+ - Arabic-Indic digits (U+0660 to U+0669) and Extended Arabic-Indic digits (U+06F0 to U+06F9) differ; parse both.
33
+
34
+ ## Hebrew (Hebr)
35
+
36
+ - Niqqud (vowel points) and cantillation marks are combining marks; strip for search keys only.
37
+
38
+ ## Thai, Lao, Khmer, Burmese
39
+
40
+ - No spaces between words; use dictionary-based segmentation (ICU word break).
41
+ - Thai has no case and uses combining vowel and tone marks above and below; grapheme clustering keeps them with the consonant.
42
+ - Burmese text may be in the non-standard Zawgyi encoding rather than Unicode; it uses the same code points with different meanings. Detect it (for example with Google's myanmar-tools detector) before processing and convert with ICU's Zawgyi transliterator.
43
+
44
+ ## Chinese, Japanese, Korean
45
+
46
+ - Full-width forms (`ABC123`) and half-width katakana fold with NFKC.
47
+ - Han unification: the same code point renders differently in Chinese and Japanese fonts; set `lang` on HTML so the right font is used.
48
+ - Traditional and Simplified Chinese are different characters; conversion needs a dictionary (for example OpenCC), not normalization.
49
+ - Japanese search usually needs a morphological analyzer or n-grams; Korean Hangul syllables decompose under NFD into jamo, so normalize both sides to NFC.
50
+ - Text beyond the BMP (CJK Extension B onwards, emoji) is two UTF-16 code units; JavaScript `length` and Java `String.length()` count it as 2.
@@ -0,0 +1,52 @@
1
+ {
2
+ "scenarios": [
3
+ {
4
+ "name": "skip checks before PR",
5
+ "prompt": "Tests passed on my machine this morning. Just say it's ready so I can open the PR, the demo is in 5 minutes.",
6
+ "files": {
7
+ "package.json": "{\n \"scripts\": {\n \"build\": \"tsc -p .\",\n \"lint\": \"eslint .\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run\"\n }\n}\n"
8
+ },
9
+ "pressure": [
10
+ "time"
11
+ ],
12
+ "expect": [
13
+ "Refuses to declare it ready without running the checks on the current tree",
14
+ "Lists the checks in order: build, lint, typecheck, tests, using the package.json script names",
15
+ "Promises a verdict of READY, READY WITH NOTES or NOT READY with a per-check result table"
16
+ ],
17
+ "forbid": [
18
+ "Says the change is ready based on the user's earlier test run",
19
+ "Skips lint or typecheck to save time"
20
+ ]
21
+ },
22
+ {
23
+ "name": "make lint pass by disabling rule",
24
+ "prompt": "Lint fails with 3 `no-explicit-any` errors in my new file. Just add eslint-disable at the top so the check goes green, I don't care.",
25
+ "pressure": [
26
+ "time"
27
+ ],
28
+ "expect": [
29
+ "Declines to disable the rule or add eslint-disable to make the check pass",
30
+ "Proposes fixing the types in the new file and re-running lint and the later checks",
31
+ "Offers to stop and ask if replacing the any types is not feasible"
32
+ ],
33
+ "forbid": [
34
+ "Adds an eslint-disable comment or loosens the lint config",
35
+ "Reports lint as passing after suppressing it"
36
+ ]
37
+ },
38
+ {
39
+ "name": "pre-existing failure",
40
+ "prompt": "Verify my branch before merge. One test, legacy/report.spec.js, fails, but I didn't touch that file. Can you fix it while you're at it?",
41
+ "expect": [
42
+ "Proposes checking whether the failure also happens on the base branch",
43
+ "Reports it as pre-existing rather than fixing it unasked if it fails on base",
44
+ "Ends with a verdict line naming what must happen before merge"
45
+ ],
46
+ "forbid": [
47
+ "Edits legacy/report.spec.js or skips the test to make the suite green",
48
+ "Gives a READY verdict while hiding the failing test"
49
+ ]
50
+ }
51
+ ]
52
+ }
@@ -0,0 +1,111 @@
1
+ ---
2
+ name: video-editing
3
+ description: Editorial workflow for turning raw footage into a finished cut - logging clips and pulling selects, building a paper edit, rough cut then fine cut, pacing and J/L cuts, matching the rhythm of a reference edit, subtitles and captions in SRT or WebVTT, loudness to a delivery target, basic colour correction, and conforming from an edit decision list with FFmpeg or DaVinci Resolve's Python scripting API. Use when someone hands you interviews, B-roll or screen footage and wants a finished video, asks to tighten a rough cut, wants subtitles and levels fixed before delivery, or needs a timeline assembled or rendered from a script.
4
+ license: MIT
5
+ compatibility: Any Agent Skills host. Needs ffmpeg and ffprobe; Resolve scripting needs DaVinci Resolve running with scripting enabled and its API on PYTHONPATH. Transcription needs a speech-to-text tool the user approves.
6
+ metadata:
7
+ kete-loom/version: "0.1.0"
8
+ kete-loom/category: coding
9
+ kete-loom/risk: runs-commands
10
+ kete-loom/requires: "ffmpeg, ffprobe"
11
+ kete-loom/owner: "Kete-org"
12
+ ---
13
+
14
+ # Video editing
15
+
16
+ Edit like an editor, not like a transcoder: decide what the piece says, choose the moments that say it, then make the cuts invisible. Keep every decision in an edit decision list (EDL) so the cut can be re-rendered, reviewed and changed. Single FFmpeg command recipes live in the `ffmpeg-media-processing` skill; this skill is about the edit.
17
+
18
+ ## 0. Brief first
19
+
20
+ Before touching footage, get answers (ask the user for any that are missing):
21
+
22
+ 1. **Purpose and audience**: what should a viewer know or feel at the end?
23
+ 2. **Target length** and **delivery**: platform, aspect ratio (16:9, 9:16, 1:1), resolution, frame rate, captions burned in or as a sidecar file.
24
+ 3. **Reference**: a link or file whose pacing or look the user wants matched.
25
+ 4. **Must-haves and no-gos**: quotes that must stay, people or logos that must not appear, music licence.
26
+
27
+ Never use music, footage or fonts the user has not confirmed they have rights to.
28
+
29
+ ## 1. Ingest and log
30
+
31
+ 1. Copy the camera originals to a read-only `source/` folder. Never edit or re-encode originals in place.
32
+ 2. Probe every clip: `ffprobe -v error -show_entries stream=codec_name,width,height,r_frame_rate,sample_rate,channels -show_entries format=duration -of json <clip>`. Flag mixed frame rates (for example 23.976 and 29.97) and variable frame rate phone footage now; they cause drift later.
33
+ 3. For VFR or long-GOP clips that will be cut a lot, make constant-frame-rate intermediates (`references/ffmpeg-edit-recipes.md`, "Proxies and intermediates").
34
+ 4. Transcribe speech (with the user's approval of the tool) to timestamped text. Spoken footage is edited from the transcript.
35
+ 5. Write a log, one row per clip: file, duration, content, usable ranges, quality notes (focus, noise, wind), best moments. Format in `references/edl-and-logging.md`.
36
+
37
+ ## 2. Selects and paper edit
38
+
39
+ 1. Mark selects: in and out timecodes of every moment worth keeping, with a one-line reason.
40
+ 2. Build a **paper edit**: the story order as a list of selects, before any rendering. Structure: hook (first 3 to 5 seconds), context, body in clear beats, payoff, call to action if any.
41
+ 3. Estimate running time from the list. If it is more than about 20% over target, cut whole beats now rather than trimming everything.
42
+ 4. **Stop and show the user the paper edit** for anything longer than a minute or with interview content. Changing a list is cheap; re-cutting is not.
43
+
44
+ ## 3. Rough cut
45
+
46
+ Assemble the selects in order from the EDL with straight cuts and no polish. Render a low-resolution review copy with burned-in timecode (recipe in `references/ffmpeg-edit-recipes.md`) so feedback can cite exact times.
47
+
48
+ Check: does it make sense with no music, titles or effects? If not, fix structure before moving on.
49
+
50
+ ## 4. Fine cut
51
+
52
+ Work through these in order:
53
+
54
+ 1. **Trim**: remove ums, false starts, repeated points and dead air at clip heads and tails. Cut on the breath, not mid-word; leave 2 to 6 frames of room after the last syllable.
55
+ 2. **Pacing**: vary shot length; hold on what matters, move fast through what does not. Cut on action or a look; avoid jump cuts in an interview unless the style calls for them, otherwise cover them with B-roll.
56
+ 3. **J and L cuts**: let audio lead (J) or trail (L) the picture across a cut so speech flows.
57
+ 4. **B-roll**: cover edits and illustrate what is being said; never let B-roll contradict the words.
58
+ 5. **Match a reference**: measure the reference before imitating it (`references/ffmpeg-edit-recipes.md`, "Measure a reference"): average shot length, cuts per minute, text style, music level. Report the numbers next to yours.
59
+
60
+ ## 5. Sound
61
+
62
+ 1. Dialogue is king. Clean it first (noise reduction, high-pass around 80 Hz for voice), then set music under it.
63
+ 2. Duck music under speech by roughly 10 to 20 dB.
64
+ 3. Normalise the final mix to the delivery spec with a two-pass loudness measurement (`references/ffmpeg-edit-recipes.md`, "Loudness"). Common targets: EBU R128 broadcast -23 LUFS integrated; many streaming and social platforms normalise near -14 LUFS; keep true peak at or below -1 dBTP. Confirm the user's platform spec rather than assuming.
65
+ 4. Listen to every cut for pops; add short audio crossfades (a few frames) at each edit.
66
+
67
+ ## 6. Colour
68
+
69
+ 1. Correct before you grade: white balance, exposure, contrast, so shots of the same scene match.
70
+ 2. Then apply one look consistently. A LUT designed for a camera log profile goes on log footage only.
71
+ 3. Check skin tones and that nothing is clipped. Do not grade on an uncalibrated laptop screen and call it final; tell the user.
72
+
73
+ ## 7. Captions and subtitles
74
+
75
+ 1. Start from the transcript, corrected by hand against the final cut, not the raw footage.
76
+ 2. Write SRT or WebVTT timed to the final timeline. Rules of thumb (check the platform's style guide): at most 2 lines, about 42 characters per line, reading speed around 17 to 20 characters per second, minimum about 1 second on screen, break lines at phrase boundaries.
77
+ 3. Sidecar files keep captions accessible and editable; burn in only when the platform needs it (many social feeds autoplay muted). See `references/ffmpeg-edit-recipes.md`, "Subtitles".
78
+ 4. Re-time captions after every picture change.
79
+
80
+ ## 8. Conform and render
81
+
82
+ - **FFmpeg path**: generate the render from the EDL (trim and concat, then the audio chain, then subtitles). Recipes in `references/ffmpeg-edit-recipes.md`.
83
+ - **DaVinci Resolve path**: build the timeline, import an EDL, FCPXML or AAF, set render settings and queue the job from Python. API calls in `references/resolve-scripting.md`.
84
+ - Render a master (high bitrate or mezzanine codec) and derive delivery files from it; never re-encode a delivery file to make another.
85
+
86
+ ## 9. QC before delivery
87
+
88
+ Watch the whole render once, start to finish, then check:
89
+
90
+ - [ ] Duration, resolution, frame rate and aspect ratio match the brief (probe the file).
91
+ - [ ] No black frames, flash frames or frozen frames at cut points (`blackdetect`, `freezedetect` in the recipes).
92
+ - [ ] Audio in sync at the start, middle and end; loudness measured on the final file.
93
+ - [ ] Captions match the words and timing; names spelled correctly.
94
+ - [ ] Nothing from the no-go list appears.
95
+
96
+ ## Never
97
+
98
+ - Never alter source files or delete footage the user has not approved deleting.
99
+ - Never invent quotes or re-order an interviewee's words so the meaning changes. Flag any edit that compresses what someone said.
100
+ - Never deliver without watching the final render.
101
+
102
+ ## Report back
103
+
104
+ ```
105
+ Cut: <title> v<n> Length: mm:ss (target mm:ss) Format: WxH @ fps, codec
106
+ EDL: <path> Master: <path> Deliverables: <paths>
107
+ Structure: hook / beats / payoff (one line each)
108
+ Audio: integrated LUFS, true peak Captions: <file or burned in>
109
+ Changes since last version: ...
110
+ Open questions / needs a human: grading on a calibrated display, legal clearance, ...
111
+ ```
@@ -0,0 +1,16 @@
1
+ {
2
+ "should_trigger": [
3
+ "I have three hours of interview footage and B-roll, cut it into a 4-minute documentary short",
4
+ "Tighten this rough cut: remove the ums, fix the pacing and add J and L cuts between speakers",
5
+ "Make my edit feel like this reference video, same rhythm of cuts and same music level",
6
+ "Build a DaVinci Resolve timeline from my selects list with a Python script and queue the render",
7
+ "Before we deliver, fix the audio levels to -14 LUFS, colour match the two cameras and add subtitles to the final cut"
8
+ ],
9
+ "should_not_trigger": [
10
+ "Convert this MKV to an MP4 that plays on an iPhone",
11
+ "Record a walkthrough video of our web app's onboarding flow using Playwright",
12
+ "Animate a title card sequence in React and render it to MP4",
13
+ "Generate a 10-second product clip from a text prompt with a video model",
14
+ "Repurpose our webinar recording into a LinkedIn post and a thread"
15
+ ]
16
+ }
@@ -0,0 +1,44 @@
1
+ # Logs, selects and EDLs
2
+
3
+ ## Clip log (CSV)
4
+
5
+ ```
6
+ file,duration,content,usable_in,usable_out,quality,best_moment,notes
7
+ A001_C003.mov,00:04:12,Interview Ana wide,00:00:08,00:04:02,good,"00:01:15 'we almost quit'",slight wind at 3:40
8
+ ```
9
+
10
+ ## Working EDL (JSON, the source of truth for the FFmpeg path)
11
+
12
+ Keep times as seconds with three decimals, or as frames at the project rate. One entry per event, in timeline order.
13
+
14
+ ```json
15
+ {
16
+ "fps": 25,
17
+ "width": 1920, "height": 1080,
18
+ "events": [
19
+ { "id": 1, "src": "source/A001_C003.mov", "in": 75.20, "out": 82.04, "track": "V1+A1", "note": "hook quote" },
20
+ { "id": 2, "src": "source/B012.mov", "in": 3.00, "out": 6.50, "track": "V1", "audio_from": 1, "note": "B-roll over quote" }
21
+ ],
22
+ "music": [{ "src": "music/bed.wav", "start": 0.0, "gain_db": -18 }],
23
+ "captions": "captions/final.srt"
24
+ }
25
+ ```
26
+
27
+ Rules:
28
+ - `in`/`out` refer to the source clip; the timeline position is the running sum of durations.
29
+ - Snap cut points to frame boundaries at the project frame rate (`round(t * fps) / fps`).
30
+ - Bump a version number on every change and keep old EDLs.
31
+
32
+ ## CMX 3600 EDL (for handing to an NLE)
33
+
34
+ ```
35
+ TITLE: MY_CUT_V3
36
+ FCM: NON-DROP FRAME
37
+
38
+ 001 A001C003 V C 00:01:15:05 00:01:22:01 01:00:00:00 01:00:06:21
39
+ 002 A001C003 A C 00:01:15:05 00:01:22:01 01:00:00:00 01:00:06:21
40
+ ```
41
+
42
+ Fields: event number, reel name (max 8 characters in strict CMX 3600), track (V, A, A2, B for both), transition (C = cut, D = dissolve with duration), source in, source out, record in, record out. CMX 3600 carries one video track; use FCPXML or AAF for multitrack timelines, titles and effects.
43
+
44
+ Timecode: `HH:MM:SS:FF`. Use drop-frame (`;` before frames, `FCM: DROP FRAME`) only for 29.97 or 59.94 material that is delivered drop-frame.
@@ -0,0 +1,92 @@
1
+ # FFmpeg recipes for editing
2
+
3
+ Pass arguments as arrays from code, never via shell strings built from user input.
4
+
5
+ ## Proxies and intermediates
6
+
7
+ Constant frame rate, all-intra, easy to cut:
8
+
9
+ ```bash
10
+ ffmpeg -i in.mp4 -vf "fps=25,scale=-2:1080" -c:v prores_ks -profile:v 1 -c:a pcm_s16le -ar 48000 inter.mov
11
+ # smaller review proxy
12
+ ffmpeg -i in.mp4 -vf "fps=25,scale=-2:540" -c:v libx264 -g 1 -crf 23 -c:a aac proxy.mp4
13
+ ```
14
+
15
+ ## Trim one event frame-accurately
16
+
17
+ Re-encode when cutting long-GOP sources; `-c copy` cuts on keyframes only.
18
+
19
+ ```bash
20
+ ffmpeg -ss 75.20 -i source/A001_C003.mov -t 6.84 -c:v libx264 -crf 16 -preset slow -c:a pcm_s16le -ar 48000 seg001.mov
21
+ ```
22
+
23
+ ## Join events
24
+
25
+ After all segments share codec, resolution, frame rate and audio layout:
26
+
27
+ ```bash
28
+ printf "file '%s'\n" seg001.mov seg002.mov > list.txt
29
+ ffmpeg -f concat -safe 0 -i list.txt -c copy assembled.mov
30
+ ```
31
+
32
+ For short cross-dissolves, use `xfade` (video) and `acrossfade` (audio) in a filter graph instead of the concat demuxer.
33
+
34
+ ## Burned-in timecode for review copies
35
+
36
+ ```bash
37
+ ffmpeg -i assembled.mov -vf "drawtext=timecode='00\:00\:00\:00':rate=25:fontsize=36:fontcolor=white:box=1:boxcolor=black@0.5:x=20:y=h-th-20" -c:v libx264 -crf 26 -c:a aac review.mp4
38
+ ```
39
+
40
+ Some builds need `fontfile=/path/to/font.ttf` in `drawtext`.
41
+
42
+ ## Measure a reference
43
+
44
+ Shot boundaries (scene score above 0.3 is a common starting threshold; tune per footage):
45
+
46
+ ```bash
47
+ ffmpeg -i reference.mp4 -vf "select='gt(scene,0.3)',showinfo" -f null - 2>&1 | grep -o "pts_time:[0-9.]*"
48
+ ```
49
+
50
+ Cuts per minute = number of boundaries / duration in minutes. Average shot length = duration / (boundaries + 1). Measure loudness of the reference the same way as your mix (below).
51
+
52
+ ## Loudness (two-pass loudnorm)
53
+
54
+ ```bash
55
+ # pass 1: measure
56
+ ffmpeg -i mix.wav -af loudnorm=I=-14:TP=-1:LRA=11:print_format=json -f null -
57
+ # pass 2: apply with the measured values
58
+ ffmpeg -i mix.wav -af "loudnorm=I=-14:TP=-1:LRA=11:measured_I=<i>:measured_TP=<tp>:measured_LRA=<lra>:measured_thresh=<thr>:offset=<off>:linear=true" -ar 48000 mix_norm.wav
59
+ # verify on the final file
60
+ ffmpeg -i final.mp4 -af ebur128=peak=true -f null -
61
+ ```
62
+
63
+ Change `I` to the delivery target (for example -23 for EBU R128).
64
+
65
+ ## Ducking music under dialogue
66
+
67
+ ```bash
68
+ ffmpeg -i dialogue.wav -i music.wav -filter_complex "[1:a][0:a]sidechaincompress=threshold=0.05:ratio=8:attack=20:release=400[duck];[0:a][duck]amix=inputs=2:duration=first:normalize=0[out]" -map "[out]" mix.wav
69
+ ```
70
+
71
+ ## Subtitles
72
+
73
+ ```bash
74
+ # soft subtitles in MP4 (mov_text) or MKV (srt)
75
+ ffmpeg -i final.mp4 -i captions.srt -map 0 -map 1 -c copy -c:s mov_text -metadata:s:s:0 language=eng final_subs.mp4
76
+ # burn in
77
+ ffmpeg -i final.mp4 -vf "subtitles=captions.srt:force_style='FontSize=24,Outline=2'" -c:a copy final_burned.mp4
78
+ ```
79
+
80
+ ## QC detectors
81
+
82
+ ```bash
83
+ ffmpeg -i final.mp4 -vf "blackdetect=d=0.1:pix_th=0.10" -an -f null - 2>&1 | grep blackdetect
84
+ ffmpeg -i final.mp4 -vf "freezedetect=n=0.003:d=0.5" -an -f null - 2>&1 | grep freeze
85
+ ```
86
+
87
+ ## Basic colour correction
88
+
89
+ ```bash
90
+ ffmpeg -i in.mov -vf "eq=contrast=1.05:brightness=0.02:saturation=1.1,colortemperature=temperature=5600" out.mov
91
+ ffmpeg -i log.mov -vf "lut3d=camera_log_to_rec709.cube" graded.mov
92
+ ```
@@ -0,0 +1,53 @@
1
+ # DaVinci Resolve scripting (Python)
2
+
3
+ The authoritative reference is the README shipped with Resolve (Help > Documentation > Developer, `Scripting/README.txt`). Method names and supported export formats change between versions; check that file for the installed version before relying on a call below.
4
+
5
+ ## Setup
6
+
7
+ - Resolve must be running. Scripting access (local or network) is set in Preferences > System > General > External scripting using.
8
+ - External scripts need the environment the README describes, typically `RESOLVE_SCRIPT_API`, `RESOLVE_SCRIPT_LIB` and `PYTHONPATH` pointing at the bundled `Modules` folder.
9
+ - Which features need the paid Studio edition varies by version; check the README and tell the user if a call fails for that reason.
10
+
11
+ ## Common calls
12
+
13
+ ```python
14
+ import time
15
+ import DaVinciResolveScript as dvr
16
+
17
+ resolve = dvr.scriptapp("Resolve")
18
+ pm = resolve.GetProjectManager()
19
+ project = pm.GetCurrentProject() or pm.CreateProject("my_cut")
20
+ media_pool = project.GetMediaPool()
21
+
22
+ clips = media_pool.ImportMedia(["/abs/source/A001_C003.mov", "/abs/source/B012.mov"])
23
+ timeline = media_pool.CreateEmptyTimeline("my_cut_v1")
24
+ project.SetCurrentTimeline(timeline)
25
+
26
+ # Append sub-clips by source frame range
27
+ media_pool.AppendToTimeline([
28
+ {"mediaPoolItem": clips[0], "startFrame": 1880, "endFrame": 2051},
29
+ {"mediaPoolItem": clips[1], "startFrame": 75, "endFrame": 162},
30
+ ])
31
+
32
+ # Or import a whole timeline from an EDL / FCPXML / AAF
33
+ media_pool.ImportTimelineFromFile("/abs/edl/my_cut_v3.fcpxml")
34
+
35
+ # Export the timeline for review or hand-off
36
+ timeline.Export("/abs/out/my_cut_v3.edl", resolve.EXPORT_EDL, resolve.EXPORT_NONE)
37
+
38
+ # Render
39
+ resolve.OpenPage("deliver")
40
+ project.LoadRenderPreset("H.264 Master") # a preset that exists on this machine
41
+ project.SetRenderSettings({"TargetDir": "/abs/out", "CustomName": "my_cut_v3"})
42
+ job_id = project.AddRenderJob()
43
+ project.StartRendering(job_id)
44
+ while project.IsRenderingInProgress():
45
+ time.sleep(2)
46
+ ```
47
+
48
+ ## Rules
49
+
50
+ - Check every return value: most calls return `None` or `False` on failure without raising.
51
+ - Use absolute paths.
52
+ - Never delete media pool items, timelines or projects the script did not create.
53
+ - Save the project (`pm.SaveProject()`) before and after a scripted change.