acrylblends 1.0.10 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (252) hide show
  1. package/README.md +9 -0
  2. package/dist/index.d.ts +60 -2
  3. package/dist/index.js +1992 -33
  4. package/dist/index.js.map +1 -1
  5. package/docs/framework/agents/index.md +1 -1
  6. package/docs/framework/api/summary.md +1 -1
  7. package/docs/framework/getting-started/desktop.md +23 -4
  8. package/docs/framework/guides/create-acrylblends.md +1 -1
  9. package/docs/framework/guides/production.md +20 -0
  10. package/docs/framework/workshop/README.md +174 -285
  11. package/docs/framework/workshop/facilitator.md +81 -90
  12. package/legacy/README.md +9 -0
  13. package/legacy/agent/157ce3db1112/src/app.ts +98 -0
  14. package/legacy/agent/157ce3db1112/src/routes.ts +63 -0
  15. package/legacy/agent/24c681a00fca/src/app.ts +160 -0
  16. package/legacy/agent/24c681a00fca/src/routes.ts +83 -0
  17. package/legacy/agent/2e790da977b2/src/app.ts +98 -0
  18. package/legacy/agent/2e790da977b2/src/routes.ts +63 -0
  19. package/legacy/agent/6307045545dc/src/app.ts +168 -0
  20. package/legacy/agent/6307045545dc/src/routes.ts +83 -0
  21. package/legacy/agent/6a5fb9c15c53/src/app.ts +158 -0
  22. package/legacy/agent/6a5fb9c15c53/src/routes.ts +83 -0
  23. package/legacy/agent/71fb54a5a942/src/app.ts +111 -0
  24. package/legacy/agent/71fb54a5a942/src/routes.ts +63 -0
  25. package/legacy/agent/74ece148269c/src/app.ts +168 -0
  26. package/legacy/agent/74ece148269c/src/routes.ts +93 -0
  27. package/legacy/agent/855359304707/src/app.ts +168 -0
  28. package/legacy/agent/855359304707/src/routes.ts +126 -0
  29. package/legacy/agent/b5ef3c786ae4/src/app.ts +127 -0
  30. package/legacy/agent/b5ef3c786ae4/src/routes.ts +76 -0
  31. package/legacy/agent/c2f30958043b/src/app.ts +98 -0
  32. package/legacy/agent/c2f30958043b/src/routes.ts +53 -0
  33. package/legacy/blank/5a91c558af22/src/routes.ts +18 -0
  34. package/legacy/blank/9c650cf52bf3/src/routes.ts +14 -0
  35. package/legacy/blank/aea589283445/src/routes.ts +16 -0
  36. package/legacy/blank/b2cbb759c889/src/routes.ts +16 -0
  37. package/legacy/blank/d6d371c9a65e/src/routes.ts +18 -0
  38. package/legacy/chat/7076cc821e2c/src/app.ts +72 -0
  39. package/legacy/chat/7076cc821e2c/src/routes.ts +13 -0
  40. package/legacy/chat/7dbe6d5170df/src/app.ts +107 -0
  41. package/legacy/chat/7dbe6d5170df/src/routes.ts +19 -0
  42. package/legacy/chat/a9a9ab44c58e/src/app.ts +107 -0
  43. package/legacy/chat/a9a9ab44c58e/src/routes.ts +15 -0
  44. package/legacy/chat/f20ad9a51b06/src/app.ts +106 -0
  45. package/legacy/chat/f20ad9a51b06/src/routes.ts +15 -0
  46. package/legacy/layouts.json +524 -0
  47. package/legacy/nodejs/1d477f37aaf4/src/app.ts +92 -0
  48. package/legacy/nodejs/1d477f37aaf4/src/routes.ts +40 -0
  49. package/legacy/nodejs/b1bd9462496c/src/app.ts +61 -0
  50. package/legacy/nodejs/b1bd9462496c/src/routes.ts +37 -0
  51. package/legacy/nodejs/d5bab75076ef/src/app.ts +95 -0
  52. package/legacy/nodejs/d5bab75076ef/src/routes.ts +40 -0
  53. package/legacy/notes/4edc36949c15/src/app.ts +107 -0
  54. package/legacy/notes/4edc36949c15/src/routes.ts +14 -0
  55. package/legacy/notes/6cab2d09747c/src/app.ts +72 -0
  56. package/legacy/notes/6cab2d09747c/src/routes.ts +12 -0
  57. package/legacy/notes/7ca2dfed623a/src/app.ts +106 -0
  58. package/legacy/notes/7ca2dfed623a/src/routes.ts +14 -0
  59. package/legacy/todo/02e613b3625c/src/app.ts +71 -0
  60. package/legacy/todo/02e613b3625c/src/todo.ts +123 -0
  61. package/legacy/todo/45694a8d9e15/src/app.ts +71 -0
  62. package/legacy/todo/45694a8d9e15/src/todo.ts +96 -0
  63. package/legacy/todo/5923d3a6099f/src/app.ts +71 -0
  64. package/legacy/todo/5923d3a6099f/src/todo.ts +125 -0
  65. package/legacy/todo/849a18d66dc1/src/app.ts +91 -0
  66. package/legacy/todo/849a18d66dc1/src/todo.ts +125 -0
  67. package/legacy/todo/8e64211312f3/src/app.ts +71 -0
  68. package/legacy/todo/8e64211312f3/src/todo.ts +125 -0
  69. package/legacy/todo/b79078a87565/src/app.ts +71 -0
  70. package/legacy/todo/b79078a87565/src/todo.ts +125 -0
  71. package/lib/{audit-Dw-siYTp.d.ts → audit-Bok_UNCn.d.ts} +41 -6
  72. package/lib/{client-modules-drj4mjhj.js → client-modules-Bkdr83jO.js} +1 -1
  73. package/lib/cordis/door.d.ts +44 -7
  74. package/lib/cordis/door.js +214 -60
  75. package/lib/cordis/inspect.js +1 -1
  76. package/lib/cordis/node-server.d.ts +101 -3
  77. package/lib/cordis/node-server.js +3 -3
  78. package/lib/cordis/router-http.d.ts +7 -1
  79. package/lib/cordis/router-http.js +44 -3
  80. package/lib/cordis/router.d.ts +1 -1
  81. package/lib/cordis/router.js +1 -1
  82. package/lib/cordis/state.d.ts +3 -2
  83. package/lib/cordis/state.js +371 -7
  84. package/lib/door/host.d.ts +2 -2
  85. package/lib/door/host.js +1 -1
  86. package/lib/door/page.d.ts +20 -1
  87. package/lib/door/page.js +75 -14
  88. package/lib/door/protocol.d.ts +1 -1
  89. package/lib/drivers.d.ts +10 -1
  90. package/lib/{index-DMOtA-NJ.d.ts → index-DGq7H0lb.d.ts} +11 -1
  91. package/lib/node-server.d.ts +7 -1
  92. package/lib/node-server.js +2 -2
  93. package/lib/{protocol-a2aqrp2X.d.ts → protocol-BeIYCgTo.d.ts} +4 -0
  94. package/lib/{snapshot-text-BfEbEOjA.js → snapshot-text-CXTnjxGx.js} +121 -9
  95. package/lib/src-CtkIX_Gg.js +427 -0
  96. package/lib/{src-BTBm4OPD.js → src-iBJ2ysV9.js} +77 -14
  97. package/lib/{test-websocket-BLeEvybj.js → test-websocket-CQOSvBth.js} +17 -7
  98. package/lib/{test-websocket-DyeS50Tr.d.ts → test-websocket-GUTAkFQT.d.ts} +3 -1
  99. package/package.json +2 -1
  100. package/plugins/acryl-door/src/host/channel.ts +124 -9
  101. package/plugins/acryl-door/src/host/chat-tools.ts +8 -6
  102. package/plugins/acryl-door/src/host/door-file.ts +7 -2
  103. package/plugins/acryl-door/src/host/door.ts +58 -23
  104. package/plugins/acryl-door/src/host/page-routes.ts +3 -1
  105. package/plugins/acryl-door/src/host/page-socket.ts +18 -8
  106. package/plugins/acryl-door/src/host/verbs.ts +3 -0
  107. package/plugins/acryl-door/src/index.ts +166 -29
  108. package/plugins/acryl-door/src/page/base.ts +32 -0
  109. package/plugins/acryl-door/src/page/channel.ts +11 -1
  110. package/plugins/acryl-door/src/page/driver/accessibility.ts +11 -0
  111. package/plugins/acryl-door/src/page/driver/actions.ts +4 -0
  112. package/plugins/acryl-door/src/page/driver/driver.ts +49 -7
  113. package/plugins/acryl-door/src/page/driver/snapshot.ts +5 -2
  114. package/plugins/acryl-door/src/page/index.ts +46 -2
  115. package/plugins/acryl-door/src/page/indicator.ts +14 -6
  116. package/plugins/acryl-door/src/page/outline.ts +56 -0
  117. package/plugins/acryl-door/src/page/protocol.ts +4 -0
  118. package/plugins/acryl-door/src/page/snapshot-text.ts +2 -1
  119. package/plugins/acryl-node-server/src/adapter/listener.ts +4 -0
  120. package/plugins/acryl-node-server/src/adapter/raw.ts +18 -0
  121. package/plugins/acryl-node-server/src/adapter/websocket.ts +15 -9
  122. package/plugins/acryl-node-server/src/client-modules.ts +7 -1
  123. package/plugins/acryl-node-server/src/index.ts +304 -16
  124. package/plugins/acryl-node-server/src/upgrade-hub.ts +2 -2
  125. package/plugins/acryl-page/plugin.json +12 -0
  126. package/plugins/acryl-page/src/index.ts +163 -0
  127. package/plugins/acryl-router/src/service.ts +77 -14
  128. package/plugins/acryl-router-http/src/index.ts +15 -1
  129. package/plugins/acryl-router-http/src/serve.ts +31 -0
  130. package/plugins/acryl-state/plugin.json +4 -3
  131. package/plugins/acryl-state/src/client-source.ts +244 -0
  132. package/plugins/acryl-state/src/service.ts +33 -6
  133. package/plugins/acryl-state/src/socket.ts +96 -0
  134. package/plugins/acryl-web-server/plugin.json +14 -0
  135. package/plugins/acryl-web-server/src/index.ts +164 -0
  136. package/plugins/agent/agent.ts +38 -7
  137. package/plugins/agent/index.ts +1 -1
  138. package/plugins/agent/model.ts +10 -2
  139. package/plugins/agent/tools.ts +9 -3
  140. package/plugins/agent-panel/client/describe.ts +57 -0
  141. package/plugins/agent-panel/client/driver-pick.ts +22 -0
  142. package/plugins/agent-panel/client/frame.ts +51 -0
  143. package/plugins/agent-panel/client/main.ts +343 -81
  144. package/plugins/agent-panel/drivers.ts +7 -2
  145. package/plugins/agent-panel/headless.ts +5 -2
  146. package/plugins/agent-panel/index.ts +187 -61
  147. package/plugins/agent-panel/mount.ts +27 -0
  148. package/plugins/agent-panel/visitors.ts +231 -0
  149. package/plugins/desktop/frame.ts +231 -0
  150. package/plugins/desktop/launch.ts +44 -9
  151. package/plugins/desktop/main.ts +100 -32
  152. package/plugins/desktop/window.ts +21 -4
  153. package/plugins/driver-pty/client/terminal.ts +4 -1
  154. package/plugins/driver-pty/index.ts +38 -11
  155. package/plugins/driver-pty/spawn.ts +38 -0
  156. package/plugins/driver-pty/terminal.ts +2 -0
  157. package/plugins/extensions/index.ts +26 -1
  158. package/plugins/extensions/resolve.ts +13 -0
  159. package/plugins/feedback/client.d.ts +22 -0
  160. package/plugins/feedback/client.js +471 -0
  161. package/plugins/feedback/index.ts +143 -0
  162. package/plugins/feedback/plugin.json +11 -0
  163. package/plugins/feedback/store.ts +307 -0
  164. package/plugins/home/index.ts +122 -0
  165. package/plugins/home/plugin.json +11 -0
  166. package/plugins/instance/index.ts +12 -3
  167. package/plugins/manifest/app-plugins.ts +86 -0
  168. package/plugins/manifest/index.ts +12 -2
  169. package/plugins/manifest/snapshot.ts +275 -0
  170. package/plugins/openai/index.ts +64 -5
  171. package/plugins/openai/prompt.ts +23 -0
  172. package/shared/AGENTS.core.md +36 -16
  173. package/shared/skills/acryl-add-ui/SKILL.md +19 -0
  174. package/shared/skills/acryl-app/SKILL.md +13 -0
  175. package/shared/skills/acryl-build-plugin/SKILL.md +22 -0
  176. package/shared/skills/acryl-change-plugin/SKILL.md +14 -0
  177. package/shared/skills/acryl-diagnose-plugin/SKILL.md +13 -0
  178. package/shared/skills/acryl-fix-plugin/SKILL.md +13 -0
  179. package/shared/skills/acryl-remove-plugin/SKILL.md +12 -0
  180. package/shared/skills/acryl-share-plugin/SKILL.md +16 -0
  181. package/shared/skills/cordis-plugin/SKILL.md +26 -0
  182. package/templates/agent/AGENTS.md +4 -2
  183. package/templates/agent/blend.yaml +4 -0
  184. package/templates/agent/gitignore +1 -0
  185. package/templates/agent/package.json +1 -0
  186. package/templates/agent/src/app.ts +150 -33
  187. package/templates/agent/src/frame.ts +17 -0
  188. package/templates/agent/src/main.ts +5 -3
  189. package/templates/agent/src/routes.ts +73 -21
  190. package/templates/agent/template.json +2 -0
  191. package/templates/agent/test/app.test.ts +83 -5
  192. package/templates/blank/AGENTS.md +3 -2
  193. package/templates/blank/blend.yaml +11 -0
  194. package/templates/blank/gitignore +1 -0
  195. package/templates/blank/package.json +1 -0
  196. package/templates/blank/src/app.ts +100 -29
  197. package/templates/blank/src/door.ts +7 -0
  198. package/templates/blank/src/first-page.ts +5 -0
  199. package/templates/blank/src/frame.ts +17 -0
  200. package/templates/blank/src/routes.ts +65 -8
  201. package/templates/blank/template.json +14 -1
  202. package/templates/blank/test/app.test.ts +103 -16
  203. package/templates/chat/blend.yaml +2 -1
  204. package/templates/chat/gitignore +1 -0
  205. package/templates/chat/package.json +1 -0
  206. package/templates/chat/src/app.ts +72 -22
  207. package/templates/chat/src/chat-app.ts +11 -2
  208. package/templates/chat/src/client/chat.tsx +4 -2
  209. package/templates/chat/src/frame.ts +17 -0
  210. package/templates/chat/src/main.ts +1 -6
  211. package/templates/chat/src/page.tsx +6 -4
  212. package/templates/chat/src/routes.ts +14 -4
  213. package/templates/chat/src/runtime.ts +9 -3
  214. package/templates/chat/template.json +3 -1
  215. package/templates/chat/test/chat.test.ts +46 -1
  216. package/templates/chat/test/server.test.ts +17 -3
  217. package/templates/nodejs/blend.yaml +2 -1
  218. package/templates/nodejs/gitignore +1 -0
  219. package/templates/nodejs/package.json +1 -0
  220. package/templates/nodejs/src/app.ts +76 -21
  221. package/templates/nodejs/src/frame.ts +17 -0
  222. package/templates/nodejs/src/main.ts +1 -6
  223. package/templates/nodejs/src/page.tsx +3 -3
  224. package/templates/nodejs/src/routes.ts +32 -13
  225. package/templates/nodejs/template.json +3 -1
  226. package/templates/nodejs/test/app.test.ts +38 -3
  227. package/templates/nodejs/test/server.test.ts +17 -3
  228. package/templates/notes/blend.yaml +2 -1
  229. package/templates/notes/gitignore +1 -0
  230. package/templates/notes/package.json +1 -0
  231. package/templates/notes/src/app.ts +72 -22
  232. package/templates/notes/src/frame.ts +17 -0
  233. package/templates/notes/src/main.ts +1 -6
  234. package/templates/notes/src/notes-app.ts +24 -17
  235. package/templates/notes/src/routes.ts +11 -4
  236. package/templates/notes/src/runtime.ts +9 -3
  237. package/templates/notes/src/views.tsx +26 -17
  238. package/templates/notes/template.json +3 -1
  239. package/templates/notes/test/notes.test.ts +39 -1
  240. package/templates/notes/test/server.test.ts +17 -3
  241. package/templates/todo/blend.yaml +3 -0
  242. package/templates/todo/gitignore +1 -0
  243. package/templates/todo/package.json +1 -0
  244. package/templates/todo/src/app.ts +81 -27
  245. package/templates/todo/src/door.ts +7 -0
  246. package/templates/todo/src/frame.ts +17 -0
  247. package/templates/todo/src/page.ts +13 -6
  248. package/templates/todo/src/todo.ts +18 -6
  249. package/templates/todo/template.json +11 -1
  250. package/templates/todo/test/todo.test.ts +67 -9
  251. package/lib/src-LX0E4ec4.js +0 -117
  252. package/shared/SKILL.md +0 -14
@@ -7,7 +7,7 @@ A coding agent (Claude Code, Codex, OpenCode, Copilot and others) builds on Acry
7
7
  - `AGENTS.md`: where the API is, how a feature is built (an `Acryl` app mounted with `ctx.router.route`, a plugin registered in `src/app.ts` and `blend.yaml`, a state cell),
8
8
  the defaults and how each is swapped, the things that surprise people, and what must pass before a task is done (`npm test` and `npm run check`).
9
9
  - `CLAUDE.md`: the same text as `AGENTS.md`, so tools that read either file read the same guide.
10
- - One skill, `app-guide`, in `.claude/skills/app-guide/SKILL.md` and `.agents/skills/app-guide/SKILL.md` (the same text): where to read first, the one plugin folder, the defaults, the door, and what "done" means.
10
+ - Two skills, `acryl-app` and `cordis-plugin`, in `.claude/skills/<name>/SKILL.md` and `.agents/skills/<name>/SKILL.md` (the same text in both places): how the app is put together and how to change and check it through the door, and how to add a feature as a Cordis plugin.
11
11
  - `.gitignore` lists `.acryl/`, the folder the door keeps its secret and state in, so `git add -A` stages none of it.
12
12
 
13
13
  ## One plugin folder
@@ -131,7 +131,7 @@ Do not start timers inside a handler for keep-alives; let the plugin own one tim
131
131
  | `ctx.nodeServer.url`, `ctx.nodeServer.port` | `nodeServer` (`acryl-node-server`) | without the Host: one Node server for the whole router; options `hostname` (`127.0.0.1`), `port` (`0`), `scan` (`20`). See [Node server](../cordis/node-server.md) |
132
132
  | `ctx.state.cell(key, initial)` | `state` (`acryl-state`) | a writable cell owned by the plugin: `get()`, `set(value)`, `update(fn)`, `subscribe(fn)` returning an unsubscribe |
133
133
  | `ctx.state.derive(key, [cells], fn)` | `state` | a read-only cell computed from others |
134
- | `GET /api/state/:key`, `GET /api/state/:key/events` | `state` | each cell over the router, read-only; `useCell(cell)` from `acryl-state/react` in a React page |
134
+ | `GET /api/state/:key`, `GET /api/state/:key/events`, `GET /api/state/ws`, `GET /api/state/client.js` | `state` | each cell over the router, read-only; `watch(key, fn)` of `/api/state/client.js` follows keys in a page over one WebSocket (event streams as the fallback); `useCell(cell)` from `acryl-state/react` in a React page |
135
135
 
136
136
  Everything a plugin registers this way (mounts, cells, handlers) goes away when the plugin unloads, and comes back once when it reloads:
137
137
  see [Plugin lifecycle and disposal](../cordis/plugin-lifecycle.md).
@@ -1,6 +1,7 @@
1
1
  # Desktop
2
2
 
3
- An Acryl app also runs as a desktop app: an Electron window opens on the app's own server. It is the same app and the same code as `npm run dev`; nothing in the app changes. This page covers a plain Acryl app (the `nodejs`
3
+ An Acryl app also runs as a desktop app: an Electron window opens on the app's own server. It is the same app and the same code as `npm run dev`; nothing in the app changes. A Blend app that runs inside the ACRYL frame
4
+ (it has `scripts/ide-host.mjs`) gets the whole frame in the window, the same one `npm run dev` serves to the browser: see [The frame in the window](#the-frame-in-the-window). This page covers a plain Acryl app (the `nodejs`
4
5
  template) and a Blend app (the `agent` template or any other `acrylblends init` template). It runs from source today: packaging a distributable app (dmg, exe, deb) is not part of it yet.
5
6
 
6
7
  ## Add it
@@ -26,10 +27,28 @@ In a Blend app, the same two commands (`npx acrylblends add desktop`, `npm insta
26
27
 
27
28
  ## What `npm run desktop` does
28
29
 
29
- 1. Serves the app on `127.0.0.1` with a free port: for a plain app, `app.fetch` from `src/app.ts` (`export default app`) through `acrylblends/node-server`; for a Blend app, its own `createApp`.
30
+ 1. For a frame app, attaches to the running frame or starts its host (see [The frame in the window](#the-frame-in-the-window)). Otherwise it serves the app on `127.0.0.1` with a free port: for a plain app, `app.fetch` from `src/app.ts` (`export default app`) through `acrylblends/node-server`; for a Blend app, its own `createApp`.
30
31
  2. Takes a single-instance lock: a second launch of the same app focuses the first window and exits.
31
- 3. Opens one window on the server's address, with a locked-down renderer (context isolation, no Node in the page, the sandbox, web security). Navigation stays on the app's own origin; any other link opens in the system browser.
32
- 4. When the window closes (or on SIGINT or SIGTERM), stops the server and exits.
32
+ 3. Opens one window on the server's address, with a locked-down renderer (context isolation, no Node in the page, the sandbox, web security). Navigation stays on the app's own origin; a link to any other `http(s)` or `mailto` address opens in the system browser.
33
+ 4. When the window closes (or on SIGINT or SIGTERM), stops the server or frame host it started (never one it attached to) and exits.
34
+
35
+ ## The frame in the window
36
+
37
+ A Blend app made with the frame (`npm run dev` runs `scripts/ide-host.mjs`) opens the ACRYL frame in its desktop window, not only its page: the left panel with the
38
+ projects and sessions, the right panel with Files, Changes and Review, Settings, terminal tabs, the DSH chat, and the app's own page in a browser tile. It is the
39
+ same frame the browser shows; the desktop builds nothing of its own.
40
+
41
+ 1. When the frame already runs for this folder (`npm run dev` in another terminal), the window attaches to it: it reads the address the host keeps in
42
+ `.acrylblends/frame-url.json` (owner-only, with the launch token) and opens it. Closing the window leaves that host running.
43
+ 2. Otherwise the window starts the host itself, exactly as `npm run dev` does (the same npm and Node that ran `npm run desktop`; the host never runs inside
44
+ Electron), and opens the address it prints. Closing the window stops that host and everything it started, including its terminals, so its port is free
45
+ again. Ctrl-C in the terminal does the same: Electron runs in a process group of its own, and `npm run desktop` passes it exactly one signal (a second
46
+ one would end Electron before it could stop the host).
47
+ 3. Navigation follows ACRYL Desktop's rule: the frame's own address stays in the window, and its tiles (the app's page in an iframe) load freely. A link to any
48
+ other `http(s)` or `mailto` address opens in the system browser, and nothing else opens at all.
49
+ 4. The door's `window list` shows each window's address without the launch token.
50
+
51
+ The application menu's `Settings...` (`Cmd+,` on macOS, in the app menu; `Ctrl+,` and the File menu on Windows and Linux) opens the frame's own Settings, the dialog the left panel's Settings button opens. `acrylblends.desktopPath` does not apply to a frame app, because the frame opens the app's page in its tile on first run.
33
52
 
34
53
  ## The first launch downloads Electron
35
54
 
@@ -16,7 +16,7 @@
16
16
 
17
17
  Every template is a Cordis app: `blend.yaml` lists the plugins that are mounted, every plugin is a folder in `plugins/`, and the app is started by `src/main.ts`. A bare template name after the directory is the same as `--template`: `npm create acrylblends@latest my-app notes`. `bun` is no longer a template; the framework still runs on Bun (see [Bun](../getting-started/bun.md)), but a new app is a Cordis app on Node.
18
18
 
19
- Every template includes `AGENTS.md` and `CLAUDE.md` (the same text), one skill (`app-guide`) in `.claude/skills/` and `.agents/skills/`, and a copy of these docs in `docs/framework/`, so a coding agent working in the folder reads the
19
+ Every template includes `AGENTS.md` and `CLAUDE.md` (the same text), two skills (`acryl-app`, `cordis-plugin`) in `.claude/skills/` and `.agents/skills/`, and a copy of these docs in `docs/framework/`, so a coding agent working in the folder reads the
20
20
  API from the folder.
21
21
 
22
22
  ## Passing arguments
@@ -48,6 +48,26 @@ Installing a plugin (`ctx.extensions.install`, the door's `plugin add`, the buil
48
48
  - It **stops**: reading any file outside the tool's own folder; writing files; starting child processes or workers; loading native addons; using the inspector. It gets an empty environment (no keys, no paths). It is killed after a time limit and capped in memory and output size. Calls are independent: nothing survives into the next one.
49
49
  - It **does not stop**: network access (Node 24 has no network permission: restrict egress outside the process where that matters), and it does not apply to plugins installed live (those are not run in the sandbox).
50
50
 
51
+ ## The address and the port
52
+
53
+ A server made from a template listens on `127.0.0.1` and starts looking for a free port at a number of its own (3100 and up, chosen from the app's folder). A hosting platform tells the process where to listen with `PORT`, and a container needs `0.0.0.0` to be reached from outside. The app reads four variables, in this order:
54
+
55
+ | What | First | Then | Otherwise |
56
+ | --- | --- | --- | --- |
57
+ | The port to start from (`0` for any free port) | `ACRYLBLENDS_PORT` | `PORT` | a number of its own, from the app's folder |
58
+ | The interface | `ACRYLBLENDS_HOST` | `HOST` | `127.0.0.1` (this machine only) |
59
+
60
+ `PORT` and `HOST` have been read since 1.1.0; before it, the `agent` and `blank` templates ignored `PORT` (`PORT=3299` still listened on the app's own number). If the port is taken the server tries the next ones, and the line it prints at start (`app listening on http://0.0.0.0:3299`) says which it got; a platform that routes to a fixed port should be given one that is free. For example, on a plain server:
61
+
62
+ ```sh
63
+ npm ci --omit=dev
64
+ NODE_ENV=production HOST=0.0.0.0 PORT=3299 npm start
65
+ # app listening on http://0.0.0.0:3299 (data in /srv/app/.acrylblends; ...)
66
+ curl http://127.0.0.1:3299/health
67
+ ```
68
+
69
+ Putting the app on `0.0.0.0` makes it reachable by anyone who can reach the machine: put the login or the proxy in front first (see the checklist below).
70
+
51
71
  ## Checklist for a deployment
52
72
 
53
73
  1. `NODE_ENV=production` (the process manager or the Dockerfile sets it; the templates' Dockerfile does).