@ketecode/loom 0.0.0-stage → 0.1.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 (656) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +516 -2
  3. package/agents/accessibility-reviewer/AGENT.md +70 -0
  4. package/agents/accessibility-reviewer/evals/triggers.json +15 -0
  5. package/agents/agent-evaluator/AGENT.md +74 -0
  6. package/agents/agent-evaluator/evals/triggers.json +15 -0
  7. package/agents/architect/AGENT.md +82 -0
  8. package/agents/architect/evals/triggers.json +17 -0
  9. package/agents/billing-reviewer/AGENT.md +68 -0
  10. package/agents/billing-reviewer/evals/triggers.json +16 -0
  11. package/agents/code-reviewer/AGENT.md +51 -0
  12. package/agents/code-reviewer/evals/triggers.json +14 -0
  13. package/agents/code-simplifier/AGENT.md +74 -0
  14. package/agents/code-simplifier/evals/triggers.json +15 -0
  15. package/agents/cpp-build-resolver/AGENT.md +73 -0
  16. package/agents/cpp-build-resolver/evals/triggers.json +16 -0
  17. package/agents/cpp-reviewer/AGENT.md +59 -0
  18. package/agents/cpp-reviewer/evals/triggers.json +16 -0
  19. package/agents/csharp-build-resolver/AGENT.md +84 -0
  20. package/agents/csharp-build-resolver/evals/triggers.json +17 -0
  21. package/agents/csharp-reviewer/AGENT.md +88 -0
  22. package/agents/csharp-reviewer/evals/triggers.json +17 -0
  23. package/agents/dart-build-resolver/AGENT.md +80 -0
  24. package/agents/dart-build-resolver/evals/triggers.json +17 -0
  25. package/agents/dart-reviewer/AGENT.md +66 -0
  26. package/agents/dart-reviewer/evals/triggers.json +17 -0
  27. package/agents/database-reviewer/AGENT.md +72 -0
  28. package/agents/database-reviewer/evals/triggers.json +16 -0
  29. package/agents/django-reviewer/AGENT.md +61 -0
  30. package/agents/django-reviewer/evals/triggers.json +15 -0
  31. package/agents/doc-updater/AGENT.md +92 -0
  32. package/agents/doc-updater/evals/triggers.json +14 -0
  33. package/agents/e2e-runner/AGENT.md +88 -0
  34. package/agents/e2e-runner/evals/triggers.json +16 -0
  35. package/agents/fastapi-reviewer/AGENT.md +63 -0
  36. package/agents/fastapi-reviewer/evals/triggers.json +15 -0
  37. package/agents/flutter-reviewer/AGENT.md +70 -0
  38. package/agents/flutter-reviewer/evals/triggers.json +15 -0
  39. package/agents/fsharp-build-resolver/AGENT.md +81 -0
  40. package/agents/fsharp-build-resolver/evals/triggers.json +15 -0
  41. package/agents/fsharp-reviewer/AGENT.md +77 -0
  42. package/agents/fsharp-reviewer/evals/triggers.json +15 -0
  43. package/agents/go-build-resolver/AGENT.md +85 -0
  44. package/agents/go-build-resolver/evals/triggers.json +16 -0
  45. package/agents/go-reviewer/AGENT.md +66 -0
  46. package/agents/go-reviewer/evals/triggers.json +16 -0
  47. package/agents/healthcare-reviewer/AGENT.md +65 -0
  48. package/agents/healthcare-reviewer/evals/triggers.json +16 -0
  49. package/agents/i18n-reviewer/AGENT.md +64 -0
  50. package/agents/i18n-reviewer/evals/triggers.json +16 -0
  51. package/agents/infra-reviewer/AGENT.md +93 -0
  52. package/agents/infra-reviewer/evals/triggers.json +15 -0
  53. package/agents/java-build-resolver/AGENT.md +82 -0
  54. package/agents/java-build-resolver/evals/triggers.json +16 -0
  55. package/agents/java-reviewer/AGENT.md +64 -0
  56. package/agents/java-reviewer/evals/triggers.json +16 -0
  57. package/agents/kotlin-build-resolver/AGENT.md +89 -0
  58. package/agents/kotlin-build-resolver/evals/triggers.json +16 -0
  59. package/agents/kotlin-reviewer/AGENT.md +75 -0
  60. package/agents/kotlin-reviewer/evals/triggers.json +16 -0
  61. package/agents/mle-reviewer/AGENT.md +68 -0
  62. package/agents/mle-reviewer/evals/triggers.json +16 -0
  63. package/agents/network-config-reviewer/AGENT.md +68 -0
  64. package/agents/network-config-reviewer/evals/triggers.json +17 -0
  65. package/agents/payments-reviewer/AGENT.md +64 -0
  66. package/agents/payments-reviewer/evals/triggers.json +16 -0
  67. package/agents/performance-optimizer/AGENT.md +86 -0
  68. package/agents/performance-optimizer/evals/triggers.json +16 -0
  69. package/agents/perl-build-resolver/AGENT.md +84 -0
  70. package/agents/perl-build-resolver/evals/triggers.json +15 -0
  71. package/agents/perl-reviewer/AGENT.md +77 -0
  72. package/agents/perl-reviewer/evals/triggers.json +15 -0
  73. package/agents/php-build-resolver/AGENT.md +88 -0
  74. package/agents/php-build-resolver/evals/triggers.json +16 -0
  75. package/agents/php-reviewer/AGENT.md +61 -0
  76. package/agents/php-reviewer/evals/triggers.json +15 -0
  77. package/agents/planner/AGENT.md +75 -0
  78. package/agents/planner/evals/triggers.json +17 -0
  79. package/agents/pr-test-analyzer/AGENT.md +82 -0
  80. package/agents/pr-test-analyzer/evals/triggers.json +16 -0
  81. package/agents/python-build-resolver/AGENT.md +87 -0
  82. package/agents/python-build-resolver/evals/triggers.json +16 -0
  83. package/agents/python-reviewer/AGENT.md +63 -0
  84. package/agents/python-reviewer/evals/triggers.json +15 -0
  85. package/agents/rag-reviewer/AGENT.md +71 -0
  86. package/agents/rag-reviewer/evals/triggers.json +16 -0
  87. package/agents/react-reviewer/AGENT.md +70 -0
  88. package/agents/react-reviewer/evals/triggers.json +16 -0
  89. package/agents/refactor-cleaner/AGENT.md +82 -0
  90. package/agents/refactor-cleaner/evals/triggers.json +16 -0
  91. package/agents/ruby-build-resolver/AGENT.md +93 -0
  92. package/agents/ruby-build-resolver/evals/triggers.json +16 -0
  93. package/agents/ruby-reviewer/AGENT.md +62 -0
  94. package/agents/ruby-reviewer/evals/triggers.json +16 -0
  95. package/agents/rust-build-resolver/AGENT.md +98 -0
  96. package/agents/rust-build-resolver/evals/triggers.json +16 -0
  97. package/agents/rust-reviewer/AGENT.md +78 -0
  98. package/agents/rust-reviewer/evals/triggers.json +15 -0
  99. package/agents/security-reviewer/AGENT.md +84 -0
  100. package/agents/security-reviewer/evals/triggers.json +16 -0
  101. package/agents/silent-failure-hunter/AGENT.md +66 -0
  102. package/agents/silent-failure-hunter/evals/triggers.json +16 -0
  103. package/agents/solidity-reviewer/AGENT.md +70 -0
  104. package/agents/solidity-reviewer/evals/triggers.json +16 -0
  105. package/agents/swift-build-resolver/AGENT.md +85 -0
  106. package/agents/swift-build-resolver/evals/triggers.json +15 -0
  107. package/agents/swift-reviewer/AGENT.md +75 -0
  108. package/agents/swift-reviewer/evals/triggers.json +15 -0
  109. package/agents/typescript-build-resolver/AGENT.md +76 -0
  110. package/agents/typescript-build-resolver/evals/triggers.json +15 -0
  111. package/agents/typescript-reviewer/AGENT.md +76 -0
  112. package/agents/typescript-reviewer/evals/triggers.json +15 -0
  113. package/agents/vue-reviewer/AGENT.md +75 -0
  114. package/agents/vue-reviewer/evals/triggers.json +15 -0
  115. package/bin/kete-loom.js +683 -0
  116. package/commands/aside.md +19 -0
  117. package/commands/build-fix.md +26 -0
  118. package/commands/campaign.md +19 -0
  119. package/commands/changelog.md +36 -0
  120. package/commands/checkpoint.md +26 -0
  121. package/commands/codemap.md +25 -0
  122. package/commands/commit.md +26 -0
  123. package/commands/deps-audit.md +32 -0
  124. package/commands/epic-decompose.md +21 -0
  125. package/commands/explain.md +37 -0
  126. package/commands/feature-dev.md +22 -0
  127. package/commands/hookify.md +23 -0
  128. package/commands/i18n-check.md +39 -0
  129. package/commands/issue-sync.md +22 -0
  130. package/commands/jira.md +19 -0
  131. package/commands/learn.md +23 -0
  132. package/commands/loom.md +21 -0
  133. package/commands/loop.md +20 -0
  134. package/commands/model-route.md +27 -0
  135. package/commands/onboard.md +35 -0
  136. package/commands/orchestrate.md +21 -0
  137. package/commands/plan-feature.md +36 -0
  138. package/commands/postmortem.md +42 -0
  139. package/commands/pr-describe.md +39 -0
  140. package/commands/pr.md +22 -0
  141. package/commands/prd.md +41 -0
  142. package/commands/project-init.md +21 -0
  143. package/commands/refactor-clean.md +24 -0
  144. package/commands/resume-session.md +22 -0
  145. package/commands/review.md +35 -0
  146. package/commands/save-session.md +37 -0
  147. package/commands/security-scan.md +32 -0
  148. package/commands/sessions.md +21 -0
  149. package/commands/skill-create.md +21 -0
  150. package/commands/tdd.md +36 -0
  151. package/commands/test-coverage.md +24 -0
  152. package/commands/threat-model.md +36 -0
  153. package/commands/update-docs.md +25 -0
  154. package/commands/verify.md +21 -0
  155. package/hooks/block-dangerous-commands/HOOK.md +30 -0
  156. package/hooks/block-dangerous-commands/cases.json +50 -0
  157. package/hooks/block-dangerous-commands/hook.js +75 -0
  158. package/hooks/block-no-verify/HOOK.md +25 -0
  159. package/hooks/block-no-verify/cases.json +30 -0
  160. package/hooks/block-no-verify/hook.js +43 -0
  161. package/hooks/format-on-edit/HOOK.md +24 -0
  162. package/hooks/format-on-edit/hook.js +89 -0
  163. package/hooks/guard-secrets/HOOK.md +19 -0
  164. package/hooks/guard-secrets/cases.json +110 -0
  165. package/hooks/guard-secrets/hook.js +44 -0
  166. package/hooks/load-session-context/HOOK.md +20 -0
  167. package/hooks/load-session-context/hook.js +56 -0
  168. package/hooks/protect-files/HOOK.md +24 -0
  169. package/hooks/protect-files/cases.json +27 -0
  170. package/hooks/protect-files/hook.js +39 -0
  171. package/hooks/run.js +132 -0
  172. package/mcp/atlassian.json +11 -0
  173. package/mcp/chrome-devtools.json +18 -0
  174. package/mcp/cloudflare.json +11 -0
  175. package/mcp/context7.json +11 -0
  176. package/mcp/fetch.json +17 -0
  177. package/mcp/figma.json +11 -0
  178. package/mcp/git.json +17 -0
  179. package/mcp/github.json +11 -0
  180. package/mcp/linear.json +11 -0
  181. package/mcp/memory.json +18 -0
  182. package/mcp/notion.json +11 -0
  183. package/mcp/playwright.json +18 -0
  184. package/mcp/sentry.json +11 -0
  185. package/mcp/stripe.json +11 -0
  186. package/mcp/supabase.json +11 -0
  187. package/mcp/time.json +17 -0
  188. package/package.json +59 -4
  189. package/profiles.json +165 -0
  190. package/rules/common.md +21 -0
  191. package/rules/cpp.md +29 -0
  192. package/rules/csharp.md +25 -0
  193. package/rules/dart.md +29 -0
  194. package/rules/fsharp.md +28 -0
  195. package/rules/git.md +26 -0
  196. package/rules/go.md +29 -0
  197. package/rules/java.md +29 -0
  198. package/rules/kotlin.md +27 -0
  199. package/rules/perl.md +26 -0
  200. package/rules/php.md +28 -0
  201. package/rules/python.md +30 -0
  202. package/rules/ruby.md +27 -0
  203. package/rules/rust.md +26 -0
  204. package/rules/security.md +29 -0
  205. package/rules/swift.md +28 -0
  206. package/rules/testing.md +25 -0
  207. package/rules/typescript.md +29 -0
  208. package/schemas/skill-frontmatter.schema.json +52 -0
  209. package/scripts/lib/audit.js +96 -0
  210. package/scripts/lib/frontmatter.js +65 -0
  211. package/scripts/lib/hooks-install.js +292 -0
  212. package/scripts/lib/i18n.js +51 -0
  213. package/scripts/lib/inventory.js +85 -0
  214. package/scripts/lib/lint.js +158 -0
  215. package/scripts/lib/mcp-install.js +284 -0
  216. package/scripts/lib/profiles.js +128 -0
  217. package/scripts/lib/render.js +86 -0
  218. package/scripts/lib/rules-install.js +118 -0
  219. package/scripts/lib/skills.js +86 -0
  220. package/scripts/lib/targets.js +113 -0
  221. package/skills/accounting-api-integration/SKILL.md +81 -0
  222. package/skills/accounting-api-integration/evals/triggers.json +17 -0
  223. package/skills/accounting-api-integration/references/quickbooks.md +48 -0
  224. package/skills/accounting-api-integration/references/xero.md +45 -0
  225. package/skills/agent-harness-design/SKILL.md +125 -0
  226. package/skills/agent-harness-design/evals/triggers.json +21 -0
  227. package/skills/ai-media-generation/SKILL.md +89 -0
  228. package/skills/ai-media-generation/evals/triggers.json +16 -0
  229. package/skills/ai-media-generation/references/job-pipeline.md +76 -0
  230. package/skills/angular-patterns/SKILL.md +122 -0
  231. package/skills/angular-patterns/evals/triggers.json +16 -0
  232. package/skills/api-design/SKILL.md +96 -0
  233. package/skills/api-design/evals/triggers.json +18 -0
  234. package/skills/api-design/references/conventions.md +133 -0
  235. package/skills/architecture-decision-records/SKILL.md +98 -0
  236. package/skills/architecture-decision-records/evals/triggers.json +17 -0
  237. package/skills/article-writing/SKILL.md +108 -0
  238. package/skills/article-writing/evals/triggers.json +16 -0
  239. package/skills/aspnet-core-patterns/SKILL.md +149 -0
  240. package/skills/aspnet-core-patterns/evals/triggers.json +16 -0
  241. package/skills/auth-patterns/SKILL.md +104 -0
  242. package/skills/auth-patterns/evals/triggers.json +17 -0
  243. package/skills/auth-patterns/references/oauth-oidc.md +64 -0
  244. package/skills/autonomous-loops/SKILL.md +99 -0
  245. package/skills/autonomous-loops/evals/triggers.json +14 -0
  246. package/skills/aws-patterns/SKILL.md +91 -0
  247. package/skills/aws-patterns/evals/triggers.json +16 -0
  248. package/skills/azure-patterns/SKILL.md +86 -0
  249. package/skills/azure-patterns/evals/triggers.json +16 -0
  250. package/skills/benchmark-methodology/SKILL.md +88 -0
  251. package/skills/benchmark-methodology/evals/triggers.json +16 -0
  252. package/skills/benchmark-methodology/references/language-harnesses.md +130 -0
  253. package/skills/bgp-diagnostics/SKILL.md +84 -0
  254. package/skills/bgp-diagnostics/evals/triggers.json +18 -0
  255. package/skills/bgp-diagnostics/references/bgp-reference.md +81 -0
  256. package/skills/bioinformatics-workflows/SKILL.md +108 -0
  257. package/skills/bioinformatics-workflows/evals/triggers.json +16 -0
  258. package/skills/bioinformatics-workflows/references/commands.md +71 -0
  259. package/skills/bioinformatics-workflows/references/formats.md +24 -0
  260. package/skills/bioinformatics-workflows/references/workflow-managers.md +107 -0
  261. package/skills/brand-voice/SKILL.md +112 -0
  262. package/skills/brand-voice/evals/triggers.json +16 -0
  263. package/skills/browser-qa/SKILL.md +99 -0
  264. package/skills/browser-qa/evals/triggers.json +16 -0
  265. package/skills/bun-runtime/SKILL.md +93 -0
  266. package/skills/bun-runtime/evals/triggers.json +16 -0
  267. package/skills/cisco-ios-config/SKILL.md +101 -0
  268. package/skills/cisco-ios-config/evals/triggers.json +18 -0
  269. package/skills/cisco-ios-config/references/verification.md +63 -0
  270. package/skills/clickhouse-patterns/SKILL.md +101 -0
  271. package/skills/clickhouse-patterns/evals/triggers.json +18 -0
  272. package/skills/clickhouse-patterns/references/engines-and-views.md +138 -0
  273. package/skills/clinical-decision-support/SKILL.md +90 -0
  274. package/skills/clinical-decision-support/evals/triggers.json +16 -0
  275. package/skills/clinical-decision-support/references/cds-hooks.md +76 -0
  276. package/skills/clinical-decision-support/references/regulatory-boundaries.md +37 -0
  277. package/skills/code-tour/SKILL.md +97 -0
  278. package/skills/code-tour/evals/triggers.json +14 -0
  279. package/skills/codebase-onboarding/SKILL.md +112 -0
  280. package/skills/codebase-onboarding/evals/triggers.json +14 -0
  281. package/skills/cold-outreach-sequences/SKILL.md +90 -0
  282. package/skills/cold-outreach-sequences/evals/triggers.json +16 -0
  283. package/skills/content-repurposing/SKILL.md +82 -0
  284. package/skills/content-repurposing/evals/triggers.json +16 -0
  285. package/skills/context-budget/SKILL.md +84 -0
  286. package/skills/context-budget/evals/triggers.json +14 -0
  287. package/skills/conventional-commits/SKILL.md +144 -0
  288. package/skills/conventional-commits/evals/triggers.json +16 -0
  289. package/skills/cpp-patterns/SKILL.md +129 -0
  290. package/skills/cpp-patterns/evals/triggers.json +16 -0
  291. package/skills/cpp-patterns/references/cmake-and-tooling.md +88 -0
  292. package/skills/cpp-patterns/references/undefined-behaviour.md +75 -0
  293. package/skills/cpp-testing/SKILL.md +131 -0
  294. package/skills/cpp-testing/evals/triggers.json +16 -0
  295. package/skills/csharp-patterns/SKILL.md +110 -0
  296. package/skills/csharp-patterns/evals/triggers.json +17 -0
  297. package/skills/csharp-patterns/references/analyzers.md +59 -0
  298. package/skills/csharp-testing/SKILL.md +85 -0
  299. package/skills/csharp-testing/evals/triggers.json +17 -0
  300. package/skills/csharp-testing/references/integration-tests.md +77 -0
  301. package/skills/css-architecture/SKILL.md +143 -0
  302. package/skills/css-architecture/evals/triggers.json +16 -0
  303. package/skills/customs-trade-compliance/SKILL.md +95 -0
  304. package/skills/customs-trade-compliance/evals/triggers.json +16 -0
  305. package/skills/customs-trade-compliance/references/incoterms-2020.md +42 -0
  306. package/skills/dart-patterns/SKILL.md +157 -0
  307. package/skills/dart-patterns/evals/triggers.json +18 -0
  308. package/skills/dart-testing/SKILL.md +164 -0
  309. package/skills/dart-testing/evals/triggers.json +18 -0
  310. package/skills/data-analysis-notebooks/SKILL.md +113 -0
  311. package/skills/data-analysis-notebooks/evals/triggers.json +16 -0
  312. package/skills/data-analysis-notebooks/references/dataframe-pitfalls.md +49 -0
  313. package/skills/data-analysis-notebooks/references/statistics-pitfalls.md +24 -0
  314. package/skills/data-pipelines/SKILL.md +90 -0
  315. package/skills/data-pipelines/evals/triggers.json +16 -0
  316. package/skills/data-pipelines/references/orchestrators.md +64 -0
  317. package/skills/database-migrations/SKILL.md +102 -0
  318. package/skills/database-migrations/evals/triggers.json +16 -0
  319. package/skills/database-migrations/references/recipes.md +98 -0
  320. package/skills/database-migrations/references/tools.md +21 -0
  321. package/skills/dbt-patterns/SKILL.md +96 -0
  322. package/skills/dbt-patterns/evals/triggers.json +16 -0
  323. package/skills/dbt-patterns/references/yaml-examples.md +114 -0
  324. package/skills/deep-research/SKILL.md +107 -0
  325. package/skills/deep-research/evals/triggers.json +14 -0
  326. package/skills/dependency-audit/SKILL.md +103 -0
  327. package/skills/dependency-audit/evals/triggers.json +16 -0
  328. package/skills/dependency-audit/references/tools.md +124 -0
  329. package/skills/deployment-strategies/SKILL.md +108 -0
  330. package/skills/deployment-strategies/evals/triggers.json +16 -0
  331. package/skills/django-patterns/SKILL.md +123 -0
  332. package/skills/django-patterns/evals/triggers.json +16 -0
  333. package/skills/docker-patterns/SKILL.md +132 -0
  334. package/skills/docker-patterns/evals/triggers.json +16 -0
  335. package/skills/docker-patterns/references/dockerfiles.md +105 -0
  336. package/skills/e2e-testing-playwright/SKILL.md +94 -0
  337. package/skills/e2e-testing-playwright/evals/triggers.json +16 -0
  338. package/skills/e2e-testing-playwright/references/config-and-ci.md +129 -0
  339. package/skills/ef-core-patterns/SKILL.md +117 -0
  340. package/skills/ef-core-patterns/evals/triggers.json +16 -0
  341. package/skills/email-deliverability/SKILL.md +99 -0
  342. package/skills/email-deliverability/evals/triggers.json +17 -0
  343. package/skills/email-deliverability/references/dns-records.md +85 -0
  344. package/skills/error-handling-patterns/SKILL.md +112 -0
  345. package/skills/error-handling-patterns/evals/triggers.json +18 -0
  346. package/skills/error-handling-patterns/references/language-idioms.md +49 -0
  347. package/skills/estimation-and-scoping/SKILL.md +97 -0
  348. package/skills/estimation-and-scoping/evals/triggers.json +14 -0
  349. package/skills/evm-dapp-integration/SKILL.md +73 -0
  350. package/skills/evm-dapp-integration/evals/triggers.json +16 -0
  351. package/skills/fastapi-patterns/SKILL.md +127 -0
  352. package/skills/fastapi-patterns/evals/triggers.json +16 -0
  353. package/skills/ffmpeg-media-processing/SKILL.md +94 -0
  354. package/skills/ffmpeg-media-processing/evals/triggers.json +16 -0
  355. package/skills/ffmpeg-media-processing/references/recipes.md +112 -0
  356. package/skills/fhir-integration/SKILL.md +81 -0
  357. package/skills/fhir-integration/evals/triggers.json +16 -0
  358. package/skills/fhir-integration/references/search-and-bundles.md +73 -0
  359. package/skills/fhir-integration/references/smart-on-fhir.md +50 -0
  360. package/skills/flask-patterns/SKILL.md +132 -0
  361. package/skills/flask-patterns/evals/triggers.json +16 -0
  362. package/skills/flutter-patterns/SKILL.md +99 -0
  363. package/skills/flutter-patterns/evals/triggers.json +16 -0
  364. package/skills/flutterwave-integration/SKILL.md +75 -0
  365. package/skills/flutterwave-integration/evals/triggers.json +16 -0
  366. package/skills/flutterwave-integration/references/api.md +73 -0
  367. package/skills/flutterwave-integration/references/webhooks.md +49 -0
  368. package/skills/fsharp-patterns/SKILL.md +133 -0
  369. package/skills/fsharp-patterns/evals/triggers.json +16 -0
  370. package/skills/fsharp-testing/SKILL.md +136 -0
  371. package/skills/fsharp-testing/evals/triggers.json +16 -0
  372. package/skills/gcp-patterns/SKILL.md +86 -0
  373. package/skills/gcp-patterns/evals/triggers.json +16 -0
  374. package/skills/git-workflow/SKILL.md +114 -0
  375. package/skills/git-workflow/evals/triggers.json +16 -0
  376. package/skills/github-actions-ci/SKILL.md +117 -0
  377. package/skills/github-actions-ci/evals/triggers.json +16 -0
  378. package/skills/github-api-automation/SKILL.md +101 -0
  379. package/skills/github-api-automation/evals/triggers.json +17 -0
  380. package/skills/go-patterns/SKILL.md +118 -0
  381. package/skills/go-patterns/evals/triggers.json +17 -0
  382. package/skills/go-patterns/references/concurrency.md +162 -0
  383. package/skills/go-testing/SKILL.md +154 -0
  384. package/skills/go-testing/evals/triggers.json +17 -0
  385. package/skills/hexagonal-architecture/SKILL.md +89 -0
  386. package/skills/hexagonal-architecture/evals/triggers.json +17 -0
  387. package/skills/hipaa-compliance/SKILL.md +91 -0
  388. package/skills/hipaa-compliance/evals/triggers.json +18 -0
  389. package/skills/hipaa-compliance/references/safeguards.md +68 -0
  390. package/skills/hl7v2-integration/SKILL.md +69 -0
  391. package/skills/hl7v2-integration/evals/triggers.json +16 -0
  392. package/skills/hl7v2-integration/references/messages-and-ack.md +78 -0
  393. package/skills/homelab-network-setup/SKILL.md +125 -0
  394. package/skills/homelab-network-setup/evals/triggers.json +18 -0
  395. package/skills/homelab-network-setup/references/firewall-and-dns.md +45 -0
  396. package/skills/homelab-network-setup/references/wireguard.md +72 -0
  397. package/skills/hubtel-integration/SKILL.md +77 -0
  398. package/skills/hubtel-integration/evals/triggers.json +16 -0
  399. package/skills/hubtel-integration/references/api.md +92 -0
  400. package/skills/i18n-localization/SKILL.md +114 -0
  401. package/skills/i18n-localization/evals/triggers.json +16 -0
  402. package/skills/i18n-localization/references/libraries.md +52 -0
  403. package/skills/incident-postmortem/SKILL.md +118 -0
  404. package/skills/incident-postmortem/evals/triggers.json +14 -0
  405. package/skills/inventory-demand-planning/SKILL.md +89 -0
  406. package/skills/inventory-demand-planning/evals/triggers.json +16 -0
  407. package/skills/inventory-demand-planning/references/formulas.md +62 -0
  408. package/skills/investor-materials/SKILL.md +127 -0
  409. package/skills/investor-materials/evals/triggers.json +16 -0
  410. package/skills/investor-materials/references/templates.md +74 -0
  411. package/skills/invoicing-and-tax/SKILL.md +84 -0
  412. package/skills/invoicing-and-tax/evals/triggers.json +17 -0
  413. package/skills/invoicing-and-tax/references/e-invoicing.md +24 -0
  414. package/skills/invoicing-and-tax/references/invoice-fields.md +38 -0
  415. package/skills/invoicing-and-tax/references/rounding.md +26 -0
  416. package/skills/java-patterns/SKILL.md +141 -0
  417. package/skills/java-patterns/evals/triggers.json +17 -0
  418. package/skills/java-testing/SKILL.md +142 -0
  419. package/skills/java-testing/evals/triggers.json +16 -0
  420. package/skills/jetpack-compose-patterns/SKILL.md +88 -0
  421. package/skills/jetpack-compose-patterns/evals/triggers.json +16 -0
  422. package/skills/jira-integration/SKILL.md +92 -0
  423. package/skills/jira-integration/evals/triggers.json +17 -0
  424. package/skills/jpa-hibernate/SKILL.md +92 -0
  425. package/skills/jpa-hibernate/evals/triggers.json +18 -0
  426. package/skills/jpa-hibernate/references/mapping.md +99 -0
  427. package/skills/kotlin-multiplatform/SKILL.md +97 -0
  428. package/skills/kotlin-multiplatform/evals/triggers.json +16 -0
  429. package/skills/kotlin-patterns/SKILL.md +128 -0
  430. package/skills/kotlin-patterns/evals/triggers.json +16 -0
  431. package/skills/kotlin-testing/SKILL.md +117 -0
  432. package/skills/kotlin-testing/evals/triggers.json +16 -0
  433. package/skills/ktor-patterns/SKILL.md +135 -0
  434. package/skills/ktor-patterns/evals/triggers.json +18 -0
  435. package/skills/kubernetes-patterns/SKILL.md +106 -0
  436. package/skills/kubernetes-patterns/evals/triggers.json +16 -0
  437. package/skills/kubernetes-patterns/references/manifests.md +115 -0
  438. package/skills/laravel-patterns/SKILL.md +136 -0
  439. package/skills/laravel-patterns/evals/triggers.json +16 -0
  440. package/skills/linear-integration/SKILL.md +98 -0
  441. package/skills/linear-integration/evals/triggers.json +17 -0
  442. package/skills/literature-review/SKILL.md +109 -0
  443. package/skills/literature-review/evals/triggers.json +16 -0
  444. package/skills/literature-review/references/appraisal.md +41 -0
  445. package/skills/literature-review/references/search-sources.md +39 -0
  446. package/skills/llm-app-patterns/SKILL.md +97 -0
  447. package/skills/llm-app-patterns/evals/triggers.json +17 -0
  448. package/skills/llm-evals/SKILL.md +98 -0
  449. package/skills/llm-evals/evals/triggers.json +16 -0
  450. package/skills/llm-evals/references/graders.md +66 -0
  451. package/skills/logistics-exception-management/SKILL.md +90 -0
  452. package/skills/logistics-exception-management/evals/triggers.json +16 -0
  453. package/skills/manim-animations/SKILL.md +106 -0
  454. package/skills/manim-animations/evals/triggers.json +16 -0
  455. package/skills/market-research/SKILL.md +117 -0
  456. package/skills/market-research/evals/triggers.json +16 -0
  457. package/skills/marketing-campaign/SKILL.md +111 -0
  458. package/skills/marketing-campaign/evals/triggers.json +16 -0
  459. package/skills/mcp-server-patterns/SKILL.md +127 -0
  460. package/skills/mcp-server-patterns/evals/triggers.json +18 -0
  461. package/skills/mcp-server-patterns/references/protocol-notes.md +68 -0
  462. package/skills/metrics-dashboards/SKILL.md +113 -0
  463. package/skills/metrics-dashboards/evals/triggers.json +16 -0
  464. package/skills/ml-experiment-workflow/SKILL.md +125 -0
  465. package/skills/ml-experiment-workflow/evals/triggers.json +16 -0
  466. package/skills/mongodb-patterns/SKILL.md +115 -0
  467. package/skills/mongodb-patterns/evals/triggers.json +18 -0
  468. package/skills/mongodb-patterns/references/indexes-and-aggregation.md +94 -0
  469. package/skills/mpesa-daraja-integration/SKILL.md +70 -0
  470. package/skills/mpesa-daraja-integration/evals/triggers.json +16 -0
  471. package/skills/mpesa-daraja-integration/references/api.md +103 -0
  472. package/skills/mpesa-daraja-integration/references/callbacks.md +74 -0
  473. package/skills/mtn-momo-integration/SKILL.md +66 -0
  474. package/skills/mtn-momo-integration/evals/triggers.json +16 -0
  475. package/skills/mtn-momo-integration/references/api.md +153 -0
  476. package/skills/mtn-momo-integration/references/callbacks.md +92 -0
  477. package/skills/mtn-momo-integration/references/sandbox-and-go-live.md +51 -0
  478. package/skills/mtn-momo-integration/scripts/sandbox-setup.js +79 -0
  479. package/skills/mysql-patterns/SKILL.md +96 -0
  480. package/skills/mysql-patterns/evals/triggers.json +16 -0
  481. package/skills/mysql-patterns/references/explain.md +34 -0
  482. package/skills/mysql-patterns/references/online-ddl.md +41 -0
  483. package/skills/nestjs-patterns/SKILL.md +114 -0
  484. package/skills/nestjs-patterns/evals/triggers.json +16 -0
  485. package/skills/nestjs-patterns/references/testing.md +68 -0
  486. package/skills/network-automation/SKILL.md +107 -0
  487. package/skills/network-automation/evals/triggers.json +18 -0
  488. package/skills/network-automation/references/tool-snippets.md +153 -0
  489. package/skills/network-troubleshooting/SKILL.md +152 -0
  490. package/skills/network-troubleshooting/evals/triggers.json +18 -0
  491. package/skills/network-troubleshooting/references/commands.md +33 -0
  492. package/skills/nextjs-patterns/SKILL.md +150 -0
  493. package/skills/nextjs-patterns/evals/triggers.json +18 -0
  494. package/skills/nextjs-patterns/references/caching.md +87 -0
  495. package/skills/node-backend-patterns/SKILL.md +103 -0
  496. package/skills/node-backend-patterns/evals/triggers.json +16 -0
  497. package/skills/node-backend-patterns/references/templates.md +122 -0
  498. package/skills/nuxt-patterns/SKILL.md +103 -0
  499. package/skills/nuxt-patterns/evals/triggers.json +16 -0
  500. package/skills/parallel-agent-orchestration/SKILL.md +106 -0
  501. package/skills/parallel-agent-orchestration/evals/triggers.json +14 -0
  502. package/skills/paystack-integration/SKILL.md +59 -0
  503. package/skills/paystack-integration/evals/triggers.json +14 -0
  504. package/skills/paystack-integration/references/api.md +73 -0
  505. package/skills/paystack-integration/references/mobile-money.md +50 -0
  506. package/skills/paystack-integration/references/webhooks.md +80 -0
  507. package/skills/pci-dss-scope/SKILL.md +103 -0
  508. package/skills/pci-dss-scope/evals/triggers.json +18 -0
  509. package/skills/pci-dss-scope/references/saq-and-data.md +36 -0
  510. package/skills/perl-patterns/SKILL.md +135 -0
  511. package/skills/perl-patterns/evals/triggers.json +18 -0
  512. package/skills/perl-testing/SKILL.md +126 -0
  513. package/skills/perl-testing/evals/triggers.json +17 -0
  514. package/skills/php-patterns/SKILL.md +116 -0
  515. package/skills/php-patterns/evals/triggers.json +16 -0
  516. package/skills/php-testing/SKILL.md +123 -0
  517. package/skills/php-testing/evals/triggers.json +16 -0
  518. package/skills/postgres-patterns/SKILL.md +103 -0
  519. package/skills/postgres-patterns/evals/triggers.json +17 -0
  520. package/skills/postgres-patterns/references/explain.md +59 -0
  521. package/skills/postgres-patterns/references/locks.md +53 -0
  522. package/skills/prd-writing/SKILL.md +124 -0
  523. package/skills/prd-writing/evals/triggers.json +15 -0
  524. package/skills/prisma-patterns/SKILL.md +83 -0
  525. package/skills/prisma-patterns/evals/triggers.json +18 -0
  526. package/skills/prisma-patterns/references/prisma-8.md +46 -0
  527. package/skills/prisma-patterns/references/workflow.md +50 -0
  528. package/skills/privacy-compliance/SKILL.md +121 -0
  529. package/skills/privacy-compliance/evals/triggers.json +18 -0
  530. package/skills/privacy-compliance/references/jurisdictions.md +51 -0
  531. package/skills/production-scheduling/SKILL.md +98 -0
  532. package/skills/production-scheduling/evals/triggers.json +16 -0
  533. package/skills/prompt-engineering/SKILL.md +92 -0
  534. package/skills/prompt-engineering/evals/triggers.json +16 -0
  535. package/skills/python-patterns/SKILL.md +107 -0
  536. package/skills/python-patterns/evals/triggers.json +16 -0
  537. package/skills/python-patterns/references/tooling.md +101 -0
  538. package/skills/python-testing/SKILL.md +126 -0
  539. package/skills/python-testing/evals/triggers.json +16 -0
  540. package/skills/python-testing/references/mocking.md +71 -0
  541. package/skills/pytorch-patterns/SKILL.md +139 -0
  542. package/skills/pytorch-patterns/evals/triggers.json +16 -0
  543. package/skills/pytorch-patterns/references/debugging.md +39 -0
  544. package/skills/quarkus-patterns/SKILL.md +93 -0
  545. package/skills/quarkus-patterns/evals/triggers.json +18 -0
  546. package/skills/rag-pipeline-patterns/SKILL.md +117 -0
  547. package/skills/rag-pipeline-patterns/evals/triggers.json +18 -0
  548. package/skills/rag-pipeline-patterns/references/evaluation.md +37 -0
  549. package/skills/rag-pipeline-patterns/references/retrieval-recipes.md +78 -0
  550. package/skills/rails-patterns/SKILL.md +132 -0
  551. package/skills/rails-patterns/evals/triggers.json +16 -0
  552. package/skills/react-native-patterns/SKILL.md +101 -0
  553. package/skills/react-native-patterns/evals/triggers.json +16 -0
  554. package/skills/react-patterns/SKILL.md +140 -0
  555. package/skills/react-patterns/evals/triggers.json +18 -0
  556. package/skills/react-performance/SKILL.md +107 -0
  557. package/skills/react-performance/evals/triggers.json +18 -0
  558. package/skills/redis-patterns/SKILL.md +109 -0
  559. package/skills/redis-patterns/evals/triggers.json +18 -0
  560. package/skills/redis-patterns/references/operations.md +61 -0
  561. package/skills/refactoring-safely/SKILL.md +107 -0
  562. package/skills/refactoring-safely/evals/triggers.json +17 -0
  563. package/skills/release-management/SKILL.md +141 -0
  564. package/skills/release-management/evals/triggers.json +16 -0
  565. package/skills/remotion-video/SKILL.md +91 -0
  566. package/skills/remotion-video/evals/triggers.json +16 -0
  567. package/skills/remotion-video/references/lambda.md +66 -0
  568. package/skills/returns-reverse-logistics/SKILL.md +97 -0
  569. package/skills/returns-reverse-logistics/evals/triggers.json +16 -0
  570. package/skills/ruby-patterns/SKILL.md +127 -0
  571. package/skills/ruby-patterns/evals/triggers.json +18 -0
  572. package/skills/ruby-testing/SKILL.md +113 -0
  573. package/skills/ruby-testing/evals/triggers.json +18 -0
  574. package/skills/runbook-writing/SKILL.md +101 -0
  575. package/skills/runbook-writing/evals/triggers.json +14 -0
  576. package/skills/rust-patterns/SKILL.md +118 -0
  577. package/skills/rust-patterns/evals/triggers.json +16 -0
  578. package/skills/rust-patterns/references/cargo-and-clippy.md +105 -0
  579. package/skills/rust-patterns/references/errors-and-traits.md +97 -0
  580. package/skills/rust-testing/SKILL.md +148 -0
  581. package/skills/rust-testing/evals/triggers.json +16 -0
  582. package/skills/rust-testing/references/fakes-proptest-async.md +113 -0
  583. package/skills/search-first/SKILL.md +73 -0
  584. package/skills/search-first/evals/triggers.json +14 -0
  585. package/skills/security-review/SKILL.md +58 -0
  586. package/skills/security-review/evals/triggers.json +14 -0
  587. package/skills/security-review/references/checklist.md +54 -0
  588. package/skills/security-review/scripts/scan-secrets.js +79 -0
  589. package/skills/seo-audit/SKILL.md +111 -0
  590. package/skills/seo-audit/evals/triggers.json +16 -0
  591. package/skills/seo-audit/references/checks.md +65 -0
  592. package/skills/session-handoff/SKILL.md +101 -0
  593. package/skills/session-handoff/evals/triggers.json +14 -0
  594. package/skills/skill-authoring/SKILL.md +87 -0
  595. package/skills/skill-authoring/evals/triggers.json +14 -0
  596. package/skills/skill-authoring/references/frontmatter.md +40 -0
  597. package/skills/slack-app-integration/SKILL.md +108 -0
  598. package/skills/slack-app-integration/evals/triggers.json +17 -0
  599. package/skills/smart-contract-security/SKILL.md +110 -0
  600. package/skills/smart-contract-security/evals/triggers.json +16 -0
  601. package/skills/smart-contract-security/references/vulnerability-checklist.md +79 -0
  602. package/skills/social-media-publishing/SKILL.md +84 -0
  603. package/skills/social-media-publishing/evals/triggers.json +17 -0
  604. package/skills/social-media-publishing/references/platform-apis.md +116 -0
  605. package/skills/solidity-patterns/SKILL.md +95 -0
  606. package/skills/solidity-patterns/evals/triggers.json +16 -0
  607. package/skills/spring-boot-patterns/SKILL.md +128 -0
  608. package/skills/spring-boot-patterns/evals/triggers.json +18 -0
  609. package/skills/spring-boot-patterns/references/testing.md +72 -0
  610. package/skills/stripe-integration/SKILL.md +69 -0
  611. package/skills/stripe-integration/evals/triggers.json +16 -0
  612. package/skills/stripe-integration/references/api.md +71 -0
  613. package/skills/stripe-integration/references/billing.md +58 -0
  614. package/skills/stripe-integration/references/webhooks.md +76 -0
  615. package/skills/subscription-billing-ops/SKILL.md +118 -0
  616. package/skills/subscription-billing-ops/evals/triggers.json +17 -0
  617. package/skills/subscription-billing-ops/references/proration.md +47 -0
  618. package/skills/subscription-billing-ops/references/revenue-metrics.md +38 -0
  619. package/skills/svelte-patterns/SKILL.md +122 -0
  620. package/skills/svelte-patterns/evals/triggers.json +16 -0
  621. package/skills/swift-patterns/SKILL.md +113 -0
  622. package/skills/swift-patterns/evals/triggers.json +16 -0
  623. package/skills/swift-patterns/references/concurrency-migration.md +40 -0
  624. package/skills/swift-testing/SKILL.md +121 -0
  625. package/skills/swift-testing/evals/triggers.json +16 -0
  626. package/skills/swift-testing/references/swift-testing-cheatsheet.md +81 -0
  627. package/skills/swiftui-patterns/SKILL.md +102 -0
  628. package/skills/swiftui-patterns/evals/triggers.json +16 -0
  629. package/skills/tdd-workflow/SKILL.md +67 -0
  630. package/skills/tdd-workflow/evals/triggers.json +14 -0
  631. package/skills/technical-writing/SKILL.md +95 -0
  632. package/skills/technical-writing/evals/triggers.json +14 -0
  633. package/skills/terraform-patterns/SKILL.md +122 -0
  634. package/skills/terraform-patterns/evals/triggers.json +16 -0
  635. package/skills/terraform-patterns/references/backends.md +67 -0
  636. package/skills/test-coverage-improvement/SKILL.md +107 -0
  637. package/skills/test-coverage-improvement/evals/triggers.json +16 -0
  638. package/skills/threat-modeling/SKILL.md +113 -0
  639. package/skills/threat-modeling/evals/triggers.json +16 -0
  640. package/skills/typescript-patterns/SKILL.md +122 -0
  641. package/skills/typescript-patterns/evals/triggers.json +16 -0
  642. package/skills/typescript-testing/SKILL.md +101 -0
  643. package/skills/typescript-testing/evals/triggers.json +16 -0
  644. package/skills/verification-loop/SKILL.md +70 -0
  645. package/skills/verification-loop/evals/triggers.json +14 -0
  646. package/skills/verification-loop/scripts/detect-checks.js +102 -0
  647. package/skills/vite-patterns/SKILL.md +117 -0
  648. package/skills/vite-patterns/evals/triggers.json +16 -0
  649. package/skills/vue-patterns/SKILL.md +104 -0
  650. package/skills/vue-patterns/evals/triggers.json +16 -0
  651. package/skills/web-accessibility/SKILL.md +119 -0
  652. package/skills/web-accessibility/evals/triggers.json +16 -0
  653. package/skills/web-performance/SKILL.md +107 -0
  654. package/skills/web-performance/evals/triggers.json +16 -0
  655. package/skills/web-scraping/SKILL.md +80 -0
  656. package/skills/web-scraping/evals/triggers.json +16 -0
@@ -0,0 +1,125 @@
1
+ ---
2
+ name: ml-experiment-workflow
3
+ description: Plans and runs machine learning experiments so results can be trusted, from a dumb baseline and leakage-free train, validation and test splits, through tracked runs, metrics chosen to match the business goal, and ablations, to turning a notebook into a repeatable pipeline. Use when starting a new model, comparing approaches, deciding whether an improvement is real, or productionising notebook experiments.
4
+ license: MIT
5
+ compatibility: Any Agent Skills host. Framework-agnostic (scikit-learn, PyTorch, XGBoost and others); needs Python to run experiments.
6
+ metadata:
7
+ kete-loom/version: "0.1.0"
8
+ kete-loom/category: ai
9
+ kete-loom/risk: runs-commands
10
+ kete-loom/requires: "python, git"
11
+ kete-loom/owner: "Kete-org"
12
+ ---
13
+
14
+ # ML experiment workflow
15
+
16
+ An experiment is only useful if someone else could rerun it and get the same answer, and if the number it reports means what the user thinks it means. Follow these steps in order. For PyTorch training-loop mechanics use the `pytorch-patterns` skill; for evaluating LLM outputs use `llm-evals`.
17
+
18
+ ## 1. Pin down the goal
19
+
20
+ Write these down with the user before touching data:
21
+
22
+ 1. **Decision.** What will be done differently if the model is good? (Auto-approve claims, rank search results, flag churn risk.)
23
+ 2. **Metric that matches it.** Pick from the cost of errors, not habit:
24
+ - Imbalanced classes: precision/recall at an operating threshold, PR-AUC, or cost-weighted error. Accuracy is misleading when one class is 95% of the data.
25
+ - Ranking: NDCG@k, recall@k, MRR at the k the product shows.
26
+ - Probabilities used downstream: log loss and calibration (Brier score, reliability plot).
27
+ - Regression: MAE when all errors cost the same, RMSE when large errors are much worse, MAPE only when targets are never near zero.
28
+ 3. **Bar to beat.** The current system's number, or a minimum the decision needs.
29
+ 4. **Unit of prediction.** Per user, per transaction, per day? This drives the split.
30
+
31
+ **Stop and ask** if the user cannot name the decision or the metric. Don't pick one silently.
32
+
33
+ ## 2. Split without leakage
34
+
35
+ Decide the split before any exploration, then never look at the test set until the end.
36
+
37
+ - **Time-ordered data** (forecasting, anything predicted about the future): split by time. Train on the past, validate and test on later periods. Use `TimeSeriesSplit` or a rolling-origin scheme, not random K-fold. When the label looks ahead (for example "churns in the next 30 days"), leave a gap of at least that horizon between train and validation (`TimeSeriesSplit(gap=...)`) so training labels do not overlap the validation period.
38
+ - **Grouped data** (several rows per patient, user, device, document): split by group so no group appears on both sides. Use `GroupKFold` / `GroupShuffleSplit`.
39
+ - **Imbalanced labels**: stratify (`StratifiedKFold`, `StratifiedGroupKFold`).
40
+ - **Duplicates**: dedupe, or group near-duplicates, before splitting.
41
+
42
+ Leakage checklist (any yes means fix before continuing):
43
+
44
+ - Is any preprocessing (scaling, imputation, target encoding, feature selection, vocabulary, PCA) fitted on data that includes validation or test rows? Fit it inside the training fold only; in scikit-learn, put it in a `Pipeline` passed to cross-validation.
45
+ - Does any feature use information not available at prediction time (a later timestamp, a status set after the outcome, an aggregate over the whole dataset)?
46
+ - Was the test set used to choose features, hyperparameters, thresholds or the stopping epoch?
47
+ - Is a feature suspiciously predictive on its own? Check top-importance features one by one.
48
+
49
+ ## 3. Baselines first
50
+
51
+ Before any real model, record:
52
+
53
+ 1. A trivial baseline: majority class / mean prediction / "same as last period" / popularity ranking.
54
+ 2. A simple model: logistic or linear regression, or gradient-boosted trees for tabular data, with default settings.
55
+ 3. The current production system, if there is one.
56
+
57
+ If a complex model does not clearly beat the simple one, report that; it is a result, not a failure.
58
+
59
+ ## 4. Track every run
60
+
61
+ Each run records, automatically:
62
+
63
+ - git commit (and whether the tree was dirty), config/hyperparameters, seed
64
+ - dataset version: file hash, snapshot id or query plus date
65
+ - metrics on validation (and test only for the final run), with the split definition
66
+ - environment: Python and key library versions, hardware
67
+ - artifacts: model file, predictions on the validation set
68
+
69
+ Use whatever the project already has (MLflow, Weights & Biases, DVC, a CSV log). If there's nothing, write one JSON line per run to a log file and commit the code that writes it. Don't add a tracking service the user did not ask for.
70
+
71
+ ## 5. Decide whether a gain is real
72
+
73
+ - Run the leading candidates with at least 3 seeds (or use cross-validation folds) and report mean and spread, not the best run.
74
+ - A gain smaller than the seed-to-seed spread is noise. Say so.
75
+ - For a single held-out set, use a paired bootstrap over test examples to get an interval on the difference.
76
+ - Compare models on the same split, the same preprocessing and the same eval code.
77
+ - Look at the errors: slice the metric by important segments (region, device, class, new vs returning users). An average gain that hides a regression on a key segment must be reported.
78
+
79
+ ## 6. Ablations
80
+
81
+ When a model has several changes stacked together, remove one at a time from the final configuration and rerun. Report a table:
82
+
83
+ ```
84
+ | Variant | Val metric (mean ± std, n seeds) | Δ vs full |
85
+ |--------------------------|----------------------------------|-----------|
86
+ | Full | 0.812 ± 0.004 | — |
87
+ | − feature group X | 0.809 ± 0.005 | −0.003 |
88
+ | − augmentation | 0.781 ± 0.006 | −0.031 |
89
+ ```
90
+
91
+ Drop any component whose removal does not hurt beyond noise; it is complexity with no evidence behind it.
92
+
93
+ ## 7. From notebook to pipeline
94
+
95
+ Do this once an approach is worth keeping:
96
+
97
+ 1. Move code out of cells into modules with functions: `load_data`, `build_features`, `split`, `train`, `evaluate`. The notebook then only imports and calls them.
98
+ 2. Put every constant (paths, dates, hyperparameters, seed) in one config file.
99
+ 3. Provide one command that runs the whole thing end to end, for example `python -m project.train --config configs/baseline.yaml`.
100
+ 4. Add tests for the feature code and the split: a test that train and test share no group ids or overlapping time ranges is cheap and catches the worst bugs.
101
+ 5. Rerun from a clean checkout and confirm the metric matches the notebook within seed noise. If it does not, find out why before anything else.
102
+
103
+ ## 8. Final evaluation
104
+
105
+ Only after model, features and threshold are frozen: evaluate once on the test set. If the test result is then used to change anything, that set is no longer a test set; say so and hold out new data.
106
+
107
+ ## Never
108
+
109
+ - Never report a test-set number that was used for tuning.
110
+ - Never report the best of many seeds as the result.
111
+ - Never fit preprocessing on the full dataset before splitting.
112
+ - Never claim an improvement without the baseline beside it.
113
+
114
+ ## Report
115
+
116
+ ```
117
+ Goal: <decision> | Metric: <metric @ threshold/k> | Bar: <number>
118
+ Split: <method, sizes, date ranges or group key>
119
+ Results (validation, n seeds):
120
+ baseline: ... | simple model: ... | candidate: ...
121
+ Test (final, once): ...
122
+ Leakage checks: <passed / issues found>
123
+ Caveats: <segments that regressed, what was not checked>
124
+ Reproduce: <exact command and commit>
125
+ ```
@@ -0,0 +1,16 @@
1
+ {
2
+ "should_trigger": [
3
+ "We want to predict customer churn next quarter. How should I set up the experiment and which metric should we use?",
4
+ "My new model is 0.4% better on validation than the old one. Is that a real improvement?",
5
+ "Turn my exploratory Jupyter notebook into a reproducible training pipeline with tracked runs",
6
+ "Plan an ablation study for the three changes we stacked into the fraud model",
7
+ "How do I split patient records into train and test so the same patient never shows up in both?"
8
+ ],
9
+ "should_not_trigger": [
10
+ "My torch DataLoader is slow and the GPU sits at 20% utilisation",
11
+ "Check this pull request's feature engineering code for target leakage and broadcasting bugs",
12
+ "Write a SQL query that counts weekly active users by country",
13
+ "Score our RAG assistant's answers for faithfulness against the source documents",
14
+ "Benchmark this sorting function against the old version and tell me if it's faster"
15
+ ]
16
+ }
@@ -0,0 +1,115 @@
1
+ ---
2
+ name: mongodb-patterns
3
+ description: MongoDB document modelling and query tuning, from embed-versus-reference decisions and unbounded-array traps to compound indexes ordered by the ESR rule, reading explain executionStats, aggregation pipelines, multi-document transactions on replica sets, and $jsonSchema collection validation. Use when designing or changing MongoDB collections, a MongoDB query or aggregation is slow, adding indexes or validators, or deciding whether a write needs a transaction, with the native driver, Mongoose or another ODM.
4
+ license: MIT
5
+ compatibility: Any Agent Skills host. Commands are mongosh syntax; the same options exist in every official driver. Atlas-only features (Atlas Search, Performance Advisor) are noted as such.
6
+ metadata:
7
+ kete-loom/version: "0.1.0"
8
+ kete-loom/category: data
9
+ kete-loom/risk: runs-commands
10
+ kete-loom/requires: "mongosh"
11
+ kete-loom/owner: "Kete-org"
12
+ ---
13
+
14
+ # MongoDB patterns
15
+
16
+ Model documents around how the application reads them, index for the queries it actually runs, and prove every performance claim with `explain`. The detailed recipes live in `references/indexes-and-aggregation.md`.
17
+
18
+ ## 0. Before you start
19
+
20
+ 1. Find the driver or ODM (native driver, Mongoose, Motor, Spring Data, Prisma) and where the connection string comes from. Search for `MongoClient`, `mongoose.connect` or the `mongodb://` / `mongodb+srv://` variable.
21
+ 2. Get the server version and topology with `db.version()` and `db.hello()` (look for `setName` for a replica set, `msg: "isdbgrid"` for mongos). Transactions and change streams need a replica set or sharded cluster.
22
+ 3. List the queries the feature will run: filter fields, sort, projection, and how many documents each returns. If you can't list them, **stop and ask the user**; a model can't be judged without them.
23
+ 4. Never run `dropDatabase`, `drop`, `deleteMany({})`, `updateMany` without a tight filter, or a `collMod` that tightens validation on a shared or production database without the user's explicit approval. Build indexes on large production collections only after the user has agreed on timing; they consume I/O while they build.
24
+
25
+ ## 1. Embed or reference
26
+
27
+ Embed when the data is read together, owned by the parent, and bounded in size. Reference when it is shared, updated on its own, or grows without limit.
28
+
29
+ | Relationship | Default |
30
+ |---|---|
31
+ | One-to-few, read with the parent (addresses, line items of an order) | Embed an array |
32
+ | One-to-many, unbounded (comments on a post, events of a device) | Separate collection with the parent's `_id` indexed on the child |
33
+ | Many-to-many (students and courses) | Array of IDs on the side queried most, or a link collection |
34
+ | Data shared by many parents and edited (product name in old orders) | Reference; copy only fields that should freeze at write time (the price paid) |
35
+
36
+ Rules:
37
+
38
+ - A document is at most 16 MiB. Any array that grows with user activity must have a hard cap or live in its own collection. Large, frequently rewritten arrays also make every update expensive.
39
+ - Design so the common page loads with **one query**. If it needs `$lookup` on every request, reconsider the model (or accept it knowingly for low-traffic paths).
40
+ - Duplicating a field is fine when you know who updates the copies. Write it down in the code next to the update.
41
+ - Use the **bucket** pattern for time series on older servers (one document per device per hour), or a native time series collection (`db.createCollection(name, { timeseries: { timeField, metaField } })`).
42
+ - Use the **subset** pattern for large related lists: embed the latest N, keep the rest in a separate collection.
43
+
44
+ ## 2. Indexes
45
+
46
+ - Every query in a request path needs an index that supports its filter and sort. A `COLLSCAN` in `explain` on a large collection is a bug.
47
+ - Order compound index keys by **ESR**: **E**quality fields first, then **S**ort fields, then **R**ange fields (`$gt`, `$lt`, `$in` with many values, regex).
48
+ - One compound index can serve its prefixes: `{ tenantId: 1, status: 1, createdAt: -1 }` also serves `{ tenantId: 1 }`. Drop indexes that are a prefix of another.
49
+ - Use partial indexes (`partialFilterExpression`) for queries that only touch a subset, unique indexes for invariants, and TTL indexes (`expireAfterSeconds`) for expiring data.
50
+ - Each index costs RAM and slows every write. Check usage with `db.coll.aggregate([{ $indexStats: {} }])` before adding more, and propose removing unused ones (hide them first with `db.coll.hideIndex(name)` to test safely).
51
+
52
+ Verify with:
53
+
54
+ ```js
55
+ db.orders.find({ tenantId: t, status: "open" }).sort({ createdAt: -1 }).explain("executionStats")
56
+ ```
57
+
58
+ Read `winningPlan` (want `IXSCAN`, no in-memory `SORT` stage), `totalKeysExamined` and `totalDocsExamined` against `nReturned` (want them close), and `executionTimeMillis`. Report these numbers before and after.
59
+
60
+ ## 3. Aggregation
61
+
62
+ - Put `$match` first and `$project`/`$unset` early so later stages see fewer, smaller documents; only the leading `$match` and `$sort` can use an index.
63
+ - `$lookup` needs an index on the foreign field. Avoid `$lookup` inside hot request paths when an embed would do.
64
+ - Each blocking stage (`$group`, `$sort` without an index, `$bucket`) has a 100 MB memory limit before it spills to disk or errors, depending on `allowDiskUse` and the server default. Spilling is slow; prefer narrowing earlier.
65
+ - Use `$facet` for several counts over one result set instead of several round trips, and `$merge`/`$out` to precompute heavy reports on a schedule.
66
+ - Paginate with a range on an indexed key (`_id > lastSeenId`), not large `skip` values.
67
+
68
+ ## 4. Transactions
69
+
70
+ - A single-document write is already atomic, including its embedded arrays. Model so most invariants live in one document; reach for a transaction only when several documents must change together.
71
+ - Transactions need a replica set or sharded cluster, and by default must finish within 60 seconds (`transactionLifetimeLimitSeconds`). Keep them short and touch few documents.
72
+ - Use the driver's callback API (`session.withTransaction(fn)`), which retries on `TransientTransactionError` and `UnknownTransactionCommitResult`. Pass the session to **every** operation inside, or that operation runs outside the transaction.
73
+ - Use `writeConcern: { w: "majority" }` and `readConcern: "snapshot"` for transactions whose result must survive failover.
74
+ - Outside transactions, guard concurrent updates with conditional filters (`updateOne({ _id, version: 3 }, { $set: {...}, $inc: { version: 1 } })`) and check `matchedCount`.
75
+
76
+ ## 5. Schema validation
77
+
78
+ Keep the database honest even if one service skips the ODM's checks:
79
+
80
+ ```js
81
+ db.runCommand({
82
+ collMod: "orders",
83
+ validator: { $jsonSchema: {
84
+ bsonType: "object",
85
+ required: ["tenantId", "status", "total"],
86
+ properties: {
87
+ status: { enum: ["open", "paid", "cancelled"] },
88
+ total: { bsonType: "decimal" }
89
+ }
90
+ }},
91
+ validationLevel: "moderate",
92
+ validationAction: "error"
93
+ })
94
+ ```
95
+
96
+ - Roll out on an existing collection with `validationAction: "warn"` first, check the logs for violations, fix the data, then switch to `"error"`. `validationLevel: "moderate"` checks inserts and updates to documents that are already valid; updates to documents that were already invalid are not checked, so fix those in a backfill.
97
+ - Store money as `Decimal128` or integer minor units, never as a double. Store dates as BSON dates, not strings.
98
+
99
+ ## Never
100
+
101
+ - Build query filters from raw request JSON; a body like `{ "$ne": null }` becomes an operator. Validate types or use a sanitiser, and reject keys starting with `$`.
102
+ - Use `$where` or server-side JavaScript on user input.
103
+ - Let arrays grow without a limit inside a document.
104
+ - Claim a query is fast without `explain("executionStats")` output.
105
+
106
+ ## Report format (when reviewing)
107
+
108
+ ```
109
+ MongoDB review: <collections or feature>
110
+ Topology/version: <replica set | sharded | standalone>, <version>
111
+ Findings:
112
+ 1. [severity] <file:line or collection>: <problem> → <fix>
113
+ Explain evidence: <query> keys/docs examined vs returned, before → after
114
+ Not verified: <anything you could not run>
115
+ ```
@@ -0,0 +1,18 @@
1
+ {
2
+ "should_trigger": [
3
+ "Should I embed comments inside the post document or put them in their own MongoDB collection?",
4
+ "This Mongo aggregation with $lookup and $group takes 8 seconds, help me speed it up",
5
+ "explain() shows COLLSCAN on our orders collection, what compound index do we need?",
6
+ "Add a $jsonSchema validator to the users collection without breaking existing documents",
7
+ "Do I need a transaction in Mongoose to move credits between two wallet documents?",
8
+ "Design the document model for a multi-tenant SaaS on MongoDB Atlas"
9
+ ],
10
+ "should_not_trigger": [
11
+ "Cache the user profile in Redis with a five minute TTL",
12
+ "Write a Prisma schema for users and posts on Postgres",
13
+ "Design a ClickHouse table for billions of analytics events",
14
+ "Normalise this Postgres schema and add foreign keys",
15
+ "Write a zero-downtime migration that renames a column in MySQL",
16
+ "Review this pull request for SQL injection and auth bugs"
17
+ ]
18
+ }
@@ -0,0 +1,94 @@
1
+ # MongoDB indexes and aggregation recipes
2
+
3
+ Read this when designing an index for a specific query, debugging a slow aggregation, or writing a migration that reshapes documents. Confirm option names against the MongoDB manual for the server version in use.
4
+
5
+ ## ESR worked example
6
+
7
+ Query:
8
+
9
+ ```js
10
+ db.orders.find({ tenantId: t, status: "open", total: { $gte: 100 } }).sort({ createdAt: -1 })
11
+ ```
12
+
13
+ - Equality: `tenantId`, `status`
14
+ - Sort: `createdAt`
15
+ - Range: `total`
16
+
17
+ Index: `{ tenantId: 1, status: 1, createdAt: -1, total: 1 }`. Putting `total` before `createdAt` forces an in-memory sort.
18
+
19
+ A covered query (only indexed fields in filter and projection, `_id: 0` unless `_id` is indexed in that index) shows `totalDocsExamined: 0`.
20
+
21
+ ## Reading explain
22
+
23
+ ```js
24
+ db.coll.find(filter).sort(sort).explain("executionStats")
25
+ db.coll.aggregate(pipeline, { explain: true }) // or .explain("executionStats") on the cursor
26
+ ```
27
+
28
+ | Field | Good sign | Bad sign |
29
+ |---|---|---|
30
+ | `winningPlan.stage` tree | `IXSCAN` → `FETCH` | `COLLSCAN`; `SORT` stage (in-memory sort) |
31
+ | `totalKeysExamined` / `nReturned` | close to 1 | much larger: index not selective or wrong order |
32
+ | `totalDocsExamined` / `nReturned` | close to 1 | large: filter applied after fetch |
33
+ | `rejectedPlans` | few | many similar indexes competing |
34
+
35
+ Use the profiler only with the user's agreement on shared servers: `db.setProfilingLevel(1, { slowms: 100 })`, then `db.system.profile.find().sort({ ts: -1 }).limit(10)`. Turn it off afterwards with `db.setProfilingLevel(0)`. On Atlas, the Query Profiler and Performance Advisor show the same without changing settings.
36
+
37
+ ## Index options
38
+
39
+ ```js
40
+ db.users.createIndex({ email: 1 }, { unique: true, collation: { locale: "en", strength: 2 } }) // case-insensitive unique
41
+ db.sessions.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 }) // TTL at the stored date
42
+ db.orders.createIndex({ status: 1, createdAt: -1 }, { partialFilterExpression: { status: "open" } })
43
+ db.coll.hideIndex("old_index_name") // test dropping without losing it
44
+ db.coll.unhideIndex("old_index_name")
45
+ ```
46
+
47
+ - A query uses a collation-specific index only if it specifies the same collation.
48
+ - A partial index is used only when the query filter implies the partial expression.
49
+ - The TTL monitor runs periodically, so expired documents disappear with some delay; don't rely on it for exact expiry.
50
+ - A multikey index (on an array field) can't be compound with a second array field.
51
+
52
+ ## Aggregation patterns
53
+
54
+ Top N per group:
55
+
56
+ ```js
57
+ db.orders.aggregate([
58
+ { $match: { tenantId: t, createdAt: { $gte: since } } },
59
+ { $sort: { customerId: 1, total: -1 } },
60
+ { $group: { _id: "$customerId", top: { $firstN: { input: "$$ROOT", n: 3 } } } }
61
+ ])
62
+ ```
63
+
64
+ (`$firstN` needs MongoDB 5.2 or later; on older servers use `$push` then `$slice`.)
65
+
66
+ Indexed `$lookup` with a sub-pipeline (combining `localField`/`foreignField` with `pipeline` needs MongoDB 5.0 or later; older servers need `let` and `$expr`):
67
+
68
+ ```js
69
+ { $lookup: {
70
+ from: "customers",
71
+ localField: "customerId",
72
+ foreignField: "_id",
73
+ pipeline: [{ $project: { name: 1, tier: 1 } }],
74
+ as: "customer"
75
+ }}
76
+ ```
77
+
78
+ Several counts in one pass:
79
+
80
+ ```js
81
+ { $facet: {
82
+ byStatus: [{ $group: { _id: "$status", n: { $sum: 1 } } }],
83
+ total: [{ $count: "n" }]
84
+ }}
85
+ ```
86
+
87
+ Precompute a report: end the pipeline with `{ $merge: { into: "daily_sales", on: "_id", whenMatched: "replace" } }` and run it from a scheduled job.
88
+
89
+ ## Reshaping documents safely
90
+
91
+ 1. Add the new field in code that writes both shapes; read with a fallback.
92
+ 2. Backfill in batches with `bulkWrite` filtered on documents missing the new field, so the job can be re-run.
93
+ 3. Switch reads to the new field, then stop writing the old one, then remove it with `$unset` in batches.
94
+ 4. Tighten the `$jsonSchema` validator last.
@@ -0,0 +1,70 @@
1
+ ---
2
+ name: mpesa-daraja-integration
3
+ description: Implements and audits direct Safaricom M-Pesa integrations on the Daraja API in Kenya, including the OAuth client-credentials token, Lipa na M-Pesa Online (STK Push) with the base64 shortcode+passkey+timestamp password, stkCallback parsing, confirmation through the STK Push Query endpoint, C2B URL registration with validation and confirmation, B2C payouts with SecurityCredential, and the sandbox-to-production go-live path. Use when calling Daraja endpoints yourself rather than via Flutterwave or another aggregator, wiring an M-Pesa paybill or till into an app, or debugging Daraja errors such as invalid access token, wrong credentials or ResultCode 1032.
4
+ license: MIT
5
+ compatibility: Any Agent Skills host. Live calls need network access to sandbox.safaricom.co.ke or api.safaricom.co.ke. Examples are TypeScript (Node 18+); the rules apply to any backend language.
6
+ metadata:
7
+ kete-loom/version: "0.1.0"
8
+ kete-loom/category: integrations
9
+ kete-loom/risk: network
10
+ kete-loom/owner: "Kete-org"
11
+ ---
12
+
13
+ # M-Pesa Daraja integration
14
+
15
+ Build an M-Pesa flow where a forged callback can't mark an order paid, a lost callback still settles, and a payout is never sent twice. This skill is for Safaricom's Daraja API called directly. If the project collects M-Pesa through Flutterwave, Paystack or another aggregator, follow that provider's flow instead.
16
+
17
+ ## Ground rules
18
+
19
+ 1. **Credentials stay on the server.** Consumer key and secret, passkey, initiator name and initiator password are secrets in the environment. Sandbox and production have different keys, shortcodes, passkeys and base URLs (`https://sandbox.safaricom.co.ke` vs `https://api.safaricom.co.ke`).
20
+ 2. **Cache the access token.** `GET /oauth/v1/generate?grant_type=client_credentials` with Basic auth (`consumerKey:consumerSecret`) returns a token valid for about an hour (`expires_in` 3599 or 3600). Refresh before expiry; don't request one per payment.
21
+ 3. **The server sets the amount.** Daraja `Amount` is whole shillings. Compute it from your own order; never accept it from the client.
22
+ 4. **`ResponseCode: "0"` means accepted, not paid.** The STK Push response only says the prompt was queued. Store `CheckoutRequestID` and `MerchantRequestID` against the order straight away.
23
+ 5. **Callbacks are unsigned.** Daraja does not sign `stkCallback`, C2B or B2C results. Never give value from the callback body alone. Put an unguessable per-payment token in the callback path, match `CheckoutRequestID` to a stored pending payment, and confirm with STK Push Query (or Transaction Status) before fulfilling. If Safaricom gives you its callback IP range, allow-list it as an extra layer.
24
+ 6. **Fulfilment is idempotent.** Guarded update keyed on `CheckoutRequestID` (`... WHERE status = 'pending'`), and a unique constraint on `MpesaReceiptNumber`. Callbacks, queries and retries can all arrive.
25
+ 7. **Payouts are never sent blind twice.** Generate and store a unique `OriginatorConversationID` per payout before the call. Daraja is not documented to reject a repeated ID, so after a timeout or lost result check Transaction Status first and retry only when it shows the payout did not happen.
26
+
27
+ ## STK Push flow
28
+
29
+ ```
30
+ client ──(order id, phone 2547XXXXXXXX)──▶ server: create pending payment
31
+ server ──POST /mpesa/stkpush/v1/processrequest──▶ Daraja: ResponseCode "0", CheckoutRequestID
32
+ customer enters M-Pesa PIN on the phone
33
+ Daraja ──POST CallBackURL {Body.stkCallback}──▶ server: 200 at once, queue a check
34
+ server ──POST /mpesa/stkpushquery/v1/query──▶ ResultCode 0 + amount matches → fulfil once
35
+ background job: query payments still pending after ~1-2 minutes; expire them later
36
+ ```
37
+
38
+ ## Implementation steps
39
+
40
+ 1. **Configure** environment variables: base URL, consumer key/secret, `BusinessShortCode`, passkey, callback base URL, and for B2C the initiator name and production certificate. Shapes and samples: `references/api.md`.
41
+ 2. **Build the password**: `Timestamp` is `YYYYMMDDHHmmss` in Kenyan time (EAT, UTC+3); `Password = base64(BusinessShortCode + Passkey + Timestamp)`. Generate both per request; a stale timestamp or one in the wrong timezone causes "Wrong credentials".
42
+ 3. **Send STK Push** with `TransactionType` `CustomerPayBillOnline` (paybill) or `CustomerBuyGoodsOnline` (till; then `PartyB` is the till number while `BusinessShortCode` is the store/HO number). Normalise the phone to `2547XXXXXXXX` or `2541XXXXXXXX`. `AccountReference` is at most 12 characters, `TransactionDesc` at most 13.
43
+ 4. **Handle the callback** as in `references/callbacks.md`: respond quickly, match on `CheckoutRequestID`, read `ResultCode` and `CallbackMetadata`, then confirm with STK Push Query.
44
+ 5. **Map result codes** to customer messages: `1032` cancelled, `1037` phone unreachable, `1` insufficient balance, `2001` wrong PIN, `1019` expired, `17` duplicate request within 2 minutes. Let the customer retry with a new STK Push.
45
+ 6. **C2B (customer pays your paybill/till from their phone)**: register Confirmation and Validation URLs once with `/mpesa/c2b/v2/registerurl`; see `references/callbacks.md`. Match payments to orders by `BillRefNumber` (the account number the customer typed) and dedupe on `TransID`.
46
+ 7. **B2C payouts**: `/mpesa/b2c/v3/paymentrequest` with `SecurityCredential` (initiator password RSA-encrypted with Safaricom's certificate for that environment, base64). The result arrives at `ResultURL`; a timeout at `QueueTimeOutURL`. Treat a queue timeout as unknown, not failed: check Transaction Status before retrying.
47
+ 8. **Persist** per payment: order id, phone, amount, `MerchantRequestID`, `CheckoutRequestID`, `MpesaReceiptNumber`, `ResultCode`, `ResultDesc`, status, timestamps.
48
+
49
+ ## Reviewing an existing integration
50
+
51
+ Check each ground rule, then look for:
52
+
53
+ - Order marked paid when the STK Push request returns `ResponseCode "0"`.
54
+ - Callback body trusted with no match to a stored `CheckoutRequestID` and no query.
55
+ - `Amount` read from `CallbackMetadata` without comparing it to the stored order amount.
56
+ - Token fetched on every request, causing spike-arrest or quota errors (`500.003.02`, `500.003.03`).
57
+ - Timestamp built from server UTC or local time instead of EAT.
58
+ - Callback URL that is not public HTTPS, uses a tunnel URL in production, or contains blocked words such as `mpesa`, `safaricom`, `sql`, `exec`, `cmd` or `query`.
59
+ - Sandbox shortcode `174379` or sandbox passkey left in production config.
60
+ - B2C retried after a timeout or missing result without a Transaction Status check first.
61
+
62
+ ## Stop and ask the user
63
+
64
+ - Paybill or till, and which shortcode is used on go-live.
65
+ - Whether C2B validation is needed; it is off by default and Safaricom has to enable it.
66
+ - Before writing any B2C code: payouts move real money and need a B2C shortcode and an API initiator created on the M-Pesa org portal.
67
+
68
+ ## Before you finish
69
+
70
+ Daraja's docs at developer.safaricom.co.ke are the final word on fields and endpoints; this skill gives the rules and the shape. Production endpoints and the production passkey are issued at go-live. Then test in the sandbox: a successful STK Push, a cancelled prompt (1032), a phone that never answers, a callback that never arrives (the query job must settle it), a forged callback with a known `CheckoutRequestID` but a failed query (must not fulfil), and the same callback twice.
@@ -0,0 +1,16 @@
1
+ {
2
+ "should_trigger": [
3
+ "Implement Lipa na M-Pesa STK push for our Kenyan delivery app using Daraja",
4
+ "Daraja keeps returning Wrong credentials for my STK push password, what's wrong?",
5
+ "Register C2B confirmation and validation URLs for our paybill number",
6
+ "Pay out refunds to customers' M-Pesa numbers with the B2C API",
7
+ "Our stkCallback never arrives in production, how do we still confirm the payment?"
8
+ ],
9
+ "should_not_trigger": [
10
+ "Charge a Kenyan customer's M-Pesa wallet through Flutterwave from our backend",
11
+ "Integrate MTN MoMo request to pay for Ugandan customers",
12
+ "Accept Telecel Cash payments through Hubtel in our Ghana app",
13
+ "Check our checkout code for client-trusted amounts and missing idempotency",
14
+ "Add Stripe Checkout for card payments in Kenya"
15
+ ]
16
+ }
@@ -0,0 +1,103 @@
1
+ # Daraja API shapes used by this skill
2
+
3
+ Base URLs: sandbox `https://sandbox.safaricom.co.ke`, production `https://api.safaricom.co.ke`. Every call except the token call sends `Authorization: Bearer <token>` and `Content-Type: application/json` (a missing content type gives "Bad Request - Invalid BusinessShortCode").
4
+
5
+ Confirm fields against developer.safaricom.co.ke before shipping; this is a working summary.
6
+
7
+ ## Access token
8
+
9
+ `GET /oauth/v1/generate?grant_type=client_credentials` with `Authorization: Basic base64(consumerKey:consumerSecret)`.
10
+
11
+ Response: `{ "access_token": "...", "expires_in": "3599" }`. `404.001.03 Invalid Access Token` means expired or from the wrong app.
12
+
13
+ ## STK Push (M-Pesa Express)
14
+
15
+ `POST /mpesa/stkpush/v1/processrequest`
16
+
17
+ ```json
18
+ {
19
+ "BusinessShortCode": "174379",
20
+ "Password": "<base64(BusinessShortCode + Passkey + Timestamp)>",
21
+ "Timestamp": "20260618092408",
22
+ "TransactionType": "CustomerPayBillOnline",
23
+ "Amount": "150",
24
+ "PartyA": "254712345678",
25
+ "PartyB": "174379",
26
+ "PhoneNumber": "254712345678",
27
+ "CallBackURL": "https://api.example.com/hooks/daraja/stk/<per-payment-token>",
28
+ "AccountReference": "ORD8F2C1A",
29
+ "TransactionDesc": "Order"
30
+ }
31
+ ```
32
+
33
+ Response: `MerchantRequestID`, `CheckoutRequestID`, `ResponseCode` (`"0"` = accepted), `ResponseDescription`, `CustomerMessage`.
34
+
35
+ Limits from the Daraja FAQ: minimum KES 1, up to KES 250,000 per transaction, daily KES 500,000. Only one prompt can be live per subscriber; "Unable to lock subscriber" means wait about a minute.
36
+
37
+ ## STK Push Query
38
+
39
+ `POST /mpesa/stkpushquery/v1/query`
40
+
41
+ ```json
42
+ { "BusinessShortCode": "174379", "Password": "<fresh>", "Timestamp": "<fresh>", "CheckoutRequestID": "ws_CO_..." }
43
+ ```
44
+
45
+ Response has `ResultCode` and `ResultDesc`. `ResultCode` `"0"` = paid. While the customer has not answered, the query returns an error rather than a final code; retry with backoff.
46
+
47
+ ## Result codes (STK)
48
+
49
+ | Code | Meaning |
50
+ |---|---|
51
+ | 0 | Paid |
52
+ | 1 | Insufficient balance |
53
+ | 17 | Same amount to same customer within 2 minutes |
54
+ | 1019 | Transaction expired |
55
+ | 1025 | Push failed (prompt over 182 characters; shorten AccountReference) |
56
+ | 1032 | Cancelled by user |
57
+ | 1037 | Phone unreachable |
58
+ | 2001 | Wrong PIN |
59
+ | 2028 | TransactionType / PartyB don't match the shortcode type |
60
+
61
+ ## C2B register URLs
62
+
63
+ `POST /mpesa/c2b/v2/registerurl`
64
+
65
+ ```json
66
+ { "ShortCode": "600638", "ResponseType": "Completed", "ConfirmationURL": "https://api.example.com/hooks/daraja/c2b/confirm", "ValidationURL": "https://api.example.com/hooks/daraja/c2b/validate" }
67
+ ```
68
+
69
+ `ResponseType` (`Completed` or `Cancelled`) is what M-Pesa does when your validation URL is unreachable. In production, registration is one-time; change URLs by deleting them in the URL management self-service and re-registering. Sandbox has `/mpesa/c2b/v2/simulate` for test payments.
70
+
71
+ ## B2C payment
72
+
73
+ `POST /mpesa/b2c/v3/paymentrequest`
74
+
75
+ ```json
76
+ {
77
+ "OriginatorConversationID": "payout_7d1e9b",
78
+ "InitiatorName": "apiop",
79
+ "SecurityCredential": "<RSA-encrypt(initiator password, Safaricom cert) as base64>",
80
+ "CommandID": "BusinessPayment",
81
+ "Amount": "500",
82
+ "PartyA": "600997",
83
+ "PartyB": "254712345678",
84
+ "Remarks": "Refund ORD8F2C1A",
85
+ "QueueTimeOutURL": "https://api.example.com/hooks/daraja/b2c/timeout/<token>",
86
+ "ResultURL": "https://api.example.com/hooks/daraja/b2c/result/<token>",
87
+ "Occassion": "Refund"
88
+ }
89
+ ```
90
+
91
+ `CommandID`: `BusinessPayment`, `SalaryPayment` or `PromotionPayment`. Note the API's spelling `Occassion`. The sandbox and production certificates differ. The response (`ConversationID`, `OriginatorConversationID`, `ResponseCode`) only means accepted; the outcome is the `Result` posted to `ResultURL` (`ResultCode`, `TransactionID`, `ResultParameters.ResultParameter[]`).
92
+
93
+ ## Password and timestamp (TypeScript)
94
+
95
+ ```ts
96
+ export function stkPassword(shortCode: string, passkey: string, now = new Date()) {
97
+ // Daraja expects Kenyan time (EAT, UTC+3), formatted YYYYMMDDHHmmss
98
+ const eat = new Date(now.getTime() + 3 * 60 * 60 * 1000).toISOString();
99
+ const timestamp = eat.slice(0, 19).replace(/[-T:]/g, '');
100
+ const password = Buffer.from(shortCode + passkey + timestamp).toString('base64');
101
+ return { timestamp, password };
102
+ }
103
+ ```
@@ -0,0 +1,74 @@
1
+ # Daraja callbacks
2
+
3
+ None of these are signed. Treat every body as untrusted: match it to a record you created, then confirm with a query before giving value.
4
+
5
+ ## STK Push callback
6
+
7
+ `POST` to your `CallBackURL`:
8
+
9
+ ```json
10
+ {
11
+ "Body": {
12
+ "stkCallback": {
13
+ "MerchantRequestID": "29115-34620561-1",
14
+ "CheckoutRequestID": "ws_CO_191220191020363925",
15
+ "ResultCode": 0,
16
+ "ResultDesc": "The service request is processed successfully.",
17
+ "CallbackMetadata": {
18
+ "Item": [
19
+ { "Name": "Amount", "Value": 1.0 },
20
+ { "Name": "MpesaReceiptNumber", "Value": "NLJ7RT61SV" },
21
+ { "Name": "TransactionDate", "Value": 20191219102115 },
22
+ { "Name": "PhoneNumber", "Value": 254708374149 }
23
+ ]
24
+ }
25
+ }
26
+ }
27
+ }
28
+ ```
29
+
30
+ A failed or cancelled payment has `ResultCode` other than `0` and no `CallbackMetadata`. Read items by `Name`, not by position; `Balance` sometimes appears and shifts the order.
31
+
32
+ ### Handler rules
33
+
34
+ 1. Check the per-payment token in the path, then find the pending payment by `CheckoutRequestID`. Unknown → log and return 200; never create an order from a callback.
35
+ 2. Respond `200` with `{ "ResultCode": 0, "ResultDesc": "Accepted" }` quickly and queue the work.
36
+ 3. In the worker: if `ResultCode !== 0`, mark failed with the code. If `0`, run STK Push Query; fulfil only if the query says `0` **and** `Amount` equals the stored amount. Guarded update on status, unique `MpesaReceiptNumber`.
37
+
38
+ ```ts
39
+ app.post('/hooks/daraja/stk/:token', express.json(), async (req, res) => {
40
+ const cb = req.body?.Body?.stkCallback;
41
+ const payment = cb && (await payments.findPending(cb.CheckoutRequestID, req.params.token));
42
+ res.json({ ResultCode: 0, ResultDesc: 'Accepted' });
43
+ if (payment) await queue.add('daraja-confirm', { checkoutRequestId: cb.CheckoutRequestID, resultCode: cb.ResultCode });
44
+ });
45
+ ```
46
+
47
+ ## C2B validation and confirmation
48
+
49
+ Both URLs receive the same shape:
50
+
51
+ ```json
52
+ {
53
+ "TransactionType": "Pay Bill",
54
+ "TransID": "RKTQDM7W6S",
55
+ "TransTime": "20191122063845",
56
+ "TransAmount": "10",
57
+ "BusinessShortCode": "600638",
58
+ "BillRefNumber": "invoice008",
59
+ "InvoiceNumber": "",
60
+ "OrgAccountBalance": "",
61
+ "ThirdPartyTransID": "",
62
+ "MSISDN": "25470****149",
63
+ "FirstName": "John",
64
+ "MiddleName": "",
65
+ "LastName": "Doe"
66
+ }
67
+ ```
68
+
69
+ - **Validation** (only if Safaricom enabled external validation on your shortcode): reply `{ "ResultCode": "0", "ResultDesc": "Accepted" }` to accept, or `{ "ResultCode": "C2B00012", "ResultDesc": "Rejected" }` to reject (`C2B00011` invalid MSISDN, `C2B00012` invalid account number, `C2B00013` invalid amount, `C2B00014` invalid KYC, `C2B00015` invalid shortcode, `C2B00016` other). Reply fast; if it is unreachable M-Pesa applies the registered `ResponseType`.
70
+ - **Confirmation**: the payment is complete. Dedupe on `TransID`, match `BillRefNumber` to an open invoice, compare `TransAmount`, and park anything that doesn't match for manual review instead of dropping it: the customer's money has already moved. `MSISDN` may be masked or hashed, so don't rely on it to identify the payer.
71
+
72
+ ## B2C result
73
+
74
+ `POST` to `ResultURL` with `{ "Result": { "ResultType", "ResultCode", "ResultDesc", "OriginatorConversationID", "ConversationID", "TransactionID", "ResultParameters": { "ResultParameter": [ { "Key", "Value" } ] } } }`. Match on `OriginatorConversationID`. `ResultCode` `0` = paid. A post to `QueueTimeOutURL` means the outcome is unknown: run Transaction Status (`/mpesa/transactionstatus/v1/query`) before any retry.