luca 3.0.0 → 3.0.2

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 (372) hide show
  1. package/.github/workflows/release.yaml +1 -0
  2. package/CLAUDE.md +10 -2
  3. package/README.md +130 -112
  4. package/assistants/codingAssistant/CORE.md +6 -1
  5. package/assistants/codingAssistant/hooks.ts +1 -1
  6. package/assistants/inkbot/hooks.ts +1 -1
  7. package/assistants/inkbot/tools.ts +1 -1
  8. package/bun.lock +220 -322
  9. package/commands/audit-docs.ts +2 -2
  10. package/commands/build-bootstrap.ts +2 -3
  11. package/commands/build-python-bridge.ts +2 -3
  12. package/commands/build-scaffolds.ts +2 -3
  13. package/commands/bundle-consumer-project.ts +521 -0
  14. package/commands/generate-api-docs.ts +2 -2
  15. package/commands/inkbot.ts +2 -2
  16. package/commands/release.ts +2 -2
  17. package/commands/try-all-challenges.ts +3 -3
  18. package/commands/try-challenge.ts +3 -3
  19. package/dist/agi/container.server.d.ts +2 -2
  20. package/dist/agi/features/assistant.d.ts +2 -2
  21. package/dist/agi/features/assistants-manager.d.ts +1 -1
  22. package/dist/agi/features/autonomous-assistant.d.ts +1 -1
  23. package/dist/agi/features/browser-use.d.ts +1 -1
  24. package/dist/agi/features/claude-code.d.ts +1 -1
  25. package/dist/agi/features/conversation-history.d.ts +2 -2
  26. package/dist/agi/features/conversation.d.ts +1 -1
  27. package/dist/agi/features/docs-reader.d.ts +1 -1
  28. package/dist/agi/features/file-tools.d.ts +1 -1
  29. package/dist/agi/features/luca-coder.d.ts +1 -1
  30. package/dist/agi/features/openai-codex.d.ts +1 -1
  31. package/dist/agi/features/skills-library.d.ts +1 -1
  32. package/dist/clients/civitai/index.d.ts +4 -4
  33. package/dist/clients/client-template.d.ts +4 -4
  34. package/dist/clients/comfyui/index.d.ts +2 -2
  35. package/dist/clients/elevenlabs/index.d.ts +2 -2
  36. package/dist/clients/openai/index.d.ts +2 -2
  37. package/dist/clients/supabase/index.d.ts +3 -3
  38. package/dist/command.d.ts +1 -1
  39. package/dist/node/container.d.ts +1 -1
  40. package/dist/node/features/helpers.d.ts +3 -3
  41. package/dist/node/features/semantic-search.d.ts +1 -1
  42. package/dist/node/features/vm.d.ts +3 -3
  43. package/dist/node.d.ts +1 -1
  44. package/dist/scaffolds/generated.d.ts +1 -1
  45. package/dist/selector.d.ts +1 -1
  46. package/index.html +217 -190
  47. package/luca.console.ts +1 -1
  48. package/package.json +2 -2
  49. package/public/index.html +217 -190
  50. package/public/slides-ai-native.html +1 -1
  51. package/public/slides-intro.html +2 -2
  52. package/scripts/examples/ask-luca-expert.ts +1 -1
  53. package/scripts/examples/assistant-questions.ts +1 -1
  54. package/scripts/examples/excalidraw-expert.ts +1 -1
  55. package/scripts/examples/file-manager.ts +1 -1
  56. package/scripts/examples/ideas.ts +1 -1
  57. package/scripts/examples/interactive-chat.ts +1 -1
  58. package/scripts/examples/opening-a-web-browser.ts +1 -1
  59. package/scripts/examples/telegram-bot.ts +1 -1
  60. package/scripts/examples/using-assistant-with-mcp.ts +1 -1
  61. package/scripts/examples/using-claude-code.ts +1 -1
  62. package/scripts/examples/using-contentdb.ts +2 -2
  63. package/scripts/examples/using-conversations.ts +1 -1
  64. package/scripts/examples/using-disk-cache.ts +1 -1
  65. package/scripts/examples/using-docker-shell.ts +1 -1
  66. package/scripts/examples/using-elevenlabs.ts +1 -1
  67. package/scripts/examples/using-google-calendar.ts +1 -1
  68. package/scripts/examples/using-google-docs.ts +1 -1
  69. package/scripts/examples/using-google-drive.ts +1 -1
  70. package/scripts/examples/using-google-sheets.ts +1 -1
  71. package/scripts/examples/using-nlp.ts +1 -1
  72. package/scripts/examples/using-ollama.ts +1 -1
  73. package/scripts/examples/using-postgres.ts +1 -1
  74. package/scripts/examples/using-runpod.ts +1 -1
  75. package/scripts/examples/using-tts.ts +1 -1
  76. package/scripts/scaffold.ts +5 -5
  77. package/scripts/scratch.ts +1 -1
  78. package/scripts/test-assistant-hooks.ts +1 -1
  79. package/scripts/test-docs-reader.ts +1 -1
  80. package/src/agi/container.server.ts +6 -2
  81. package/src/agi/features/agent-memory.ts +25 -25
  82. package/src/agi/features/assistant.ts +34 -5
  83. package/src/agi/features/assistants-manager.ts +122 -6
  84. package/src/agi/features/autonomous-assistant.ts +1 -1
  85. package/src/agi/features/browser-use.ts +20 -1
  86. package/src/agi/features/claude-code.ts +51 -5
  87. package/src/agi/features/coding-tools.ts +1 -1
  88. package/src/agi/features/conversation-history.ts +181 -4
  89. package/src/agi/features/conversation.ts +186 -15
  90. package/src/agi/features/docs-reader.ts +2 -2
  91. package/src/agi/features/file-tools.ts +49 -2
  92. package/src/agi/features/luca-coder.ts +7 -5
  93. package/src/agi/features/mcp-bridge.ts +532 -0
  94. package/src/agi/features/openai-codex.ts +2 -2
  95. package/src/agi/features/skills-library.ts +131 -52
  96. package/src/agi/lib/token-counter.ts +80 -0
  97. package/src/bootstrap/generated.ts +56 -57
  98. package/src/browser.ts +1 -1
  99. package/src/cli/build-info.ts +2 -2
  100. package/src/cli/cli.ts +2 -2
  101. package/src/clients/civitai/index.ts +5 -5
  102. package/src/clients/client-template.ts +4 -4
  103. package/src/clients/comfyui/index.ts +4 -4
  104. package/src/clients/elevenlabs/index.ts +4 -4
  105. package/src/clients/openai/index.ts +7 -7
  106. package/src/clients/supabase/index.ts +4 -4
  107. package/src/clients/voicebox/index.ts +4 -4
  108. package/src/command.ts +2 -1
  109. package/src/commands/chat.ts +1 -0
  110. package/src/commands/eval.ts +2 -56
  111. package/src/commands/introspect.ts +1 -1
  112. package/src/commands/prompt.ts +41 -9
  113. package/src/container-describer.ts +8 -1
  114. package/src/container.ts +13 -0
  115. package/src/entity.ts +2 -2
  116. package/src/helper.ts +1 -1
  117. package/src/introspection/generated.agi.ts +28563 -27571
  118. package/src/introspection/generated.node.ts +20281 -20194
  119. package/src/introspection/generated.web.ts +605 -584
  120. package/src/introspection/scan.ts +11 -6
  121. package/src/node/container.ts +1 -1
  122. package/src/node/features/content-db.ts +39 -2
  123. package/src/node/features/display-result.ts +57 -0
  124. package/src/node/features/helpers.ts +42 -15
  125. package/src/node/features/python.ts +25 -19
  126. package/src/node/features/repl.ts +1 -1
  127. package/src/node/features/secure-shell.ts +11 -17
  128. package/src/node/features/semantic-search.ts +2 -2
  129. package/src/node/features/transpiler.ts +2 -3
  130. package/src/node/features/ui.ts +5 -0
  131. package/src/node/features/vm.ts +3 -3
  132. package/src/node.ts +3 -3
  133. package/src/python/generated.ts +0 -1
  134. package/src/scaffolds/generated.ts +82 -83
  135. package/src/selector.ts +1 -1
  136. package/src/servers/express.ts +1 -1
  137. package/src/web/features/helpers.ts +22 -0
  138. package/tsconfig.json +12 -12
  139. package/docs/CLI.md +0 -335
  140. package/docs/CNAME +0 -1
  141. package/docs/README.md +0 -60
  142. package/docs/TABLE-OF-CONTENTS.md +0 -183
  143. package/docs/apis/clients/elevenlabs.md +0 -308
  144. package/docs/apis/clients/graph.md +0 -107
  145. package/docs/apis/clients/openai.md +0 -429
  146. package/docs/apis/clients/rest.md +0 -161
  147. package/docs/apis/clients/websocket.md +0 -174
  148. package/docs/apis/features/agi/assistant.md +0 -625
  149. package/docs/apis/features/agi/assistants-manager.md +0 -282
  150. package/docs/apis/features/agi/auto-assistant.md +0 -279
  151. package/docs/apis/features/agi/browser-use.md +0 -802
  152. package/docs/apis/features/agi/claude-code.md +0 -884
  153. package/docs/apis/features/agi/conversation-history.md +0 -364
  154. package/docs/apis/features/agi/conversation.md +0 -548
  155. package/docs/apis/features/agi/docs-reader.md +0 -99
  156. package/docs/apis/features/agi/file-tools.md +0 -163
  157. package/docs/apis/features/agi/luca-coder.md +0 -407
  158. package/docs/apis/features/agi/openai-codex.md +0 -396
  159. package/docs/apis/features/agi/openapi.md +0 -138
  160. package/docs/apis/features/agi/semantic-search.md +0 -387
  161. package/docs/apis/features/agi/skills-library.md +0 -239
  162. package/docs/apis/features/node/container-link.md +0 -192
  163. package/docs/apis/features/node/content-db.md +0 -450
  164. package/docs/apis/features/node/disk-cache.md +0 -379
  165. package/docs/apis/features/node/dns.md +0 -652
  166. package/docs/apis/features/node/docker.md +0 -706
  167. package/docs/apis/features/node/downloader.md +0 -81
  168. package/docs/apis/features/node/esbuild.md +0 -60
  169. package/docs/apis/features/node/file-manager.md +0 -191
  170. package/docs/apis/features/node/fs.md +0 -1217
  171. package/docs/apis/features/node/git.md +0 -371
  172. package/docs/apis/features/node/google-auth.md +0 -193
  173. package/docs/apis/features/node/google-calendar.md +0 -202
  174. package/docs/apis/features/node/google-docs.md +0 -173
  175. package/docs/apis/features/node/google-drive.md +0 -246
  176. package/docs/apis/features/node/google-mail.md +0 -214
  177. package/docs/apis/features/node/google-sheets.md +0 -194
  178. package/docs/apis/features/node/grep.md +0 -292
  179. package/docs/apis/features/node/helpers.md +0 -164
  180. package/docs/apis/features/node/ink.md +0 -334
  181. package/docs/apis/features/node/ipc-socket.md +0 -249
  182. package/docs/apis/features/node/json-tree.md +0 -86
  183. package/docs/apis/features/node/networking.md +0 -316
  184. package/docs/apis/features/node/nlp.md +0 -133
  185. package/docs/apis/features/node/opener.md +0 -97
  186. package/docs/apis/features/node/os.md +0 -146
  187. package/docs/apis/features/node/package-finder.md +0 -392
  188. package/docs/apis/features/node/postgres.md +0 -234
  189. package/docs/apis/features/node/proc.md +0 -399
  190. package/docs/apis/features/node/process-manager.md +0 -305
  191. package/docs/apis/features/node/python.md +0 -604
  192. package/docs/apis/features/node/redis.md +0 -380
  193. package/docs/apis/features/node/repl.md +0 -88
  194. package/docs/apis/features/node/runpod.md +0 -674
  195. package/docs/apis/features/node/secure-shell.md +0 -176
  196. package/docs/apis/features/node/semantic-search.md +0 -408
  197. package/docs/apis/features/node/sqlite.md +0 -233
  198. package/docs/apis/features/node/telegram.md +0 -279
  199. package/docs/apis/features/node/transpiler.md +0 -74
  200. package/docs/apis/features/node/tts.md +0 -133
  201. package/docs/apis/features/node/ui.md +0 -701
  202. package/docs/apis/features/node/vault.md +0 -59
  203. package/docs/apis/features/node/vm.md +0 -75
  204. package/docs/apis/features/node/yaml-tree.md +0 -85
  205. package/docs/apis/features/node/yaml.md +0 -176
  206. package/docs/apis/features/web/asset-loader.md +0 -59
  207. package/docs/apis/features/web/container-link.md +0 -192
  208. package/docs/apis/features/web/esbuild.md +0 -54
  209. package/docs/apis/features/web/helpers.md +0 -164
  210. package/docs/apis/features/web/network.md +0 -44
  211. package/docs/apis/features/web/speech.md +0 -69
  212. package/docs/apis/features/web/vault.md +0 -59
  213. package/docs/apis/features/web/vm.md +0 -75
  214. package/docs/apis/features/web/voice.md +0 -84
  215. package/docs/apis/servers/express.md +0 -171
  216. package/docs/apis/servers/mcp.md +0 -238
  217. package/docs/apis/servers/websocket.md +0 -170
  218. package/docs/bootstrap/CLAUDE.md +0 -101
  219. package/docs/bootstrap/SKILL.md +0 -341
  220. package/docs/bootstrap/templates/about-command.ts +0 -41
  221. package/docs/bootstrap/templates/docs-models.ts +0 -22
  222. package/docs/bootstrap/templates/docs-readme.md +0 -43
  223. package/docs/bootstrap/templates/example-feature.ts +0 -53
  224. package/docs/bootstrap/templates/health-endpoint.ts +0 -15
  225. package/docs/bootstrap/templates/luca-cli.ts +0 -30
  226. package/docs/bootstrap/templates/runme.md +0 -54
  227. package/docs/challenges/caching-proxy.md +0 -16
  228. package/docs/challenges/content-db-round-trip.md +0 -14
  229. package/docs/challenges/custom-command.md +0 -9
  230. package/docs/challenges/file-watcher-pipeline.md +0 -11
  231. package/docs/challenges/grep-audit-report.md +0 -15
  232. package/docs/challenges/multi-feature-dashboard.md +0 -14
  233. package/docs/challenges/process-orchestrator.md +0 -17
  234. package/docs/challenges/rest-api-server-with-client.md +0 -12
  235. package/docs/challenges/script-runner-with-vm.md +0 -11
  236. package/docs/challenges/simple-rest-api.md +0 -15
  237. package/docs/challenges/websocket-serve-and-client.md +0 -11
  238. package/docs/challenges/yaml-config-system.md +0 -14
  239. package/docs/command-system-overhaul.md +0 -94
  240. package/docs/documentation-audit.md +0 -134
  241. package/docs/examples/assistant/CORE.md +0 -18
  242. package/docs/examples/assistant/hooks.ts +0 -3
  243. package/docs/examples/assistant/tools.ts +0 -10
  244. package/docs/examples/assistant-hooks-reference.ts +0 -171
  245. package/docs/examples/assistant-with-process-manager.md +0 -84
  246. package/docs/examples/content-db.md +0 -77
  247. package/docs/examples/disk-cache.md +0 -83
  248. package/docs/examples/docker.md +0 -101
  249. package/docs/examples/downloader.md +0 -70
  250. package/docs/examples/entity.md +0 -124
  251. package/docs/examples/esbuild.md +0 -80
  252. package/docs/examples/feature-as-tool-provider.md +0 -143
  253. package/docs/examples/file-manager.md +0 -82
  254. package/docs/examples/fs.md +0 -83
  255. package/docs/examples/git.md +0 -85
  256. package/docs/examples/google-auth.md +0 -88
  257. package/docs/examples/google-calendar.md +0 -94
  258. package/docs/examples/google-docs.md +0 -82
  259. package/docs/examples/google-drive.md +0 -96
  260. package/docs/examples/google-sheets.md +0 -95
  261. package/docs/examples/grep.md +0 -85
  262. package/docs/examples/ink-blocks.md +0 -75
  263. package/docs/examples/ink-renderer.md +0 -41
  264. package/docs/examples/ink.md +0 -103
  265. package/docs/examples/ipc-socket.md +0 -103
  266. package/docs/examples/json-tree.md +0 -91
  267. package/docs/examples/networking.md +0 -58
  268. package/docs/examples/nlp.md +0 -91
  269. package/docs/examples/opener.md +0 -78
  270. package/docs/examples/os.md +0 -72
  271. package/docs/examples/package-finder.md +0 -89
  272. package/docs/examples/postgres.md +0 -91
  273. package/docs/examples/proc.md +0 -81
  274. package/docs/examples/process-manager.md +0 -79
  275. package/docs/examples/python.md +0 -132
  276. package/docs/examples/repl.md +0 -93
  277. package/docs/examples/runpod.md +0 -119
  278. package/docs/examples/secure-shell.md +0 -92
  279. package/docs/examples/sqlite.md +0 -86
  280. package/docs/examples/structured-output-with-assistants.md +0 -144
  281. package/docs/examples/telegram.md +0 -77
  282. package/docs/examples/tts.md +0 -86
  283. package/docs/examples/ui.md +0 -80
  284. package/docs/examples/vault.md +0 -70
  285. package/docs/examples/vm.md +0 -86
  286. package/docs/examples/websocket-ask-and-reply-example.md +0 -128
  287. package/docs/examples/yaml-tree.md +0 -93
  288. package/docs/examples/yaml.md +0 -104
  289. package/docs/ideas/assistant-factory-pattern.md +0 -142
  290. package/docs/in-memory-fs.md +0 -4
  291. package/docs/introspection-audit.md +0 -49
  292. package/docs/introspection.md +0 -164
  293. package/docs/mcp/readme.md +0 -162
  294. package/docs/models.ts +0 -41
  295. package/docs/philosophy.md +0 -86
  296. package/docs/principles.md +0 -7
  297. package/docs/prompts/audit-codebase-for-failures-to-use-the-container.md +0 -34
  298. package/docs/prompts/check-for-undocumented-features.md +0 -27
  299. package/docs/prompts/mcp-test-easy-command.md +0 -27
  300. package/docs/scaffolds/client.md +0 -149
  301. package/docs/scaffolds/command.md +0 -120
  302. package/docs/scaffolds/endpoint.md +0 -171
  303. package/docs/scaffolds/feature.md +0 -158
  304. package/docs/scaffolds/selector.md +0 -91
  305. package/docs/scaffolds/server.md +0 -196
  306. package/docs/selectors.md +0 -115
  307. package/docs/sessions/custom-command/attempt-log-2.md +0 -195
  308. package/docs/sessions/file-watcher-pipeline/attempt-log-1.md +0 -728
  309. package/docs/sessions/file-watcher-pipeline/attempt-log-2.md +0 -555
  310. package/docs/sessions/grep-audit-report/attempt-log-1.md +0 -289
  311. package/docs/sessions/multi-feature-dashboard/attempt-log-2.md +0 -679
  312. package/docs/sessions/rest-api-server-with-client/attempt-log-1.md +0 -1
  313. package/docs/sessions/rest-api-server-with-client/attempt-log-3.md +0 -920
  314. package/docs/sessions/simple-rest-api/attempt-log-1.md +0 -593
  315. package/docs/sessions/websocket-serve-and-client/attempt-log-2.md +0 -995
  316. package/docs/tutorials/00-bootstrap.md +0 -166
  317. package/docs/tutorials/01-getting-started.md +0 -106
  318. package/docs/tutorials/02-container.md +0 -210
  319. package/docs/tutorials/03-scripts.md +0 -194
  320. package/docs/tutorials/04-features-overview.md +0 -196
  321. package/docs/tutorials/05-state-and-events.md +0 -171
  322. package/docs/tutorials/06-servers.md +0 -157
  323. package/docs/tutorials/07-endpoints.md +0 -198
  324. package/docs/tutorials/08-commands.md +0 -252
  325. package/docs/tutorials/09-clients.md +0 -162
  326. package/docs/tutorials/10-creating-features.md +0 -203
  327. package/docs/tutorials/11-contentbase.md +0 -191
  328. package/docs/tutorials/12-assistants.md +0 -215
  329. package/docs/tutorials/13-introspection.md +0 -157
  330. package/docs/tutorials/14-type-system.md +0 -174
  331. package/docs/tutorials/15-project-patterns.md +0 -222
  332. package/docs/tutorials/16-google-features.md +0 -534
  333. package/docs/tutorials/17-tui-blocks.md +0 -530
  334. package/docs/tutorials/18-semantic-search.md +0 -334
  335. package/docs/tutorials/19-python-sessions.md +0 -401
  336. package/docs/tutorials/20-browser-esm.md +0 -234
  337. package/src/agi/endpoints/ask.ts +0 -60
  338. package/src/agi/endpoints/conversations/[id].ts +0 -45
  339. package/src/agi/endpoints/conversations.ts +0 -31
  340. package/src/agi/endpoints/experts.ts +0 -37
  341. package/test/assistant-hooks.test.ts +0 -306
  342. package/test/assistant.test.ts +0 -81
  343. package/test/bus.test.ts +0 -134
  344. package/test/clients-servers.test.ts +0 -217
  345. package/test/command.test.ts +0 -267
  346. package/test/container-link.test.ts +0 -274
  347. package/test/conversation.test.ts +0 -220
  348. package/test/features.test.ts +0 -160
  349. package/test/fork-and-research.test.ts +0 -450
  350. package/test/integration.test.ts +0 -787
  351. package/test/interceptor-chain.test.ts +0 -61
  352. package/test/node-container.test.ts +0 -121
  353. package/test/python-session.test.ts +0 -105
  354. package/test/rate-limit.test.ts +0 -272
  355. package/test/semantic-search.test.ts +0 -550
  356. package/test/state.test.ts +0 -121
  357. package/test/vm-context.test.ts +0 -146
  358. package/test/vm-loadmodule.test.ts +0 -213
  359. package/test/websocket-ask.test.ts +0 -101
  360. package/test-integration/assistant.test.ts +0 -138
  361. package/test-integration/assistants-manager.test.ts +0 -113
  362. package/test-integration/claude-code.test.ts +0 -98
  363. package/test-integration/conversation-history.test.ts +0 -205
  364. package/test-integration/conversation.test.ts +0 -137
  365. package/test-integration/elevenlabs.test.ts +0 -55
  366. package/test-integration/google-services.test.ts +0 -80
  367. package/test-integration/helpers.ts +0 -89
  368. package/test-integration/memory.test.ts +0 -204
  369. package/test-integration/openai-codex.test.ts +0 -93
  370. package/test-integration/runpod.test.ts +0 -58
  371. package/test-integration/server-endpoints.test.ts +0 -97
  372. package/test-integration/telegram.test.ts +0 -46
@@ -1,86 +0,0 @@
1
- # Luca's Philosophy
2
-
3
- > LUCA - Lightweight Universal Conversational Architecture.
4
-
5
- If you open up a Developer console on a blank HTML page, you have the `window` object and the `document` object, and from those objects you have everything you need to build every web application you've ever interacted with, IN THEORY, without ever reloading the page.
6
-
7
- Obviously nobody builds applications this way in a single REPL, but in 2026 developers are people and Agent AIs collaborating on the same codebase in a bigger Read, Eval, Print, Loop that takes place across more computers and brains.
8
-
9
- Luca aims to provide a `container` object that gets you 60% of the way to having ANY kind of real world, production grade full stack software, before you ever write your own line of application code. As the types of applications you build and who you build them for further narrow, the container can grow to cover 95% of every boring but necessary component you need.
10
-
11
- How? By layering, the way you layer dockerfiles. The things which change least frequently are solved once and cached. The things which change more frequently live in their own isolated layer. That loop is smaller, quicker — the difference between a dockerfile that reinstalls the OS every time you change the HTML file, and one that doesn't.
12
-
13
- ## The Layer Model
14
- > Cache to the max == CA$H to the max
15
- >
16
- Think of it like docker layers:
17
-
18
- **Layer 1: Platform** — `NodeContainer`, `WebContainer`. Features that are universally applicable to any application in that runtime. Filesystem, networking, process management, event buses, observable state. You solve this once.
19
-
20
- **Layer 2: Domain** — `AGIContainer`, or imagine a `RestaurantContainer`, `FinanceContainer`. Features, clients, servers specific to that category of application. You solve this rarely.
21
-
22
- **Layer 3: The Actual Work** — The specific thing you're building for the specific person who needs it. This is what changes every day.
23
-
24
- Layer 1 and Layer 2 you solve once and almost never again. When you get to Layer 3, everything is so specific that it changes constantly. The entire point is to spend all of your energy on Layer 3. If you fix something in Layer 1, every project that uses it benefits immediately — just like every docker image based on alpine benefits when alpine patches something.
25
-
26
- The `container` is the central piece. You build it in layers with components that are stable enough to be reused across tasks, use cases, projects, and clients. And since it's JavaScript, it works in the browser or the server. Build a GitHub client in one project, add it to the container, start a brand new project with that same container, and the GitHub client is already there.
27
-
28
- ## Helpers and Registries: Conversational Dependency Injection
29
-
30
- The `container` provides `Registries` of `Helpers`. A `Helper` is a formal, consistent interface for a category of thing. Features can be enabled. Servers can be started and stopped. Clients can be connected. Commands can be run. These "things" share common lifecycles (state) and emit similar events (started, connected, enabled). Clients, servers, features are part of almost every application I've built for 20 years, but every domain has its own categories too — Helpers can be customized to represent those.
31
-
32
- `Registries` are a central place for storing the various implementations and being able to discover which ones are available.
33
-
34
- The `container` provides factory functions — `feature()`, `server()`, `client()` — to create instances. Every helper instance has its own event bus, its own observable state, can be `introspected()` at runtime, and has fully typed interfaces that light up your IDE.
35
-
36
- ## Why "Conversational"?
37
-
38
- The name means two things at once.
39
-
40
- First, you can literally talk to the container. Give an LLM access to the container object and tool calls, and it can discover what's available, learn how to use it, and build with it — all at runtime. The introspection system means nothing is hidden. Every feature, every method signature, every event, every state shape is discoverable programmatically.
41
-
42
- Second, the components talk to each other. Observable state, event buses, and well-documented typed interfaces mean that everything in the system can react to everything else through formal, predictable channels. Not magic strings and implicit coupling — actual typed contracts with build-time autocomplete and runtime introspection of the same.
43
-
44
- ## A Shared Mental Model
45
-
46
- This is the real thesis.
47
-
48
- The human and the AI share the same mental model of how the code should be organized and structured. The human isn't just directing the AI — they're collaborating inside the same architecture, speaking the same language about the same things.
49
-
50
- A human defines the Helper — the interface, the lifecycle, the state shape, the events it emits. They decide *what* a thing is, *how* it behaves from the outside, and *where* it lives in the system. The AI understands that same structure and works within it. When the human says "make a client for Stripe," the AI already knows what a Client is, where it goes, what interface it needs to satisfy, and what lifecycle it follows. They're not negotiating from scratch every time — they're both operating from the same map.
51
-
52
- This matters because as AI builds more and more of the internals, the human still feels at home. The organization of the code is still theirs. The names are theirs. The architecture is theirs. The folder structure, the class hierarchy, the way things relate to each other — that's their map, and the AI respects it because the AI shares it.
53
-
54
- Defining Helpers is how a human says "in my world, these are the categories of things that exist, and this is how they work." The AI doesn't need to understand *why* those categories make sense for the business or the domain — it just needs the interface contract and it can implement anything that satisfies it.
55
-
56
- ## Trust Through Composition
57
-
58
- Here's where it gets really interesting.
59
-
60
- Because everything is captured as Helpers with formal interfaces, every component can be reviewed, audited, and secured independently. You can track provenance — who wrote it, when, what it depends on. A Helper that's been vetted is a Helper you can trust.
61
-
62
- Over time, the AI generates less and less net-new code. Instead, it composes with existing Helpers — calling their interfaces, subscribing to their events, reading their state. The new code it does write gets captured into new Helpers that go through the same review cycle. The codebase becomes a growing library of trusted, audited building blocks.
63
-
64
- This flips the usual fear about AI-generated code on its head. Normally, the more an AI writes, the less confident you feel about what's in there. With Luca, the more an AI writes, the more it's using components you've already reviewed. The codebase gets *more* trustworthy as it grows, not less. The surface area of unreviewed code shrinks because the AI is reaching for existing Helpers instead of generating raw implementations from scratch every time.
65
-
66
- This also constrains the AI in a productive way. Instead of generating sprawling, unstructured code that the human has to reverse-engineer, the AI is given a clear place to put things and a clear shape they need to be. The result is a codebase that grows but stays navigable, because the human designed the map and the AI respects it.
67
-
68
- ## The Agent Runtime
69
-
70
- Take this one step further.
71
-
72
- Imagine an Agent that already knows JavaScript like a master. Give it a `container` object. Through introspection alone, it can learn about every feature, server, client, and command available to it. It can discover their options, their observable state, the events they emit, and the signatures for all of these things. It can write code against them. It can modify itself at runtime. You can watch the thing being built, interact with it, steer it.
73
-
74
- This is not theoretical. The AGI container layer already does this — it wraps tools like Claude Code and OpenAI into the same Helper pattern, gives them the same observable state and event buses, and lets agents use the full container to build and extend themselves.
75
-
76
- The REPL-driven development style that Luca was originally designed for maps perfectly onto this. The same properties that make something nice to work with in a REPL — discoverability, introspection, observable state, immediate feedback — are exactly the properties that make something nice for an AI agent to work with.
77
-
78
- ## Why This Architecture Specifically?
79
-
80
- Observable state, events, and well-documented APIs aren't arbitrary choices. They're specifically what makes things *conversational* in both senses:
81
-
82
- - **Observable state** means anything can watch anything else and react. Debugging, analytics, reporting, reactive UI patterns, data providers for React — all fall out naturally. An AI agent can monitor state to understand what's happening.
83
- - **Events** are the necessary primitive for JavaScript's async event loop, and they're also how components announce things to the rest of the system without needing to know who's listening. An AI agent can subscribe to events to understand what just happened.
84
- - **Introspection** means you never have to remember the specifics. You only need to know the philosophy, and the container will teach you the rest. This is true whether "you" is a human in a REPL or an AI agent with tool access.
85
-
86
- The fact that you can start from a single `container` object and learn everything it provides — how to interact with it, how to use it, what to expect from it — means the philosophy *is* the documentation. Know the pattern, and the system reveals itself.
@@ -1,7 +0,0 @@
1
- # Random Principles
2
-
3
- - I've built so many different client / server applications with JavaScript ( and many other languages ). I've reinvented way too many things that could have been solved once. The clearest example of this pain is a poorly structured dockerfile, e.g. one that reinstalls core os dependencies when you change an html file.
4
-
5
- - Nearly every application, I've structured as a "boss with liuetenants" so to speak, that everything else talked to. The boss, the liuetenants, had some kind of state. Events occur during their operations. Sometimes these events need to be triggered. Overtime, core patterns emerged, somewhat encouraged by popular frameworks in the shape they took or names I gave them.
6
-
7
- - In building Luca, we want to provide ways to ultimately narrow the range of possible outputs a first time developer, or AI assistant, might produce when asked to build something using a Luca `container` and its components. The names themselves of the helpers, `clients`, `servers`, `features` already begin to describe their shape, purpose, where their code should live, etc. By going through the extra effort of building essentially a wrapper class, with descriptive interfaces, the developer will ultimately be delivering code that is easier to work with, and re-use in future efforts.
@@ -1,34 +0,0 @@
1
- ---
2
- reusable: true
3
- lastRanAt: 1772162827313
4
- durationMs: 278913
5
- outputTokens: 552
6
- ---
7
-
8
-
9
- # Code Audit
10
-
11
- Do an audit of the code in the following folders:
12
-
13
- - src/**/features/**
14
- - src/**/clients/**
15
- - src/clients/**
16
- - src/servers/**
17
- - src/commands/**
18
-
19
- Ignore the fs, proc, git features in src/node/features. These are a core abstraction that wraps the underlying ones provided by node or bun, so it is expected they would use child_process, fs, etc. In general, if the feature you're looking at is intended to be wrapping a core runtime / os primitive, it is probably ok ( that's the point of the feature )
20
-
21
- if a completely unrelated feature is using the fs or path module, or Bun unguarded, then that's probably an issue.
22
-
23
- Look for instances of the following, but don't fix them yet.
24
-
25
- - using file system directly, instead of this.container.fs ( except the file system feature itself )
26
- - using the path module functions instead of this.container.paths.resolve ( with the exception of fileManager, where it is ok )
27
- - reinventing the wheel in general instead of using functionality already provided by the container
28
- - anything that would break compatibility with node.js instead of Bun. make sure you wrap it in a guard (if this.container.isBun)
29
-
30
- Save the results of your audit in docs/reports/code-audit-results.md
31
-
32
- If this file already exists, read it first, and note cases where items persist.
33
-
34
- The next step will be me reviewing the audit, providing commentary, and advising you what to fix
@@ -1,27 +0,0 @@
1
- ---
2
- agentOptions:
3
- permissionMode: bypassPermissions
4
- ---
5
-
6
- # Check for undocumented features
7
-
8
- The luca introspection and luca cli's describe command is powered by the JSDoc comments in the code base, and the values passed to the describe methods in the zod schema. This documentation is what is fed to AI Coding assistants to be able to understand how to use the individual features
9
-
10
- Please scan the following paths:
11
-
12
- ```ts
13
- const fm = await container.feature('fileManager').start()
14
- const results = fm.match(['src/node/features/*.ts', 'src/agi/features/*.ts', 'src/web/features/*.ts'])
15
- console.log(results.join("\n"))
16
- ```
17
-
18
- Please ensure every feature has accurate and valid JSDoc documentation for the class definitions, methods, and getters.
19
-
20
- Validate the output of `bun run src/cli/cli.ts describe whatever` for each item you're working on, that it displays properly, is easy to understand, accurate, in terms of how your comments display there. You may need to run `bun run src/cli/cli.ts introspect` to generate the build time data.
21
-
22
- You can pass `--platform=web` to see web specific output.
23
-
24
- ## Quality not just Quantity
25
-
26
- - The presence of documentation isn't sufficient. Is it good documentation? Is it not overly verbose? Does it not explain stuff that doesn't matter? Is it accurate? If there are examples, do they work?
27
- - The main consumer of `luca describe` will be an LLM so token budget matters. Every word has to be doing work. It should still be nice to look at for human coders too.
@@ -1,27 +0,0 @@
1
- ---
2
- target: claude
3
- reusable: true
4
- repeatable: true
5
- ---
6
-
7
- # MCP Test: Build a Command
8
-
9
- You are in an empty luca project. The `luca` CLI is available and you have a `luca-sandbox` MCP server connected.
10
-
11
- ## Task
12
-
13
- Create a luca command called `greet` in `commands/greet.ts` that:
14
-
15
- 1. Accepts a `--name` flag (string, defaults to "world")
16
- 2. Accepts a `--shout` flag (boolean, defaults to false)
17
- 3. Prints "Hello, {name}!" to stdout
18
- 4. If `--shout` is true, uppercases the entire message
19
-
20
- The command should be runnable via `luca greet --name Jon --shout`.
21
-
22
- ## Rules
23
-
24
- - Do not install any npm packages
25
- - Import only from `@soederpop/luca`
26
- - Use the MCP tools to learn the command pattern before writing code
27
- - After creating the file, verify it works by running `luca greet --name Test`
@@ -1,149 +0,0 @@
1
- # Building a Client
2
-
3
- A client is a container-managed connection to an external service. Clients handle network communication — HTTP APIs, WebSocket connections, GraphQL endpoints. They extend `RestClient` (for HTTP), `WebSocketClient` (for WS), or the base `Client` class.
4
-
5
- When to build a client:
6
- - You need to talk to an external API or service
7
- - You want connection management, error handling, and observability for free
8
- - You're wrapping an API so the rest of the codebase uses `container.client('name')`
9
-
10
- ## Imports
11
-
12
- ```ts
13
- import { z } from 'zod'
14
- import { Client, RestClient } from '@soederpop/luca/client'
15
- import { ClientStateSchema, ClientOptionsSchema, ClientEventsSchema } from '@soederpop/luca'
16
- ```
17
-
18
- Use `RestClient` for HTTP APIs (most common). It gives you `get`, `post`, `put`, `patch`, `delete` methods that handle JSON, headers, and error wrapping.
19
-
20
- ## Schemas
21
-
22
- ```ts
23
- export const {{PascalName}}StateSchema = ClientStateSchema.extend({
24
- // Add your state fields here.
25
- // Example: authenticated: z.boolean().default(false).describe('Whether API auth is configured'),
26
- })
27
- export type {{PascalName}}State = z.infer<typeof {{PascalName}}StateSchema>
28
-
29
- export const {{PascalName}}OptionsSchema = ClientOptionsSchema.extend({
30
- // Add constructor options here.
31
- // Example: apiKey: z.string().optional().describe('API key for authentication'),
32
- })
33
- export type {{PascalName}}Options = z.infer<typeof {{PascalName}}OptionsSchema>
34
- ```
35
-
36
- ## Class
37
-
38
- Running `luca introspect` captures JSDoc blocks and Zod schemas and includes them in the description whenever somebody calls `container.clients.describe('{{camelName}}')` or `luca describe {{camelName}}`.
39
-
40
- ```ts
41
- /**
42
- * {{description}}
43
- *
44
- * @example
45
- * ```typescript
46
- * const {{camelName}} = container.client('{{camelName}}')
47
- * ```
48
- *
49
- * @extends RestClient
50
- */
51
- export class {{PascalName}} extends RestClient<{{PascalName}}State, {{PascalName}}Options> {
52
- static override shortcut = 'clients.{{camelName}}' as const
53
- static override stateSchema = {{PascalName}}StateSchema
54
- static override optionsSchema = {{PascalName}}OptionsSchema
55
- static { Client.register(this, '{{camelName}}') }
56
-
57
- /**
58
- * Called after the client is initialized. Use this for any setup logic
59
- * instead of overriding the constructor.
60
- */
61
- async afterInitialize() {
62
- // Set up default headers, configure auth, etc.
63
- }
64
-
65
- // Add API methods here. Each wraps an endpoint.
66
- // Example:
67
- // async listItems(): Promise<Item[]> {
68
- // return this.get('/items')
69
- // }
70
- }
71
- ```
72
-
73
- **Important**: You almost never need to override the constructor. Use `afterInitialize()` for setup logic — it runs after the client is fully wired into the container. Set `baseURL` via the options schema default instead of constructor manipulation.
74
-
75
- ## Module Augmentation
76
-
77
- ```ts
78
- declare module '@soederpop/luca/client' {
79
- interface AvailableClients {
80
- {{camelName}}: typeof {{PascalName}}
81
- }
82
- }
83
- ```
84
-
85
- ## Registration
86
-
87
- Registration happens inside the class body using a static block. The default export is just the class itself.
88
-
89
- ```ts
90
- // Inside the class:
91
- static { Client.register(this, '{{camelName}}') }
92
-
93
- // At module level:
94
- export default {{PascalName}}
95
- ```
96
-
97
- ## Complete Example
98
-
99
- ```ts
100
- import { z } from 'zod'
101
- import { Client, RestClient } from '@soederpop/luca/client'
102
- import { ClientStateSchema, ClientOptionsSchema } from '@soederpop/luca'
103
-
104
- declare module '@soederpop/luca/client' {
105
- interface AvailableClients {
106
- {{camelName}}: typeof {{PascalName}}
107
- }
108
- }
109
-
110
- export const {{PascalName}}StateSchema = ClientStateSchema.extend({})
111
- export type {{PascalName}}State = z.infer<typeof {{PascalName}}StateSchema>
112
-
113
- export const {{PascalName}}OptionsSchema = ClientOptionsSchema.extend({
114
- baseURL: z.string().default('https://api.example.com').describe('API base URL'),
115
- })
116
- export type {{PascalName}}Options = z.infer<typeof {{PascalName}}OptionsSchema>
117
-
118
- /**
119
- * {{description}}
120
- *
121
- * @example
122
- * ```typescript
123
- * const {{camelName}} = container.client('{{camelName}}')
124
- * ```
125
- *
126
- * @extends RestClient
127
- */
128
- export class {{PascalName}} extends RestClient<{{PascalName}}State, {{PascalName}}Options> {
129
- static override shortcut = 'clients.{{camelName}}' as const
130
- static override stateSchema = {{PascalName}}StateSchema
131
- static override optionsSchema = {{PascalName}}OptionsSchema
132
- static { Client.register(this, '{{camelName}}') }
133
-
134
- async afterInitialize() {
135
- // Setup logic goes here — not in the constructor
136
- }
137
- }
138
-
139
- export default {{PascalName}}
140
- ```
141
-
142
- ## Conventions
143
-
144
- - **Extend RestClient for HTTP**: It gives you typed HTTP methods. Only use base `Client` if you need a non-HTTP protocol.
145
- - **Set baseURL via options schema**: Use a Zod `.default()` on the `baseURL` field rather than overriding the constructor.
146
- - **Use `afterInitialize()`**: For any setup logic (auth, default headers, etc.) instead of overriding the constructor.
147
- - **Wrap endpoints as methods**: Each API endpoint gets a method. Keep them thin — just map to HTTP calls.
148
- - **JSDoc everything**: Every public method needs `@param`, `@returns`, `@example`. Run `luca introspect` after changes to update generated docs.
149
- - **Auth in options**: Pass API keys, tokens via options schema. Check them in `afterInitialize()` or a setup method.
@@ -1,120 +0,0 @@
1
- # Building a Command
2
-
3
- A command extends the `luca` CLI. Commands live in a project's `commands/` folder and are automatically discovered. They are Helper subclasses under the hood — the framework grafts your module exports into a Command class at runtime.
4
-
5
- When to build a command:
6
- - You need a CLI task for a project (build scripts, generators, automation)
7
- - You want argument parsing, help text, and container access for free
8
- - The task should be runnable via `luca yourCommand`
9
-
10
- ## Imports
11
-
12
- ```ts
13
- import { z } from 'zod'
14
- import type { ContainerContext } from '@soederpop/luca'
15
- ```
16
-
17
- ## Positional Arguments
18
-
19
- Export a `positionals` array to map CLI positional args into named options fields. The first positional (`_[0]`) is always the command name — `positionals` maps `_[1]`, `_[2]`, etc.
20
-
21
- ```ts
22
- // luca {{kebabName}} ./src => options.target === './src'
23
- export const positionals = ['target']
24
- ```
25
-
26
- ## Args Schema
27
-
28
- Define your command's arguments and flags with Zod. Each field becomes a `--flag` on the CLI. Fields named in `positionals` also accept positional args.
29
-
30
- ```ts
31
- export const argsSchema = z.object({
32
- // Positional: first arg after command name (via positionals array above)
33
- // target: z.string().optional().describe('The target to operate on'),
34
-
35
- // Flags: passed as --flag on the CLI
36
- // verbose: z.boolean().default(false).describe('Enable verbose output'),
37
- // output: z.string().optional().describe('Output file path'),
38
- })
39
- ```
40
-
41
- ## Description
42
-
43
- Export a description string for `luca --help` display:
44
-
45
- ```ts
46
- export const description = '{{description}}'
47
- ```
48
-
49
- ## Handler
50
-
51
- Export a default async function. It receives parsed options and the container context. Use the container for all I/O. Positional args declared in the `positionals` export are available as named fields on `options`.
52
-
53
- ```ts
54
- export default async function {{camelName}}(options: z.infer<typeof argsSchema>, context: ContainerContext) {
55
- const { container } = context
56
- const fs = container.feature('fs')
57
-
58
- // options.target is set from the first positional arg (via positionals export)
59
- // options.verbose, options.output, etc. come from --flags
60
-
61
- // Your implementation here
62
- }
63
- ```
64
-
65
- ## Complete Example
66
-
67
- ```ts
68
- import { z } from 'zod'
69
- import type { ContainerContext } from '@soederpop/luca'
70
-
71
- export const description = '{{description}}'
72
-
73
- // Map positional args to named options: luca {{kebabName}} myTarget => options.target === 'myTarget'
74
- export const positionals = ['target']
75
-
76
- export const argsSchema = z.object({
77
- target: z.string().optional().describe('The target to operate on'),
78
- })
79
-
80
- export default async function {{camelName}}(options: z.infer<typeof argsSchema>, context: ContainerContext) {
81
- const { container } = context
82
- const fs = container.feature('fs')
83
-
84
- console.log('{{kebabName}} running...', options.target)
85
- }
86
- ```
87
-
88
- ## Container Properties
89
-
90
- The `context.container` object provides useful properties beyond features:
91
-
92
- ```ts
93
- export default async function {{camelName}}(options: z.infer<typeof argsSchema>, context: ContainerContext) {
94
- const { container } = context
95
-
96
- // Current working directory
97
- container.cwd // '/path/to/project'
98
-
99
- // Path utilities (scoped to cwd)
100
- container.paths.resolve('src') // '/path/to/project/src'
101
- container.paths.join('a', 'b') // '/path/to/project/a/b'
102
- container.paths.relative('src') // 'src'
103
-
104
- // Package manifest (parsed package.json)
105
- container.manifest.name // 'my-project'
106
- container.manifest.version // '1.0.0'
107
-
108
- // Raw CLI arguments (from minimist) — prefer positionals export for positional args
109
- container.argv // { _: ['{{kebabName}}', ...], verbose: true, ... }
110
- }
111
- ```
112
-
113
- ## Conventions
114
-
115
- - **File location**: `commands/{{kebabName}}.ts` in the project root. The `luca` CLI discovers these automatically.
116
- - **Naming**: kebab-case for filename. `luca {{kebabName}}` maps to `commands/{{kebabName}}.ts`.
117
- - **Use the container**: Never import `fs`, `path`, `child_process` directly. Use `container.feature('fs')`, `container.paths`, `container.feature('proc')`.
118
- - **Positional args**: Export `positionals = ['name1', 'name2']` to map CLI positional args into named options fields. For raw access, use `container.argv._` where `_[0]` is the command name.
119
- - **Exit codes**: Return nothing for success. Throw for errors — the CLI catches and reports them.
120
- - **Help text**: Use `.describe()` on every schema field — it powers `luca {{kebabName}} --help`.
@@ -1,171 +0,0 @@
1
- # Building an Endpoint
2
-
3
- An endpoint is a route handler that `luca serve` auto-discovers and mounts on an Express server. Endpoints live in `endpoints/` and follow a file-based routing convention — each file becomes an API route with automatic validation, OpenAPI spec generation, and rate limiting.
4
-
5
- When to build an endpoint:
6
- - You need a REST API route (GET, POST, PUT, PATCH, DELETE)
7
- - You want Zod validation, OpenAPI docs, and rate limiting for free
8
- - You're building an API that `luca serve` manages
9
-
10
- ## File Location
11
-
12
- Endpoints go in `endpoints/` at your project root:
13
- - `endpoints/health.ts` → `/health`
14
- - `endpoints/posts.ts` → `/api/posts`
15
- - `endpoints/posts/[id].ts` → `/api/posts/:id` (requires `path` export)
16
-
17
- Run `luca serve` and they're automatically discovered and mounted.
18
-
19
- ## Imports
20
-
21
- Endpoints are lightweight — just exports and handler functions. No imports are required.
22
-
23
- If your project has `@soederpop/luca` as an npm dependency, you can import `z` from `zod` and `EndpointContext` from `@soederpop/luca` for type safety. Otherwise, use `any` types — the framework handles validation and context injection for you.
24
-
25
- Access framework capabilities through the `ctx` parameter:
26
- - `ctx.container.feature('fs')` for file operations
27
- - `ctx.container.feature('yaml')` for YAML parsing
28
- - `ctx.container.feature('sqlite')` for database access
29
-
30
- ## Required Exports
31
-
32
- Every endpoint MUST export a `path` string:
33
-
34
- ```ts
35
- export const path = '/api/{{camelName}}'
36
- export const description = '{{description}}'
37
- export const tags = ['{{camelName}}']
38
- ```
39
-
40
- ## Handler Functions
41
-
42
- Export named functions for each HTTP method you support. Each receives validated parameters and a context object:
43
-
44
- ```ts
45
- export async function get(params: any, ctx: any) {
46
- const fs = ctx.container.feature('fs')
47
- // Your logic here
48
- return { message: 'ok' }
49
- }
50
-
51
- export async function post(params: any, ctx: any) {
52
- // Create something
53
- return { created: true }
54
- }
55
- ```
56
-
57
- The `EndpointContext` gives you:
58
- - `ctx.container` — the luca container (access any feature, client, etc.)
59
- - `ctx.request` — Express request object
60
- - `ctx.response` — Express response object
61
- - `ctx.query` — parsed query string
62
- - `ctx.body` — parsed request body
63
- - `ctx.params` — URL parameters (`:id`, etc.)
64
-
65
- Return any object — it's automatically JSON-serialized as the response.
66
-
67
- ## Validation Schemas
68
-
69
- If `zod` is available (via `@soederpop/luca` dependency or `node_modules`), export Zod schemas to validate parameters for each method. Name them `{method}Schema`:
70
-
71
- ```ts
72
- import { z } from 'zod'
73
-
74
- export const getSchema = z.object({
75
- q: z.string().optional().describe('Search query'),
76
- limit: z.number().default(20).describe('Max results'),
77
- })
78
-
79
- export const postSchema = z.object({
80
- title: z.string().min(1).describe('Item title'),
81
- body: z.string().min(1).describe('Item content'),
82
- })
83
- ```
84
-
85
- Invalid requests automatically return 400 with Zod error details. Schemas also feed the auto-generated OpenAPI spec. If zod is not available, skip schema exports — the endpoint still works, you just lose automatic validation.
86
-
87
- ## Rate Limiting
88
-
89
- Export rate limit config to protect endpoints:
90
-
91
- ```ts
92
- // Global rate limit for all methods
93
- export const rateLimit = { maxRequests: 100, windowSeconds: 60 }
94
-
95
- // Per-method rate limit
96
- export const postRateLimit = { maxRequests: 10, windowSeconds: 1 }
97
- ```
98
-
99
- ## Delete Handler
100
-
101
- `delete` is a reserved word in JS, so you can't use it as a function name directly. Use a named export alias:
102
-
103
- ```ts
104
- // Use a local name, then re-export as `delete`
105
- const del = async (params: any, ctx: any) => {
106
- return { deleted: true }
107
- }
108
- export { del as delete }
109
- ```
110
-
111
- You can also export `deleteSchema` and `deleteRateLimit` for validation and rate limiting on DELETE.
112
-
113
- ## Complete Example
114
-
115
- A CRUD endpoint for a resource (no external imports needed):
116
-
117
- ```ts
118
- export const path = '/api/{{camelName}}'
119
- export const description = '{{description}}'
120
- export const tags = ['{{camelName}}']
121
-
122
- export async function get(params: any, ctx: any) {
123
- return { items: [], total: 0 }
124
- }
125
-
126
- export async function post(params: any, ctx: any) {
127
- return { item: { id: '1', ...params }, message: 'Created' }
128
- }
129
-
130
- const del = async (params: any, ctx: any) => {
131
- const { id } = ctx.params
132
- return { message: `Deleted ${id}` }
133
- }
134
- export { del as delete }
135
- ```
136
-
137
- ## Dynamic Route Example
138
-
139
- For routes with URL parameters, create a nested file:
140
-
141
- ```ts
142
- // endpoints/{{camelName}}/[id].ts
143
- export const path = '/api/{{camelName}}/:id'
144
- export const description = 'Get, update, or delete a specific item'
145
- export const tags = ['{{camelName}}']
146
-
147
- export async function get(params: any, ctx: any) {
148
- const { id } = ctx.params
149
- return { item: { id } }
150
- }
151
-
152
- export async function put(params: any, ctx: any) {
153
- const { id } = ctx.params
154
- return { item: { id, ...params }, message: 'Updated' }
155
- }
156
-
157
- const del = async (params: any, ctx: any) => {
158
- const { id } = ctx.params
159
- return { message: `Deleted ${id}` }
160
- }
161
- export { del as delete }
162
- ```
163
-
164
- ## Conventions
165
-
166
- - **File = route**: The file path maps to the URL path. `endpoints/users.ts` serves `/api/users`.
167
- - **Export `path`**: Every endpoint must export a `path` string. This is the mounted route.
168
- - **Use Zod schemas**: Name them `getSchema`, `postSchema`, etc. They validate AND document.
169
- - **Use the container**: Access features via `ctx.container.feature('fs')`, not Node.js imports.
170
- - **Return objects**: Handler return values are JSON-serialized. Use `ctx.response` only for streaming or custom status codes.
171
- - **OpenAPI for free**: Your `path`, `description`, `tags`, and schemas automatically generate an OpenAPI spec at `/openapi.json`.