@protoboxai/codeloop 0.3.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 (290) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +589 -0
  3. package/dist/commands/adopt.d.ts +2 -0
  4. package/dist/commands/adopt.js +26 -0
  5. package/dist/commands/adopt.js.map +1 -0
  6. package/dist/commands/brief.d.ts +2 -0
  7. package/dist/commands/brief.js +22 -0
  8. package/dist/commands/brief.js.map +1 -0
  9. package/dist/commands/card.d.ts +6 -0
  10. package/dist/commands/card.js +159 -0
  11. package/dist/commands/card.js.map +1 -0
  12. package/dist/commands/check.d.ts +4 -0
  13. package/dist/commands/check.js +76 -0
  14. package/dist/commands/check.js.map +1 -0
  15. package/dist/commands/cloud.d.ts +8 -0
  16. package/dist/commands/cloud.js +123 -0
  17. package/dist/commands/cloud.js.map +1 -0
  18. package/dist/commands/guard.d.ts +2 -0
  19. package/dist/commands/guard.js +26 -0
  20. package/dist/commands/guard.js.map +1 -0
  21. package/dist/commands/import.d.ts +2 -0
  22. package/dist/commands/import.js +24 -0
  23. package/dist/commands/import.js.map +1 -0
  24. package/dist/commands/inbox.d.ts +2 -0
  25. package/dist/commands/inbox.js +48 -0
  26. package/dist/commands/inbox.js.map +1 -0
  27. package/dist/commands/init.d.ts +2 -0
  28. package/dist/commands/init.js +142 -0
  29. package/dist/commands/init.js.map +1 -0
  30. package/dist/commands/install.d.ts +2 -0
  31. package/dist/commands/install.js +125 -0
  32. package/dist/commands/install.js.map +1 -0
  33. package/dist/commands/lane.d.ts +2 -0
  34. package/dist/commands/lane.js +100 -0
  35. package/dist/commands/lane.js.map +1 -0
  36. package/dist/commands/list.d.ts +2 -0
  37. package/dist/commands/list.js +35 -0
  38. package/dist/commands/list.js.map +1 -0
  39. package/dist/commands/login.d.ts +2 -0
  40. package/dist/commands/login.js +77 -0
  41. package/dist/commands/login.js.map +1 -0
  42. package/dist/commands/mock.d.ts +3 -0
  43. package/dist/commands/mock.js +22 -0
  44. package/dist/commands/mock.js.map +1 -0
  45. package/dist/commands/pack.d.ts +2 -0
  46. package/dist/commands/pack.js +19 -0
  47. package/dist/commands/pack.js.map +1 -0
  48. package/dist/commands/publish.d.ts +2 -0
  49. package/dist/commands/publish.js +125 -0
  50. package/dist/commands/publish.js.map +1 -0
  51. package/dist/commands/remove.d.ts +2 -0
  52. package/dist/commands/remove.js +31 -0
  53. package/dist/commands/remove.js.map +1 -0
  54. package/dist/commands/render.d.ts +5 -0
  55. package/dist/commands/render.js +47 -0
  56. package/dist/commands/render.js.map +1 -0
  57. package/dist/commands/run.d.ts +2 -0
  58. package/dist/commands/run.js +45 -0
  59. package/dist/commands/run.js.map +1 -0
  60. package/dist/commands/scan.d.ts +2 -0
  61. package/dist/commands/scan.js +26 -0
  62. package/dist/commands/scan.js.map +1 -0
  63. package/dist/commands/schedule.d.ts +2 -0
  64. package/dist/commands/schedule.js +51 -0
  65. package/dist/commands/schedule.js.map +1 -0
  66. package/dist/commands/search.d.ts +2 -0
  67. package/dist/commands/search.js +85 -0
  68. package/dist/commands/search.js.map +1 -0
  69. package/dist/commands/serve.d.ts +7 -0
  70. package/dist/commands/serve.js +126 -0
  71. package/dist/commands/serve.js.map +1 -0
  72. package/dist/commands/spec.d.ts +3 -0
  73. package/dist/commands/spec.js +64 -0
  74. package/dist/commands/spec.js.map +1 -0
  75. package/dist/commands/status.d.ts +3 -0
  76. package/dist/commands/status.js +251 -0
  77. package/dist/commands/status.js.map +1 -0
  78. package/dist/commands/update.d.ts +2 -0
  79. package/dist/commands/update.js +83 -0
  80. package/dist/commands/update.js.map +1 -0
  81. package/dist/commands/verify.d.ts +3 -0
  82. package/dist/commands/verify.js +75 -0
  83. package/dist/commands/verify.js.map +1 -0
  84. package/dist/commands/watch.d.ts +6 -0
  85. package/dist/commands/watch.js +111 -0
  86. package/dist/commands/watch.js.map +1 -0
  87. package/dist/commands/wiki.d.ts +3 -0
  88. package/dist/commands/wiki.js +85 -0
  89. package/dist/commands/wiki.js.map +1 -0
  90. package/dist/index.d.ts +2 -0
  91. package/dist/index.js +86 -0
  92. package/dist/index.js.map +1 -0
  93. package/dist/lib/agent.d.ts +27 -0
  94. package/dist/lib/agent.js +178 -0
  95. package/dist/lib/agent.js.map +1 -0
  96. package/dist/lib/board.d.ts +38 -0
  97. package/dist/lib/board.js +86 -0
  98. package/dist/lib/board.js.map +1 -0
  99. package/dist/lib/cards.d.ts +82 -0
  100. package/dist/lib/cards.js +107 -0
  101. package/dist/lib/cards.js.map +1 -0
  102. package/dist/lib/clock.d.ts +5 -0
  103. package/dist/lib/clock.js +14 -0
  104. package/dist/lib/clock.js.map +1 -0
  105. package/dist/lib/cloud.d.ts +122 -0
  106. package/dist/lib/cloud.js +580 -0
  107. package/dist/lib/cloud.js.map +1 -0
  108. package/dist/lib/competitors.d.ts +28 -0
  109. package/dist/lib/competitors.js +90 -0
  110. package/dist/lib/competitors.js.map +1 -0
  111. package/dist/lib/config.d.ts +7 -0
  112. package/dist/lib/config.js +25 -0
  113. package/dist/lib/config.js.map +1 -0
  114. package/dist/lib/cron.d.ts +5 -0
  115. package/dist/lib/cron.js +82 -0
  116. package/dist/lib/cron.js.map +1 -0
  117. package/dist/lib/detect.d.ts +13 -0
  118. package/dist/lib/detect.js +60 -0
  119. package/dist/lib/detect.js.map +1 -0
  120. package/dist/lib/engine.d.ts +88 -0
  121. package/dist/lib/engine.js +435 -0
  122. package/dist/lib/engine.js.map +1 -0
  123. package/dist/lib/flow.d.ts +44 -0
  124. package/dist/lib/flow.js +121 -0
  125. package/dist/lib/flow.js.map +1 -0
  126. package/dist/lib/glob.d.ts +2 -0
  127. package/dist/lib/glob.js +10 -0
  128. package/dist/lib/glob.js.map +1 -0
  129. package/dist/lib/import.d.ts +13 -0
  130. package/dist/lib/import.js +127 -0
  131. package/dist/lib/import.js.map +1 -0
  132. package/dist/lib/inbox.d.ts +42 -0
  133. package/dist/lib/inbox.js +65 -0
  134. package/dist/lib/inbox.js.map +1 -0
  135. package/dist/lib/lane.d.ts +71 -0
  136. package/dist/lib/lane.js +105 -0
  137. package/dist/lib/lane.js.map +1 -0
  138. package/dist/lib/lock.d.ts +6 -0
  139. package/dist/lib/lock.js +64 -0
  140. package/dist/lib/lock.js.map +1 -0
  141. package/dist/lib/mcp.d.ts +2 -0
  142. package/dist/lib/mcp.js +57 -0
  143. package/dist/lib/mcp.js.map +1 -0
  144. package/dist/lib/mock.d.ts +17 -0
  145. package/dist/lib/mock.js +137 -0
  146. package/dist/lib/mock.js.map +1 -0
  147. package/dist/lib/pack.d.ts +24 -0
  148. package/dist/lib/pack.js +77 -0
  149. package/dist/lib/pack.js.map +1 -0
  150. package/dist/lib/proposals.d.ts +48 -0
  151. package/dist/lib/proposals.js +240 -0
  152. package/dist/lib/proposals.js.map +1 -0
  153. package/dist/lib/render.d.ts +7 -0
  154. package/dist/lib/render.js +84 -0
  155. package/dist/lib/render.js.map +1 -0
  156. package/dist/lib/research.d.ts +8 -0
  157. package/dist/lib/research.js +39 -0
  158. package/dist/lib/research.js.map +1 -0
  159. package/dist/lib/run.d.ts +38 -0
  160. package/dist/lib/run.js +215 -0
  161. package/dist/lib/run.js.map +1 -0
  162. package/dist/lib/scaffold.d.ts +16 -0
  163. package/dist/lib/scaffold.js +175 -0
  164. package/dist/lib/scaffold.js.map +1 -0
  165. package/dist/lib/scan.d.ts +22 -0
  166. package/dist/lib/scan.js +85 -0
  167. package/dist/lib/scan.js.map +1 -0
  168. package/dist/lib/schedule.d.ts +20 -0
  169. package/dist/lib/schedule.js +66 -0
  170. package/dist/lib/schedule.js.map +1 -0
  171. package/dist/lib/server.d.ts +68 -0
  172. package/dist/lib/server.js +235 -0
  173. package/dist/lib/server.js.map +1 -0
  174. package/dist/lib/shell.d.ts +1 -0
  175. package/dist/lib/shell.js +25 -0
  176. package/dist/lib/shell.js.map +1 -0
  177. package/dist/lib/skills.d.ts +20 -0
  178. package/dist/lib/skills.js +92 -0
  179. package/dist/lib/skills.js.map +1 -0
  180. package/dist/lib/spec.d.ts +24 -0
  181. package/dist/lib/spec.js +102 -0
  182. package/dist/lib/spec.js.map +1 -0
  183. package/dist/lib/stats.d.ts +13 -0
  184. package/dist/lib/stats.js +43 -0
  185. package/dist/lib/stats.js.map +1 -0
  186. package/dist/lib/verify.d.ts +25 -0
  187. package/dist/lib/verify.js +135 -0
  188. package/dist/lib/verify.js.map +1 -0
  189. package/dist/lib/version.d.ts +10 -0
  190. package/dist/lib/version.js +27 -0
  191. package/dist/lib/version.js.map +1 -0
  192. package/dist/lib/wiki.d.ts +51 -0
  193. package/dist/lib/wiki.js +164 -0
  194. package/dist/lib/wiki.js.map +1 -0
  195. package/dist/registry/index.d.ts +7 -0
  196. package/dist/registry/index.js +8 -0
  197. package/dist/registry/index.js.map +1 -0
  198. package/dist/registry/installer.d.ts +30 -0
  199. package/dist/registry/installer.js +133 -0
  200. package/dist/registry/installer.js.map +1 -0
  201. package/dist/registry/local-index.d.ts +32 -0
  202. package/dist/registry/local-index.js +58 -0
  203. package/dist/registry/local-index.js.map +1 -0
  204. package/dist/registry/lockfile.d.ts +40 -0
  205. package/dist/registry/lockfile.js +85 -0
  206. package/dist/registry/lockfile.js.map +1 -0
  207. package/dist/registry/security.d.ts +25 -0
  208. package/dist/registry/security.js +100 -0
  209. package/dist/registry/security.js.map +1 -0
  210. package/dist/registry/skill-schema.d.ts +30 -0
  211. package/dist/registry/skill-schema.js +95 -0
  212. package/dist/registry/skill-schema.js.map +1 -0
  213. package/dist/ui/404.html +1 -0
  214. package/dist/ui/_next/static/6wzGE5sCtbYkSyhMWxL32/_buildManifest.js +1 -0
  215. package/dist/ui/_next/static/6wzGE5sCtbYkSyhMWxL32/_ssgManifest.js +1 -0
  216. package/dist/ui/_next/static/chunks/255-54d3085ce94738a4.js +1 -0
  217. package/dist/ui/_next/static/chunks/423-bb541b7ae2733575.js +1 -0
  218. package/dist/ui/_next/static/chunks/4bd1b696-c023c6e3521b1417.js +1 -0
  219. package/dist/ui/_next/static/chunks/app/_not-found/page-d6bc774f7acb716e.js +1 -0
  220. package/dist/ui/_next/static/chunks/app/layout-e5fc8e78e1c8da95.js +1 -0
  221. package/dist/ui/_next/static/chunks/app/page-0c34b6e119cef236.js +1 -0
  222. package/dist/ui/_next/static/chunks/framework-de98b93a850cfc71.js +1 -0
  223. package/dist/ui/_next/static/chunks/main-49fd204fc9037ea3.js +1 -0
  224. package/dist/ui/_next/static/chunks/main-app-c46afa2f48f3aaef.js +1 -0
  225. package/dist/ui/_next/static/chunks/pages/_app-7d307437aca18ad4.js +1 -0
  226. package/dist/ui/_next/static/chunks/pages/_error-cb2a52f75f2162e2.js +1 -0
  227. package/dist/ui/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  228. package/dist/ui/_next/static/chunks/webpack-4a462cecab786e93.js +1 -0
  229. package/dist/ui/_next/static/css/1bf01240dbfd6088.css +1 -0
  230. package/dist/ui/index.html +1 -0
  231. package/dist/ui/index.txt +19 -0
  232. package/dist/watch/index.d.ts +21 -0
  233. package/dist/watch/index.js +88 -0
  234. package/dist/watch/index.js.map +1 -0
  235. package/dist/watch/reporter.d.ts +11 -0
  236. package/dist/watch/reporter.js +44 -0
  237. package/dist/watch/reporter.js.map +1 -0
  238. package/dist/watch/signals.d.ts +38 -0
  239. package/dist/watch/signals.js +119 -0
  240. package/dist/watch/signals.js.map +1 -0
  241. package/dist/watch/triggers.d.ts +10 -0
  242. package/dist/watch/triggers.js +67 -0
  243. package/dist/watch/triggers.js.map +1 -0
  244. package/package.json +64 -0
  245. package/registry/index.json +106 -0
  246. package/starters/generic.yaml +95 -0
  247. package/starters/go.yaml +99 -0
  248. package/starters/node-typescript.yaml +108 -0
  249. package/starters/python.yaml +105 -0
  250. package/templates/ci/codeloop-pr.yml +29 -0
  251. package/templates/ci/codeloop-prod.yml +27 -0
  252. package/templates/ci/codeloop-staging.yml +34 -0
  253. package/templates/codeloop/board.json +5 -0
  254. package/templates/codeloop/gotchas.md +13 -0
  255. package/templates/codeloop/patterns.md +15 -0
  256. package/templates/codeloop/principles.md +49 -0
  257. package/templates/codeloop/rules.md +23 -0
  258. package/templates/commands/commit.md +255 -0
  259. package/templates/commands/debug.md +142 -0
  260. package/templates/commands/deploy.md +144 -0
  261. package/templates/commands/design.md +102 -0
  262. package/templates/commands/manage.md +77 -0
  263. package/templates/commands/plan.md +84 -0
  264. package/templates/commands/qa.md +155 -0
  265. package/templates/commands/reflect.md +93 -0
  266. package/templates/commands/ship.md +187 -0
  267. package/templates/commands/test.md +133 -0
  268. package/templates/hooks/commit-msg +8 -0
  269. package/templates/lanes/analyze.yaml +25 -0
  270. package/templates/lanes/build.yaml +45 -0
  271. package/templates/lanes/deploy.yaml +24 -0
  272. package/templates/lanes/learn.yaml +20 -0
  273. package/templates/lanes/market.yaml +25 -0
  274. package/templates/lanes/plan.yaml +24 -0
  275. package/templates/lanes/scan.yaml +11 -0
  276. package/templates/lanes/triage.yaml +24 -0
  277. package/templates/mock/template.html +82 -0
  278. package/templates/seeds/go-gotchas.md +28 -0
  279. package/templates/seeds/go-patterns.md +22 -0
  280. package/templates/seeds/node-typescript-gotchas.md +30 -0
  281. package/templates/seeds/node-typescript-patterns.md +27 -0
  282. package/templates/seeds/python-gotchas.md +30 -0
  283. package/templates/seeds/python-patterns.md +19 -0
  284. package/templates/seeds/universal-gotchas.md +11 -0
  285. package/templates/seeds/universal-patterns.md +11 -0
  286. package/templates/spec/plan.md +7 -0
  287. package/templates/spec/research.md +19 -0
  288. package/templates/spec/spec.md +14 -0
  289. package/templates/spec/tasks.md +10 -0
  290. package/templates/tasks/todo.md +3 -0
@@ -0,0 +1,82 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <!-- codeloop-mock-template: 1 -->
7
+ <title>{{id}} {{title}}</title>
8
+ <style>
9
+ /* codeloop-tokens:start */
10
+ :root {
11
+ --bg: #f6f7f9;
12
+ --surface: #ffffff;
13
+ --text: #1a1d21;
14
+ --muted: #5f6b7a;
15
+ --border: #d9dee5;
16
+ --accent: #2f5fd0;
17
+ --accent-text: #ffffff;
18
+ --ok: #1f7a4d;
19
+ --warn: #a15c00;
20
+ --danger: #b3261e;
21
+ --radius: 0.5rem;
22
+ --space-1: 0.25rem;
23
+ --space-2: 0.5rem;
24
+ --space-3: 1rem;
25
+ --space-4: 1.5rem;
26
+ --line: 0.0625rem;
27
+ }
28
+ @media (prefers-color-scheme: dark) {
29
+ :root {
30
+ --bg: #111418;
31
+ --surface: #1a1f26;
32
+ --text: #e8ebef;
33
+ --muted: #9aa5b4;
34
+ --border: #2c343f;
35
+ --accent: #7ea2f5;
36
+ --accent-text: #0d1117;
37
+ --ok: #5fcf96;
38
+ --warn: #f0b860;
39
+ --danger: #f28b82;
40
+ }
41
+ }
42
+ /* codeloop-tokens:end */
43
+ * { box-sizing: border-box; }
44
+ body { margin: 0; font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; line-height: 1.5; background: var(--bg); color: var(--text); }
45
+ .shell { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-4); max-width: 72rem; margin: 0 auto; padding: var(--space-4); }
46
+ .bar { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-3); align-items: baseline; padding-bottom: var(--space-3); border-bottom: var(--line) solid var(--border); }
47
+ .bar h1 { margin: 0; font-size: 1.25rem; }
48
+ .bar .meta, .muted { color: var(--muted); }
49
+ .screens { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); gap: var(--space-4); align-items: start; }
50
+ section[data-screen] { display: flex; flex-direction: column; gap: var(--space-3); min-width: 0; }
51
+ section[data-screen] > h2 { margin: 0; font-size: 1rem; }
52
+ .frame { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-3); background: var(--surface); border: var(--line) solid var(--border); border-radius: var(--radius); }
53
+ .row { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
54
+ .field { display: flex; flex-direction: column; gap: var(--space-1); }
55
+ .field input, .field select { font: inherit; padding: var(--space-2); color: var(--text); background: var(--bg); border: var(--line) solid var(--border); border-radius: var(--radius); }
56
+ .button { font: inherit; padding: var(--space-2) var(--space-3); color: var(--accent-text); background: var(--accent); border: 0; border-radius: var(--radius); }
57
+ .button.quiet { color: var(--text); background: transparent; border: var(--line) solid var(--border); }
58
+ .badge { padding: 0 var(--space-2); border: var(--line) solid var(--border); border-radius: var(--radius); font-size: 0.875rem; }
59
+ .ok { color: var(--ok); }
60
+ .warn { color: var(--warn); }
61
+ .danger { color: var(--danger); }
62
+ table { width: 100%; border-collapse: collapse; }
63
+ th, td { padding: var(--space-2); text-align: left; border-bottom: var(--line) solid var(--border); }
64
+ .note { margin: 0; padding-left: var(--space-3); border-left: var(--line) solid var(--border); color: var(--muted); font-size: 0.875rem; }
65
+ </style>
66
+ </head>
67
+ <body>
68
+ <div class="shell">
69
+ <header class="bar">
70
+ <h1>{{title}}</h1>
71
+ <span class="meta">{{id}} · {{project}} · {{topic}}</span>
72
+ </header>
73
+ <main class="screens">
74
+ <!--
75
+ One <section data-screen="name"> per screen named under `screens:` in the spec.
76
+ Draw the screen inside its .frame with the classes above. Notes about a screen go in
77
+ <p class="note"> below the frame, outside it. Colours come only from the tokens: var(--accent), never a literal.
78
+ -->
79
+ </main>
80
+ </div>
81
+ </body>
82
+ </html>
@@ -0,0 +1,28 @@
1
+
2
+ ## Backend
3
+
4
+ ### Goroutine leaks [freq:1]
5
+ Goroutines that block on channels or I/O without exit conditions leak memory. Always ensure goroutines can be cancelled via `context.Context` or channel close signals.
6
+
7
+ ### Interface nil check is not what you expect [freq:1]
8
+ A typed nil pointer assigned to an `interface{}` variable is not `== nil`. The interface value has a non-nil type, so the nil check passes. Check the concrete value or use reflection.
9
+
10
+ ### Slice append can mutate shared backing array [freq:1]
11
+ `append(slice, elem)` reuses the backing array if capacity allows. Two slices from the same source can interfere with each other. Use `copy()` or full-slice expressions (`s[:len(s):len(s)]`) for safety.
12
+
13
+ ### `defer` evaluates arguments immediately [freq:1]
14
+ `defer fmt.Println(x)` captures the current value of `x`, not the value at function exit. Use a closure (`defer func() { fmt.Println(x) }()`) to capture the final value.
15
+
16
+ ### Error wrapping needs `%w` for unwrapping [freq:1]
17
+ `fmt.Errorf("failed: %v", err)` creates a new error that breaks `errors.Is()` and `errors.As()`. Use `%w` instead: `fmt.Errorf("failed: %w", err)`.
18
+
19
+ ### Forgetting to check `rows.Err()` after iteration [freq:1]
20
+ `database/sql` `rows.Next()` can stop due to an error, not just end-of-results. Always check `rows.Err()` after the loop.
21
+
22
+ ## Testing
23
+
24
+ ### Table-driven tests need subtests [freq:1]
25
+ Table-driven tests without `t.Run(name, ...)` report failures against the parent test — impossible to tell which case failed. Always use `t.Run`.
26
+
27
+ ### Race conditions in tests [freq:1]
28
+ Tests that spawn goroutines without `-race` detection pass locally but fail in CI. Always run `go test -race ./...` in CI.
@@ -0,0 +1,22 @@
1
+
2
+ ## Backend
3
+
4
+ ### Accept interfaces, return structs [confidence:HIGH]
5
+ Function parameters should accept interfaces for flexibility. Return concrete types so callers know exactly what they get. This maximizes testability and minimizes coupling.
6
+
7
+ ### Errors are values, handle them immediately [confidence:HIGH]
8
+ Check errors on the line after the call. Don't defer error handling or collect errors for later. Each error gets handled where it occurs.
9
+
10
+ ### Context propagation through the call chain [confidence:HIGH]
11
+ Pass `context.Context` as the first parameter through every function that does I/O or could be cancelled. Never store contexts in structs.
12
+
13
+ ### Functional options for configuration [confidence:MEDIUM]
14
+ Use `WithTimeout(5*time.Second)` style option functions instead of large config structs. Extensible without breaking existing callers.
15
+
16
+ ## Testing
17
+
18
+ ### Table-driven tests with subtests [confidence:HIGH]
19
+ Define test cases as a slice of structs. Run each with `t.Run(name, func(t *testing.T) {...})`. Clear, extensible, easy to add new cases.
20
+
21
+ ### Test helpers return errors, don't t.Fatal [confidence:MEDIUM]
22
+ Helper functions return errors so the caller decides how to handle them. Only call `t.Fatal` at the test level, not in helpers — it makes helpers reusable.
@@ -0,0 +1,30 @@
1
+
2
+ ## Backend
3
+
4
+ ### Async without await silently drops errors [freq:1]
5
+ Calling an async function without `await` returns a Promise that nobody listens to. If it throws, the error is swallowed. Always `await` or explicitly handle the returned Promise.
6
+
7
+ ### `transform: true` converts missing params to NaN [freq:1]
8
+ In NestJS with `class-validator`, `@Query() n?: number` becomes `NaN` when omitted (because `Number(undefined) === NaN`). Always guard with `isNaN()` before using numeric query params.
9
+
10
+ ### `.save()` has race conditions [freq:1]
11
+ Mongoose `doc.save()` overwrites the entire document. If two processes load the same doc and save, the last write wins. Use `findByIdAndUpdate()` with `$set` for atomic field updates.
12
+
13
+ ### Import order matters with circular dependencies [freq:1]
14
+ TypeScript circular imports cause `undefined` at runtime when the execution order doesn't match expectations. Move shared types to a separate file that both modules import.
15
+
16
+ ## Frontend
17
+
18
+ ### Stale closures in React effects [freq:1]
19
+ `useEffect` closures capture variable values at render time. If a cleanup function or interval references state, it sees the stale value. Use refs or `useCallback` with proper deps.
20
+
21
+ ### `key` prop on list items must be stable [freq:1]
22
+ Using array index as `key` causes incorrect renders when items are reordered or deleted. Use a unique, stable identifier from the data.
23
+
24
+ ## Testing
25
+
26
+ ### Mock cleanup between tests [freq:1]
27
+ Mocks that aren't restored between tests leak state. Use `afterEach(() => vi.restoreAllMocks())` or `jest.restoreAllMocks()` to prevent flaky cross-test contamination.
28
+
29
+ ### Async test assertions need `await` [freq:1]
30
+ `expect(asyncFn()).rejects.toThrow()` without `await` passes even if the assertion fails — the test completes before the Promise resolves. Always `await expect(...)`.
@@ -0,0 +1,27 @@
1
+
2
+ ## Backend
3
+
4
+ ### DTOs at API boundaries [confidence:HIGH]
5
+ Never pass raw database objects to API responses. Use DTOs (Data Transfer Objects) to control exactly which fields are exposed. Prevents accidental data leaks and decouples internal schema from public API.
6
+
7
+ ### Dependency injection over direct imports [confidence:HIGH]
8
+ Import the interface, inject the implementation. Makes testing trivial (swap with mocks) and keeps modules loosely coupled.
9
+
10
+ ### Index files for module exports [confidence:MEDIUM]
11
+ Each module directory has an `index.ts` that re-exports its public API. Internal files stay private. Consumers import from the directory, not deep paths.
12
+
13
+ ## Frontend
14
+
15
+ ### Server components by default [confidence:MEDIUM]
16
+ Start with server components. Only add `'use client'` when you need interactivity (event handlers, state, effects). This keeps bundle size small and data fetching simple.
17
+
18
+ ### Colocate state with its consumer [confidence:HIGH]
19
+ State lives in the closest common parent of the components that need it. Don't hoist to a global store unless multiple unrelated features need the same data.
20
+
21
+ ## Testing
22
+
23
+ ### Test behavior, not implementation [confidence:HIGH]
24
+ Tests should verify what the code does, not how it does it. Avoid asserting on internal method calls or implementation details — they break on refactors without catching real bugs.
25
+
26
+ ### Arrange-Act-Assert structure [confidence:HIGH]
27
+ Every test has three clear sections: set up the data (Arrange), perform the action (Act), check the result (Assert). Keeps tests readable and focused.
@@ -0,0 +1,30 @@
1
+
2
+ ## Backend
3
+
4
+ ### Mutable default arguments are shared [freq:1]
5
+ `def foo(items=[])` — the default list is created once and shared across all calls. Mutations persist between invocations. Use `items=None` and create inside the function.
6
+
7
+ ### `is` vs `==` for comparisons [freq:1]
8
+ `is` checks identity (same object in memory), `==` checks equality (same value). Use `is` only for `None`, `True`, `False`. For everything else, use `==`.
9
+
10
+ ### Silent exception swallowing [freq:1]
11
+ Bare `except:` or `except Exception:` with just `pass` hides real bugs. Always log the exception or re-raise. If you must catch broadly, at least log at warning level.
12
+
13
+ ### Circular imports cause ImportError at runtime [freq:1]
14
+ Two modules importing each other works in some cases but fails unpredictably depending on import order. Move shared types/interfaces to a third module.
15
+
16
+ ### `datetime.now()` uses local timezone [freq:1]
17
+ `datetime.now()` returns naive local time. For servers, always use `datetime.now(timezone.utc)` or `datetime.utcnow()` to avoid timezone confusion.
18
+
19
+ ## Database
20
+
21
+ ### SQLAlchemy session not committed [freq:1]
22
+ Forgetting `session.commit()` after inserts/updates — changes exist in memory but never reach the database. Use context managers or explicit commit calls.
23
+
24
+ ## Testing
25
+
26
+ ### Fixtures that share mutable state [freq:1]
27
+ `@pytest.fixture(scope="module")` with mutable objects (dicts, lists) causes test pollution. Use `scope="function"` (default) for isolation, or return fresh copies.
28
+
29
+ ### Async test functions need pytest-asyncio [freq:1]
30
+ `async def test_something()` silently passes without actually running unless `pytest-asyncio` is installed and `@pytest.mark.asyncio` is applied.
@@ -0,0 +1,19 @@
1
+
2
+ ## Backend
3
+
4
+ ### Pydantic models at API boundaries [confidence:HIGH]
5
+ Use Pydantic `BaseModel` for request/response validation. Never pass raw dicts through API layers — models enforce schema, generate docs, and catch invalid data early.
6
+
7
+ ### Context managers for resource cleanup [confidence:HIGH]
8
+ Database connections, file handles, temporary directories — use `with` statements to guarantee cleanup. Prevents resource leaks on exceptions.
9
+
10
+ ### Type hints everywhere [confidence:MEDIUM]
11
+ All function signatures have type hints. Use `mypy` or `pyright` in CI. Catches bugs at static analysis time instead of runtime.
12
+
13
+ ## Testing
14
+
15
+ ### Factories over fixtures for test data [confidence:MEDIUM]
16
+ Use factory functions (or `factory_boy`) to create test data with sensible defaults. Override only the fields relevant to each test. More readable than complex fixture chains.
17
+
18
+ ### Test behavior, not implementation [confidence:HIGH]
19
+ Verify what the function returns or what side effects occur — not which internal methods were called. Implementation-coupled tests break on every refactor.
@@ -0,0 +1,11 @@
1
+
2
+ ## General
3
+
4
+ ### Never commit secrets [freq:1]
5
+ API keys, tokens, passwords in code or config files. Use environment variables or a secrets manager. Even if you "remove it later," git history is forever.
6
+
7
+ ### Merge conflicts need manual review [freq:1]
8
+ Auto-resolved merge conflicts (especially in lock files, generated code, or schema files) can silently break things. Always verify the merged result compiles and tests pass.
9
+
10
+ ### File permissions in git [freq:1]
11
+ Accidentally committing executable bits (`chmod +x`) on files that don't need it. Check `git diff --stat` for mode changes before committing.
@@ -0,0 +1,11 @@
1
+
2
+ ## General
3
+
4
+ ### Error-first control flow [confidence:HIGH]
5
+ Check error conditions and return/throw early. Keep the happy path at the lowest indentation level. Reduces nesting, improves readability.
6
+
7
+ ### One logical change per commit [confidence:HIGH]
8
+ Each commit should be a single, reviewable unit. Mixing refactors with features makes review harder and reverts riskier.
9
+
10
+ ### Config in version control [confidence:HIGH]
11
+ All configuration (except secrets) lives in the repo. If a new developer can't `git clone && make dev` and have a working setup, something is missing.
@@ -0,0 +1,7 @@
1
+ # {{id}} plan: {{title}}
2
+
3
+ ## Layers touched
4
+
5
+ ## Files
6
+
7
+ ## Risks
@@ -0,0 +1,19 @@
1
+ # {{id}} research: {{title}}
2
+
3
+ ## What exists
4
+
5
+ ## How others show it
6
+
7
+ <!-- One row per competitor that has a page in .codeloop/wiki/competitors/, its name in the first cell. The row is copied to that page when this stage passes. -->
8
+ | Competitor | How they show it | Source |
9
+ |---|---|---|
10
+
11
+ ## Options
12
+
13
+ ## Risks
14
+
15
+ ## Sources
16
+
17
+ <!-- At least three, one per line: a dash, the word source and a colon, the URL, a dash, a note. `codeloop check research` counts them. -->
18
+
19
+ <!-- End with one line that starts with the word verdict and a colon, then build, buy or drop. The stage check looks for it. -->
@@ -0,0 +1,14 @@
1
+ # {{id}} spec: {{title}}
2
+
3
+ Story: as a <who> I can <what>, so that <why>.
4
+
5
+ <!-- One line per acceptance criterion, numbered US1..US5. More than five means the card is too big: split it. -->
6
+ acceptance:
7
+ - US1 Given <state>, when <action>, then <result>.
8
+
9
+ <!-- One name per screen the mock draws; `codeloop check mock` wants a <section data-screen="name"> for each. A card with nothing to draw says `screens: none`. -->
10
+ screens:
11
+
12
+ ## Failure modes
13
+
14
+ <!-- The ways this can break in production. One use case per item. -->
@@ -0,0 +1,10 @@
1
+ # {{id}} tasks: {{title}}
2
+
3
+ <!--
4
+ One line per task, each owned by one layer and tied to an acceptance line:
5
+
6
+ - [ ] T001 [P] [US1] [api] What to do, naming the file
7
+
8
+ Layer is one of api, sdk, ui, test, docs. [P] marks a task that can run in parallel.
9
+ `codeloop spec check` fails on a task with no layer tag and on an acceptance line with no task.
10
+ -->
@@ -0,0 +1,3 @@
1
+ # Tasks
2
+
3
+ <!-- Current task plan. Updated by /plan and /manage. -->