acrylblends 1.1.0 → 1.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 (263) hide show
  1. package/README.md +9 -0
  2. package/dist/index.d.ts +47 -2
  3. package/dist/index.js +2017 -32
  4. package/dist/index.js.map +1 -1
  5. package/docs/framework/agents/index.md +1 -1
  6. package/docs/framework/getting-started/desktop.md +23 -4
  7. package/docs/framework/guides/create-acrylblends.md +5 -3
  8. package/docs/framework/workshop/README.md +139 -153
  9. package/docs/framework/workshop/facilitator.md +69 -101
  10. package/legacy/README.md +9 -0
  11. package/legacy/agent/157ce3db1112/src/app.ts +98 -0
  12. package/legacy/agent/157ce3db1112/src/routes.ts +63 -0
  13. package/legacy/agent/24c681a00fca/src/app.ts +160 -0
  14. package/legacy/agent/24c681a00fca/src/routes.ts +83 -0
  15. package/legacy/agent/2e790da977b2/src/app.ts +98 -0
  16. package/legacy/agent/2e790da977b2/src/routes.ts +63 -0
  17. package/legacy/agent/6307045545dc/src/app.ts +168 -0
  18. package/legacy/agent/6307045545dc/src/routes.ts +83 -0
  19. package/legacy/agent/6a5fb9c15c53/src/app.ts +158 -0
  20. package/legacy/agent/6a5fb9c15c53/src/routes.ts +83 -0
  21. package/legacy/agent/71fb54a5a942/src/app.ts +111 -0
  22. package/legacy/agent/71fb54a5a942/src/routes.ts +63 -0
  23. package/legacy/agent/74ece148269c/src/app.ts +168 -0
  24. package/legacy/agent/74ece148269c/src/routes.ts +93 -0
  25. package/legacy/agent/855359304707/src/app.ts +168 -0
  26. package/legacy/agent/855359304707/src/routes.ts +126 -0
  27. package/legacy/agent/b5ef3c786ae4/src/app.ts +127 -0
  28. package/legacy/agent/b5ef3c786ae4/src/routes.ts +76 -0
  29. package/legacy/agent/c2f30958043b/src/app.ts +98 -0
  30. package/legacy/agent/c2f30958043b/src/routes.ts +53 -0
  31. package/legacy/blank/5a91c558af22/src/routes.ts +18 -0
  32. package/legacy/blank/9c650cf52bf3/src/routes.ts +14 -0
  33. package/legacy/blank/aea589283445/src/routes.ts +16 -0
  34. package/legacy/blank/b2cbb759c889/src/routes.ts +16 -0
  35. package/legacy/blank/d6d371c9a65e/src/routes.ts +18 -0
  36. package/legacy/chat/7076cc821e2c/src/app.ts +72 -0
  37. package/legacy/chat/7076cc821e2c/src/routes.ts +13 -0
  38. package/legacy/chat/7dbe6d5170df/src/app.ts +107 -0
  39. package/legacy/chat/7dbe6d5170df/src/routes.ts +19 -0
  40. package/legacy/chat/a9a9ab44c58e/src/app.ts +107 -0
  41. package/legacy/chat/a9a9ab44c58e/src/routes.ts +15 -0
  42. package/legacy/chat/f20ad9a51b06/src/app.ts +106 -0
  43. package/legacy/chat/f20ad9a51b06/src/routes.ts +15 -0
  44. package/legacy/layouts.json +524 -0
  45. package/legacy/nodejs/1d477f37aaf4/src/app.ts +92 -0
  46. package/legacy/nodejs/1d477f37aaf4/src/routes.ts +40 -0
  47. package/legacy/nodejs/b1bd9462496c/src/app.ts +61 -0
  48. package/legacy/nodejs/b1bd9462496c/src/routes.ts +37 -0
  49. package/legacy/nodejs/d5bab75076ef/src/app.ts +95 -0
  50. package/legacy/nodejs/d5bab75076ef/src/routes.ts +40 -0
  51. package/legacy/notes/4edc36949c15/src/app.ts +107 -0
  52. package/legacy/notes/4edc36949c15/src/routes.ts +14 -0
  53. package/legacy/notes/6cab2d09747c/src/app.ts +72 -0
  54. package/legacy/notes/6cab2d09747c/src/routes.ts +12 -0
  55. package/legacy/notes/7ca2dfed623a/src/app.ts +106 -0
  56. package/legacy/notes/7ca2dfed623a/src/routes.ts +14 -0
  57. package/legacy/todo/02e613b3625c/src/app.ts +71 -0
  58. package/legacy/todo/02e613b3625c/src/todo.ts +123 -0
  59. package/legacy/todo/45694a8d9e15/src/app.ts +71 -0
  60. package/legacy/todo/45694a8d9e15/src/todo.ts +96 -0
  61. package/legacy/todo/5923d3a6099f/src/app.ts +71 -0
  62. package/legacy/todo/5923d3a6099f/src/todo.ts +125 -0
  63. package/legacy/todo/849a18d66dc1/src/app.ts +91 -0
  64. package/legacy/todo/849a18d66dc1/src/todo.ts +125 -0
  65. package/legacy/todo/8e64211312f3/src/app.ts +71 -0
  66. package/legacy/todo/8e64211312f3/src/todo.ts +125 -0
  67. package/legacy/todo/b79078a87565/src/app.ts +71 -0
  68. package/legacy/todo/b79078a87565/src/todo.ts +125 -0
  69. package/lib/{audit-BFpULBCj.d.ts → audit-Bok_UNCn.d.ts} +26 -3
  70. package/lib/{client-modules-drj4mjhj.js → client-modules-Bkdr83jO.js} +1 -1
  71. package/lib/cordis/door.d.ts +87 -9
  72. package/lib/cordis/door.js +324 -60
  73. package/lib/cordis/inspect.js +1 -1
  74. package/lib/cordis/node-server.d.ts +101 -3
  75. package/lib/cordis/node-server.js +3 -3
  76. package/lib/cordis/router-http.d.ts +7 -1
  77. package/lib/cordis/router-http.js +44 -3
  78. package/lib/cordis/router.d.ts +1 -1
  79. package/lib/cordis/router.js +1 -1
  80. package/lib/cordis/state.js +1 -1
  81. package/lib/door/host.d.ts +2 -2
  82. package/lib/door/host.js +1 -1
  83. package/lib/door/page.d.ts +10 -1
  84. package/lib/door/page.js +46 -7
  85. package/lib/door/protocol.d.ts +1 -1
  86. package/lib/drivers.d.ts +10 -1
  87. package/lib/{index-DMOtA-NJ.d.ts → index-DGq7H0lb.d.ts} +11 -1
  88. package/lib/node-server.d.ts +7 -1
  89. package/lib/node-server.js +2 -2
  90. package/lib/{protocol-a2aqrp2X.d.ts → protocol-BeIYCgTo.d.ts} +4 -0
  91. package/lib/{snapshot-text-BwM6T2nG.js → snapshot-text-CXTnjxGx.js} +87 -7
  92. package/lib/src-CtkIX_Gg.js +427 -0
  93. package/lib/{src-BTBm4OPD.js → src-iBJ2ysV9.js} +77 -14
  94. package/lib/{test-websocket-BLeEvybj.js → test-websocket-CQOSvBth.js} +17 -7
  95. package/lib/{test-websocket-DyeS50Tr.d.ts → test-websocket-GUTAkFQT.d.ts} +3 -1
  96. package/package.json +2 -1
  97. package/plugins/acryl-door/plugin.json +3 -0
  98. package/plugins/acryl-door/src/cli/acryl.ts +63 -6
  99. package/plugins/acryl-door/src/host/channel.ts +86 -9
  100. package/plugins/acryl-door/src/host/chat-tools.ts +8 -6
  101. package/plugins/acryl-door/src/host/door-file.ts +7 -2
  102. package/plugins/acryl-door/src/host/door.ts +128 -24
  103. package/plugins/acryl-door/src/host/operator-routes.ts +21 -1
  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 +14 -1
  107. package/plugins/acryl-door/src/index.ts +168 -30
  108. package/plugins/acryl-door/src/page/base.ts +32 -0
  109. package/plugins/acryl-door/src/page/channel.ts +3 -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 +32 -4
  113. package/plugins/acryl-door/src/page/driver/snapshot.ts +5 -2
  114. package/plugins/acryl-door/src/page/index.ts +41 -2
  115. package/plugins/acryl-door/src/page/outline.ts +56 -0
  116. package/plugins/acryl-door/src/page/protocol.ts +4 -0
  117. package/plugins/acryl-door/src/page/snapshot-text.ts +2 -1
  118. package/plugins/acryl-node-server/src/adapter/listener.ts +4 -0
  119. package/plugins/acryl-node-server/src/adapter/raw.ts +18 -0
  120. package/plugins/acryl-node-server/src/adapter/websocket.ts +15 -9
  121. package/plugins/acryl-node-server/src/client-modules.ts +7 -1
  122. package/plugins/acryl-node-server/src/index.ts +304 -16
  123. package/plugins/acryl-node-server/src/upgrade-hub.ts +2 -2
  124. package/plugins/acryl-page/plugin.json +12 -0
  125. package/plugins/acryl-page/src/index.ts +163 -0
  126. package/plugins/acryl-router/src/service.ts +77 -14
  127. package/plugins/acryl-router-http/src/index.ts +15 -1
  128. package/plugins/acryl-router-http/src/serve.ts +31 -0
  129. package/plugins/acryl-web-server/plugin.json +14 -0
  130. package/plugins/acryl-web-server/src/index.ts +164 -0
  131. package/plugins/agent/agent.ts +38 -7
  132. package/plugins/agent/index.ts +1 -1
  133. package/plugins/agent/model.ts +10 -2
  134. package/plugins/agent/tools.ts +9 -3
  135. package/plugins/agent-panel/client/describe.ts +57 -0
  136. package/plugins/agent-panel/client/driver-pick.ts +22 -0
  137. package/plugins/agent-panel/client/frame.ts +51 -0
  138. package/plugins/agent-panel/client/main.ts +238 -26
  139. package/plugins/agent-panel/drivers.ts +7 -2
  140. package/plugins/agent-panel/headless.ts +5 -2
  141. package/plugins/agent-panel/index.ts +146 -57
  142. package/plugins/agent-panel/mount.ts +27 -0
  143. package/plugins/agent-panel/visitors.ts +231 -0
  144. package/plugins/builder/index.ts +13 -35
  145. package/plugins/builder/package.ts +186 -0
  146. package/plugins/builder/plugin.json +3 -1
  147. package/plugins/desktop/frame.ts +231 -0
  148. package/plugins/desktop/launch.ts +44 -9
  149. package/plugins/desktop/main.ts +100 -32
  150. package/plugins/desktop/window.ts +21 -4
  151. package/plugins/driver-pty/client/terminal.ts +4 -1
  152. package/plugins/driver-pty/index.ts +38 -11
  153. package/plugins/driver-pty/spawn.ts +38 -0
  154. package/plugins/driver-pty/terminal.ts +2 -0
  155. package/plugins/extensions/index.ts +47 -18
  156. package/plugins/extensions/plugin-store.ts +27 -0
  157. package/plugins/extensions/plugin.json +1 -1
  158. package/plugins/extensions/resolve.ts +13 -0
  159. package/plugins/extensions/stage.ts +15 -5
  160. package/plugins/feedback/client.d.ts +22 -0
  161. package/plugins/feedback/client.js +471 -0
  162. package/plugins/feedback/index.ts +143 -0
  163. package/plugins/feedback/plugin.json +11 -0
  164. package/plugins/feedback/store.ts +307 -0
  165. package/plugins/home/index.ts +122 -0
  166. package/plugins/home/plugin.json +11 -0
  167. package/plugins/instance/index.ts +6 -0
  168. package/plugins/manifest/app-plugins.ts +86 -0
  169. package/plugins/manifest/index.ts +12 -2
  170. package/plugins/manifest/plugin.json +1 -1
  171. package/plugins/manifest/snapshot.ts +275 -0
  172. package/plugins/openai/index.ts +64 -5
  173. package/plugins/openai/prompt.ts +23 -0
  174. package/plugins/plugin-share/README.md +51 -0
  175. package/plugins/plugin-share/index.ts +467 -0
  176. package/plugins/plugin-share/plugin.json +15 -0
  177. package/plugins/plugin-share/publish.ts +65 -0
  178. package/plugins/plugin-share/pull-check.ts +129 -0
  179. package/plugins/plugin-share/pulled-records.ts +70 -0
  180. package/shared/AGENTS.core.md +36 -16
  181. package/shared/skills/acryl-add-ui/SKILL.md +19 -0
  182. package/shared/skills/acryl-app/SKILL.md +13 -0
  183. package/shared/skills/acryl-build-plugin/SKILL.md +22 -0
  184. package/shared/skills/acryl-change-plugin/SKILL.md +14 -0
  185. package/shared/skills/acryl-diagnose-plugin/SKILL.md +13 -0
  186. package/shared/skills/acryl-fix-plugin/SKILL.md +13 -0
  187. package/shared/skills/acryl-remove-plugin/SKILL.md +12 -0
  188. package/shared/skills/acryl-share-plugin/SKILL.md +16 -0
  189. package/shared/skills/cordis-plugin/SKILL.md +26 -0
  190. package/templates/agent/.gitattributes +2 -0
  191. package/templates/agent/AGENTS.md +1 -1
  192. package/templates/agent/blend.yaml +6 -0
  193. package/templates/agent/gitignore +1 -0
  194. package/templates/agent/package.json +1 -0
  195. package/templates/agent/src/app.ts +154 -33
  196. package/templates/agent/src/frame.ts +17 -0
  197. package/templates/agent/src/main.ts +5 -3
  198. package/templates/agent/src/routes.ts +38 -19
  199. package/templates/agent/template.json +3 -0
  200. package/templates/agent/test/app.test.ts +45 -3
  201. package/templates/blank/.gitattributes +2 -0
  202. package/templates/blank/AGENTS.md +3 -2
  203. package/templates/blank/blend.yaml +11 -0
  204. package/templates/blank/gitignore +1 -0
  205. package/templates/blank/package.json +1 -0
  206. package/templates/blank/src/app.ts +100 -29
  207. package/templates/blank/src/door.ts +7 -0
  208. package/templates/blank/src/first-page.ts +5 -0
  209. package/templates/blank/src/frame.ts +17 -0
  210. package/templates/blank/src/routes.ts +65 -8
  211. package/templates/blank/template.json +14 -1
  212. package/templates/blank/test/app.test.ts +103 -16
  213. package/templates/chat/.gitattributes +2 -0
  214. package/templates/chat/blend.yaml +2 -1
  215. package/templates/chat/gitignore +1 -0
  216. package/templates/chat/package.json +1 -0
  217. package/templates/chat/src/app.ts +72 -22
  218. package/templates/chat/src/chat-app.ts +11 -2
  219. package/templates/chat/src/client/chat.tsx +4 -2
  220. package/templates/chat/src/frame.ts +17 -0
  221. package/templates/chat/src/page.tsx +6 -4
  222. package/templates/chat/src/routes.ts +14 -4
  223. package/templates/chat/src/runtime.ts +9 -3
  224. package/templates/chat/template.json +3 -1
  225. package/templates/chat/test/chat.test.ts +46 -1
  226. package/templates/chat/test/server.test.ts +17 -3
  227. package/templates/nodejs/.gitattributes +2 -0
  228. package/templates/nodejs/blend.yaml +2 -1
  229. package/templates/nodejs/gitignore +1 -0
  230. package/templates/nodejs/package.json +1 -0
  231. package/templates/nodejs/src/app.ts +76 -21
  232. package/templates/nodejs/src/frame.ts +17 -0
  233. package/templates/nodejs/src/page.tsx +3 -3
  234. package/templates/nodejs/src/routes.ts +32 -13
  235. package/templates/nodejs/template.json +3 -1
  236. package/templates/nodejs/test/app.test.ts +38 -3
  237. package/templates/nodejs/test/server.test.ts +17 -3
  238. package/templates/notes/.gitattributes +2 -0
  239. package/templates/notes/blend.yaml +2 -1
  240. package/templates/notes/gitignore +1 -0
  241. package/templates/notes/package.json +1 -0
  242. package/templates/notes/src/app.ts +72 -22
  243. package/templates/notes/src/frame.ts +17 -0
  244. package/templates/notes/src/notes-app.ts +24 -17
  245. package/templates/notes/src/routes.ts +11 -4
  246. package/templates/notes/src/runtime.ts +9 -3
  247. package/templates/notes/src/views.tsx +26 -17
  248. package/templates/notes/template.json +3 -1
  249. package/templates/notes/test/notes.test.ts +39 -1
  250. package/templates/notes/test/server.test.ts +17 -3
  251. package/templates/todo/.gitattributes +2 -0
  252. package/templates/todo/blend.yaml +3 -0
  253. package/templates/todo/gitignore +1 -0
  254. package/templates/todo/package.json +1 -0
  255. package/templates/todo/src/app.ts +81 -27
  256. package/templates/todo/src/door.ts +7 -0
  257. package/templates/todo/src/frame.ts +17 -0
  258. package/templates/todo/src/page.ts +13 -6
  259. package/templates/todo/src/todo.ts +18 -6
  260. package/templates/todo/template.json +11 -1
  261. package/templates/todo/test/todo.test.ts +67 -9
  262. package/lib/src-LX0E4ec4.js +0 -117
  263. 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
@@ -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
@@ -55,7 +55,7 @@ bun create acrylblends@latest my-app --template nodejs
55
55
  | `[source]` | A template from outside the package: `github:owner/repo[#ref]`, `@scope/name[@version]` or a packed `.tgz` file. See [Templates from a repository or a package](#templates-from-a-repository-or-a-package). | `github:acme/starter` |
56
56
  | `--template <template>` | One of `blank`, `nodejs`, `notes`, `chat`, `todo`, `agent` (the same list as `acrylblends init --template`; `acryl-app` is accepted as `agent`). Skips the template question; a bare name after the directory means the same. | `--template notes` |
57
57
  | `--from <id \| source>` | A starter from the registry by its id (`acrylblends.notes-desktop`), or any source above. Only starters that declare `runtime: acrylblends` are made; an ACRYL app starter is refused. See [Starters from the registry](#starters-from-the-registry). | `-- --from acrylblends.notes-desktop` |
58
- | `--registry <source>` | Read the ids from this registry instead of the public one: `github:owner/repo` or a folder, with an `index.json` (at its root or in `registry/`). | `-- --from login.thing --registry github:acryldev/workshop-2026-11-20` |
58
+ | `--registry <source>` | Read the ids from this registry instead of the public one: `github:owner/repo`, an `https://` address, or a folder, with an `index.json` (at its root or in `registry/`). | `-- --from login.thing --registry github:acryldev/workshop-2026-11-20` |
59
59
  | `--install` | Install the dependencies with the package manager after creating the project. For a template from a source, the install scripts it will run are listed first. | `--install` |
60
60
  | `--pm <packageManager>` | The package manager for `--install`: `npm`, `pnpm`, `yarn` or `bun`. Defaults to the one that started the initializer. | `--pm pnpm` |
61
61
  | `--yes`, `-y` | Ask nothing: use `nodejs` unless `--template` is given, and the directory `acryl-app`. | `-y` |
@@ -78,7 +78,9 @@ npm run dev
78
78
  - A starter with `runtime: acrylblends` is an `acrylblends` app: this command downloads its folder, gives the manifest to the new app (`metadata.id: acrylblends.my-notes`, `visibility: private`; the starter's id and licence stay the starter's), checks it for anything that looks like a secret, and writes it. Nothing in it is installed or run: `npm install` is yours to run, and the dependencies of the starter (a desktop starter brings `electron`) are in its `package.json`.
79
79
  - A starter for the ACRYL app (`runtime: acryl`, the older `acryl.*` entries) is refused with one line that says so, because its plugins run only inside the ACRYL app. Nothing is written.
80
80
  - An unknown id lists the starters this command can make.
81
- - The ids come from `https://acrylblends.github.io/registry/index.json`. `--registry github:owner/repo` reads another registry with the same layout (`index.json` and `blends/<id>/`), a team's own or a workshop's; `--registry ./folder` reads one on disk.
81
+ - The ids come from `https://acrylblends.github.io/registry/index.json`, and only the starter you asked for is downloaded, as one archive checked against the integrity in the index; an archive that does not match is refused. When the site cannot give the starter, the registry's repository is read instead. `--registry github:owner/repo` reads another registry with the same layout (`index.json` and `blends/<id>/`), a team's own or a workshop's; `--registry ./folder` reads one on disk.
82
+
83
+ A registry on any static host works with `--registry https://...`, if its `index.json` names an `archive` and an `integrity` for each entry: `workshop-registry/scripts/registry-archives.mjs` in this repository writes both when you deploy, on the copy you publish.
82
84
 
83
85
  To publish a starter of your own, see [the registry README](https://github.com/acrylblends/acrylblends.github.io/tree/main/registry): the folder of your app under `blends/<id>/` with an `acryl.template.json`, in a pull request.
84
86
 
@@ -1,14 +1,15 @@
1
- # An app that builds and drives itself: the ACRYL Blends workshop
1
+ # Build your app inside the ACRYL frame: the ACRYL Blends workshop
2
2
 
3
- Ninety minutes, from an empty folder to an app whose interface a coding agent built from inside it, then drove the way a person would: it opens the
4
- sidebar, ticks a card, changes a setting. The same app then runs in a desktop window, where the agent drives that too, and you publish it as a starter
5
- other people can pull. **Acryl** is the small web framework underneath (a handler takes a `Request` and returns a `Response`); **ACRYL Blends** is the app
6
- around it: a folder of Cordis plugins with a `blend.yaml`, running on your machine, with an agent living inside its panel.
3
+ Ninety minutes, from an empty folder to an app that opens in ACRYL's own IDE: projects on the left, your app's page in the middle, files,
4
+ changes, checks and terminals on the right, a chat model that works on your app beside it, and Claude, Codex or Pi running in terminal tabs in
5
+ the same folder. **Acryl** is the small web framework underneath (a handler takes a `Request` and returns a `Response`); **ACRYL Blends** is the
6
+ app around it: a folder of Cordis plugins with a `blend.yaml`, running on your machine, opened by the frame.
7
7
 
8
- Two things make this workshop different from clicking through a tutorial: you write very little code (the agent writes the interface, you direct and
9
- edit it), and the agent is not a sidebar chat about the code, it is a hand on the app.
8
+ The frame is the workshop's point. You do not edit a folder and alt-tab to a browser: your app is a page inside the workspace, the agents work in
9
+ the same folder the frame shows, and every change you or an agent makes is one restart away from the page.
10
10
 
11
- This guide is for **acrylblends 1.0.10 or newer**; `npm create acrylblends@latest` gives you that.
11
+ This guide is for **acrylblends 1.3.0 or newer**; `npm create acrylblends@latest` gives you that. An app you made with an older release gets the
12
+ frame with the upgrade in block 6.
12
13
 
13
14
  ## 0. Before you start (10 minutes)
14
15
 
@@ -19,7 +20,7 @@ npx acrylblends@latest preflight
19
20
  ```
20
21
 
21
22
  It ends with `Ready for the workshop.`, or with how many lines say `FIX`: run each `FIX` line, then the preflight again. `NOTE` lines are things the
22
- first blocks do without (`gh` is only needed in block 5).
23
+ first blocks do without.
23
24
 
24
25
  | | macOS | Windows | Linux |
25
26
  | --- | --- | --- | --- |
@@ -31,15 +32,18 @@ first blocks do without (`gh` is only needed in block 5).
31
32
  Install what is missing: Node from <https://nodejs.org> (the LTS), git from <https://git-scm.com>, the GitHub CLI from <https://cli.github.com> (`gh auth
32
33
  login` once), and one agent:
33
34
 
35
+ - **Claude Code**: <https://claude.com/claude-code>, then run `claude` once to log in.
34
36
  - **Codex**: `npm i -g @openai/codex`, then `codex login`. If a run answers `model_not_found`, your account does not have the default model: pick one
35
37
  your account supports (`/model` inside codex, or `model = "..."` in `~/.codex/config.toml`).
36
- - **Claude Code**: <https://claude.com/claude-code>, then run `claude` once to log in.
37
- - **pi with DeepSeek**: `npm i -g @earendil-works/pi-coding-agent`, and set your DeepSeek key in the terminal you will start the app from (the panel
38
- starts pi from the app, so pi sees that terminal's environment). The preflight checks the key: `PASS agent pi (DeepSeek key found)`.
38
+ - **pi with DeepSeek**: `npm i -g @earendil-works/pi-coding-agent`, and set your DeepSeek key in the terminal you start the app from (the terminal
39
+ tabs inherit that environment). The preflight checks the key: `PASS agent pi (DeepSeek key found)`.
40
+
41
+ | macOS and Linux | Windows PowerShell | Windows cmd.exe |
42
+ | --- | --- | --- |
43
+ | `export DEEPSEEK_API_KEY=sk-...` | `$env:DEEPSEEK_API_KEY="sk-..."` | `set DEEPSEEK_API_KEY=sk-...` |
39
44
 
40
- | macOS and Linux | Windows PowerShell | Windows cmd.exe |
41
- | --- | --- | --- |
42
- | `export DEEPSEEK_API_KEY=sk-...` | `$env:DEEPSEEK_API_KEY="sk-..."` | `set DEEPSEEK_API_KEY=sk-...` |
45
+ **One model key for the chat.** The frame's chat needs a model: a DeepSeek API key from <https://platform.deepseek.com> is the shortest path (you add
46
+ it in block 3). A Claude or ChatGPT subscription works too, through **Sign in with an account** on the same Settings page.
43
47
 
44
48
  No prior knowledge of ACRYL, Cordis or Blends is needed; every new word is explained where it appears.
45
49
 
@@ -52,178 +56,169 @@ Make the workshop folder:
52
56
  **On Windows.** Windows PowerShell 5.1 (the one Windows ships) has no `&&`: where this guide joins two commands with `&&`, type them as two lines, or join
53
57
  them with `;`. PowerShell 7 (`pwsh`) accepts `&&`. In cmd.exe, `Ctrl-C` asks `Terminate batch job (Y/N)?`: answer `Y`.
54
58
 
55
- **The agent setting that matters all day.** The app's agent is configured to act rather than to describe: when you ask for something, it writes the
56
- files, installs the plugin and clicks through the result itself. If your agent stops to ask "shall I proceed?", answer "do it now" and it continues; that
57
- one sentence is the difference between watching and building.
59
+ **The agent setting that matters all day.** The agents are configured to act rather than to describe: when you ask for something, they write the
60
+ files and check the result. If your agent stops to ask "shall I proceed?", answer "do it now" and it continues; that one sentence is the difference
61
+ between watching and building.
58
62
 
59
63
  ## The path
60
64
 
61
65
  | Minutes | Block | What you get |
62
66
  | --- | --- | --- |
63
- | 0-10 | 0. Before you start, 1. The core in one breath | a checked machine, and an app with a route of your own, answering in a browser |
64
- | 10-40 | 2. The agent builds the interface | a board page with cards, a sidebar and live counts, written by the agent from inside |
65
- | 40-60 | 3. The agent drives the app | the agent opening the sidebar and ticking a card while you watch |
66
- | 60-75 | 4. The same app in a window | the app and its agent in a desktop window, driven there too, with its menu and settings |
67
- | 75-90 | 5. Deploy it, then publish it | the app running as a server, then listed in the registry |
68
-
69
- > **Checkpoint 10 minutes:** your route answers in the browser.
70
- > **Checkpoint 40 minutes:** the agent's board is on screen.
71
- > **Checkpoint 60 minutes:** the agent has clicked through the page by itself.
72
- > **Checkpoint 75 minutes:** the same app is in a desktop window.
73
-
74
- ## 1. The core in one breath (10 minutes)
67
+ | 0-10 | 0. Before you start | a checked machine, one model key, a folder |
68
+ | 10-20 | 1. Create the app, open the frame | the app running and shown inside the ACRYL frame |
69
+ | 20-25 | 2. Your first change | the app's page in the frame showing your edit |
70
+ | 25-30 | 3. Connect your model in Settings > Models | a chat that answers |
71
+ | 30-50 | 4. Chat: your model builds a page | a board page the model wrote and you saw at /app/board |
72
+ | 50-65 | 5. A coding agent in a terminal tab | Claude, Codex or Pi working in the app's folder |
73
+ | 65-80 | 6. Upgrade an older app onto the frame | an app from before today, opened by the frame |
74
+ | 80-90 | 7. Publish it as a starter | the app listed in the workshop registry |
75
+
76
+ > **Checkpoint 20 minutes:** the app's page is in the frame.
77
+ > **Checkpoint 30 minutes:** the chat answers.
78
+ > **Checkpoint 50 minutes:** the model's board is at /app/board.
79
+ > **Checkpoint 65 minutes:** an agent in a terminal has changed the app.
80
+
81
+ ## 1. Create the app; the frame opens on it (10 minutes)
75
82
 
76
83
  ```sh
77
- npm create acrylblends@latest my-app agent
84
+ npm create acrylblends@latest my-app agent -- --desktop
78
85
  cd my-app
79
86
  npm install
80
87
  npm run dev
81
88
  ```
82
89
 
83
- Open the address it prints. You get a small app with a button in the corner, "Ask the agent": it opens the panel, the agent that will build and drive
84
- this app. It is the `agent` template.
85
-
86
- ![The app's first page with the agent panel open on the right; the page follows the system theme, dark here](/docs-assets/workshop/s1-first-page.webp)
87
-
88
- The page follows your system's light or dark setting, so on a dark-mode machine it is dark as above. For the next two minutes forget the panel: an
89
- Acryl app is a function from a request to a response.
90
+ `npm install` is bigger than a framework-only app: it brings the frame and the chat engine (about 500 MB together, much less on a warm package
91
+ cache). `npm run dev` starts the app inside the frame and prints one line:
90
92
 
91
- Open `src/routes.ts` and add one line to the chain, just above `.get('/health', …)`, keeping the indentation of the lines around it:
92
-
93
- ```ts
94
- .get('/hello', (c) => c.json({ hello: 'workshop' }))
93
+ ```text
94
+ acrylblends host: http://127.0.0.1:3489/?token=...
95
95
  ```
96
96
 
97
- Save: the terminal prints `Restarting 'src/main.ts'` (Node 24 and 26 print `Change detected …` on the line before it; Node 22 prints only the
98
- `Restarting` line), and `/hello` answers `{"hello":"workshop"}`. Stop the server (`Ctrl-C`; in cmd.exe answer `Y`), run `npm test` and `npm run check`:
99
- both pass (`npm test` reports 14 passing tests). That is the whole core: a route, a test, a typecheck.
97
+ Open that address (it is a free port on your machine; never a fixed one). It stays the same every time you start the app, and it is the way back in
98
+ later: `npx acrylblends open` prints it again while the frame is running. The first time, DeepSeek Harness shows a **Preview Notice**: press **Continue**. Then the frame opens **on your app**: the page in the middle is `my-app`'s own page, in a tab named after the app.
100
99
 
101
- **Stuck?** A busy port means the app printed the next free one; use that address. `npm test` failing on your line names the file and the type.
100
+ ![The frame on first run: projects on the left with the app selected, the app's page in the canvas, the tab strip with the app's tab](/docs-assets/workshop/s1-frame.webp)
102
101
 
103
- ## 2. The agent builds the interface (30 minutes)
102
+ The three columns are ACRYL's IDE:
104
103
 
105
- Start the app (on pi, in the terminal where `DEEPSEEK_API_KEY` is set):
104
+ - **Left:** your workspaces and projects. `my-app` is selected; the account row above and **Settings** below.
105
+ - **Middle:** tabs. `my-app` is your app's page; the `+` at the left of the tab strip opens more (terminal, browser, files, chat, agents).
106
+ - **Right:** open it with the panel button at the top right (or `Cmd/Ctrl+B`): **Files**, **Changes**, **Review**, **Checks**, **Comments** and a
107
+ terminal. The bottom bar is the terminal dock.
106
108
 
107
- ```sh
108
- npm run dev
109
- ```
109
+ The app's page also has an agent of its own: **Ask the agent** at the bottom right opens the app's panel (the offline agent unless the app is given
110
+ a model). The frame's chat in the next blocks is the tool you will use; the panel is there for the app to ship with.
110
111
 
111
- Open the address it prints and click "Ask the agent". Ask it, in one message:
112
+ **Stuck?** A busy port means the terminal printed a different address; use that. `npm install` failing on the native terminal package needs a C++
113
+ toolchain: on macOS `xcode-select --install`, on Windows the "Desktop development with C++" workload of Visual Studio Build Tools, on Ubuntu
114
+ `sudo apt install build-essential python3`.
112
115
 
113
- > Do it now, without asking for approval. Build a board page at /board: three columns (backlog, doing, done) with cards that have a checkbox to mark
114
- > them done, a sidebar with filters (all, mine, done) and a count on each filter, a button that opens and closes the sidebar, and a header button
115
- > "New card" that adds one. Use the app's own state so the counts update live. Build it as a plugin in plugins/, install it into the running app, then
116
- > go to /board yourself and check it looks right, and tell me what you saw.
116
+ ## 2. Your first change, seen at /app (5 minutes)
117
117
 
118
- What happens next is the workshop: the agent reads `AGENTS.md` and `docs/framework` (both are in your app), writes a Cordis plugin under `plugins/`,
119
- installs it into the running app as an extension (`.acryl/bin/acryl plugin add plugins/board`), and goes to `/board` through the door to look at what it
120
- built. The panel shows `Working... m:ss` while it runs; with pi the build took about six minutes. The panel is on every page of the app, so when the
121
- agent moves the page to `/board`, the panel comes along and keeps following the run.
118
+ Open the right panel (**Files**), expand `src`, click `routes.ts`. Find the sentence the page shows ("This app runs an agent unless it is switched
119
+ off...") and change it to something that is yours. Press **Save** in the editor's bar (or `Cmd/Ctrl+S`).
122
120
 
123
- ![The panel while the agent builds: the request, then Working... 0:04 below it](/docs-assets/workshop/s2-panel-building.webp)
121
+ The running app does not pick a source change up by itself. Stop the host with `Ctrl-C` in the terminal where `npm run dev` runs (in cmd.exe answer
122
+ `Y`), then start it again:
124
123
 
125
- ![The board the agent built: three columns with cards, and a sidebar with filters and counts](/docs-assets/workshop/s3-board.webp)
126
-
127
- Then make it yours: open the plugin it wrote, change a colour or a label, save, and watch the app reload. The code is in your folder and belongs to you;
128
- the agent wrote it, you own it. Every agent builds a slightly different board: yours may need a title typed before "New card" adds one, or keep the
129
- sidebar always open.
130
-
131
- **Stuck?** If the agent describes the plan and stops, tell it "do it now, without asking for approval". An app made with an older release gets the
132
- current panel and fixes with `npx acrylblends@latest upgrade`.
133
-
134
- ## 3. The agent drives the app (20 minutes)
124
+ ```sh
125
+ npm run dev
126
+ ```
135
127
 
136
- The same agent, in the same panel, now uses the door: a channel into the running page with `look` (a snapshot of what is on screen, with refs) and
137
- `act` (click, type, select, press, scroll, wait, and `navigate` or `reload` the page).
128
+ The frame reconnects on its own, on the same address (the port is stable per app), in a few seconds. If a chat tab opened in front, press the
129
+ `my-app` tab: the page shows your sentence. That is the whole development loop for the rest of the day: edit, restart, look.
138
130
 
139
- Ask it:
131
+ ```sh
132
+ npm test
133
+ npm run check
134
+ ```
140
135
 
141
- > Do it now, without asking for approval. On /board, use the door to open the sidebar, tick one card with its checkbox, set the filter to done, then
142
- > look again and tell me what the counts say.
136
+ Both pass: the app is TypeScript, with tests and a type check, and the scaffold made the folder a git repository, so **Changes** shows what you
137
+ edited.
143
138
 
144
- Watch the page: the card ticks, the filter changes, the counts move. While each action runs, a bar at the bottom of the page says `Agent is driving:
145
- clicking` (or looking, typing) with a Stop button; it shows only for that moment, so most of the time you see the page change and the panel's `Working...`
146
- line. The panel's own Stop button ends the whole run. Every action is a line in `.acryl/audit/` afterwards. With pi the drive was six door calls in
147
- under two minutes, most of it the model thinking.
139
+ **Stuck?** If the page looks unchanged, the host did not restart (the terminal says `Restarting` or it is waiting on `Ctrl-C`). If the frame still
140
+ says `Reconnecting...` after ten seconds, reload the tab: the address is the same one it was opened with. If the tab was closed, `npx acrylblends open`
141
+ in the app's folder prints the address again.
148
142
 
149
- Then ask it to check its own work in the way a person would:
143
+ ## 3. Connect your model: Settings > Models (5 minutes)
150
144
 
151
- > Do it now, without asking for approval. Click "New card" twice, look at the board, and tell me whether the counts agree.
145
+ Press **Settings** at the bottom of the left column, then **Models** in its sidebar. The page lists DeepSeek as a provider: paste your API key into
146
+ **API key** and press **Apply**. It answers `Saved DeepSeek (deepseek-official).`; the key goes to the frame's own credentials store, never into the
147
+ app folder.
152
148
 
153
- If your board needs a title before "New card" adds a card, the agent says so, and the counts agree because nothing was added; ask it to type a title
154
- first if you want to see them move.
149
+ ![Settings > Models with the DeepSeek key field](/docs-assets/workshop/s2-settings-models.webp)
155
150
 
156
- **Stuck?** If the agent says it cannot see a page, reload the app's tab: the page connects to the door when it loads.
151
+ Then reload the frame (`Cmd/Ctrl+R`): the page you already had open picks the key up on its next load. A Claude or ChatGPT subscription instead of a
152
+ key: **Sign in with an account** on the same page.
157
153
 
158
- ## 4. The same app in a desktop window (15 minutes)
154
+ If the frame greets you with DeepSeek Harness's **Add an API key to get started** card first, you can paste the key there and press **Save and
155
+ continue**, or press **Configure later** and use Settings > Models; both write the same store.
159
156
 
160
- **First close the browser tab of the app.** While a browser tab of the app is open, the agent's page actions can go to that tab instead of the
161
- window (the door picks a page when the agent does not name a window), and you would watch an unchanged window. Keep `npm run dev` running.
157
+ **Stuck?** "Loading the provider directory failed" means the host is not answering; start `npm run dev` again. A key that stays red is usually an
158
+ extra space: paste it again.
162
159
 
163
- ```sh
164
- npx acrylblends add desktop
165
- npm install
166
- npm run desktop
167
- ```
160
+ ## 4. Chat: your model works on the app (20 minutes)
168
161
 
169
- The first `npm run desktop` downloads Electron (about 200 MB), then the window attaches to the running server and says so:
162
+ Press `+` at the left of the tab strip and choose **AcrylDSH Chat**; on the `my-app` row in the left pane, **New chat on my-app** does the same and
163
+ binds the chat to the app's folder (the chat's workspace selector says `my-app`). Then ask, in one message:
170
164
 
171
- ```text
172
- desktop: attached to the app already running from this folder at http://127.0.0.1:3288 (its server keeps running when the window closes)
173
- desktop: windows and menu are available to the door (acryl window list, acryl menu list)
174
- ```
165
+ > Do it now, without asking for approval. Build a board page at /board in this app: three columns (backlog, doing, done) with cards that have a
166
+ > checkbox to mark them done, a sidebar with filters (all, mine, done) and a count on each filter, a button that opens and closes the sidebar, and
167
+ > a header button "New card" that adds one. Use the app's own state so the counts update live. Read AGENTS.md and the app's docs first. When you are
168
+ > done, tell me what you changed.
175
169
 
176
- A window opens on the same app, from the same server: your board, your sidebar, your panel. First drive the page in the window the way you did in block
177
- 3: open the panel there and ask the agent to open the sidebar and change a filter. Look and act work the same way through the window.
170
+ The chat writes into `my-app` (watch the **Changes** panel fill), and the app's page at `/app` shows it after the loop from block 2: `Ctrl-C`, `npm
171
+ run dev`, the frame reconnects. The board is at `/app/board`: type the address in the app tab's bar (the same address with `/board` at the end) and
172
+ press **Go**.
178
173
 
179
- ![The agent driving the board inside the desktop window: the Done filter it just set, and the panel's Working... line](/docs-assets/workshop/s4-agent-drives-window.webp)
174
+ ![The AcrylDSH Chat tab with the request, beside the app](/docs-assets/workshop/s3-chat.webp)
180
175
 
181
- Then hand the agent the window itself, not only the page inside it. Ask:
176
+ Every model builds a slightly different board: yours may need a title typed before "New card" adds one, or keep the sidebar always open.
182
177
 
183
- > List the windows that are open, open a second one with the board in it, open the app's settings from the menu, and switch the appearance to dark.
178
+ **Stuck?** If the chat asks for a model, block 3 did not finish (or the page was not reloaded after Apply). If the model describes the plan and
179
+ stops, reply "do it now, without asking for approval".
184
180
 
185
- The agent lists the windows, opens a second one, clicks the menu's Settings item, and changes the app's appearance on the settings page; each shows on
186
- screen as it happens. The Settings item is in the application menu on macOS (`my-app > Settings...`, `Cmd+,`) and the first item of the File menu on
187
- Windows and Linux (`Ctrl+,`); it opens `/settings` in a window of its own.
181
+ ## 5. A coding agent in a terminal tab (15 minutes)
188
182
 
189
- The appearance is saved for the whole app. The app's own pages (`/`, `/settings`) use it; a window that is already open picks it up when it reloads, so
190
- ask the agent "reload window 1 and look at it" to see the change there. On a machine already in dark mode, dark looks like before: pick Light to see
191
- it change. A page the agent built (the board) follows the system theme unless you ask the agent to follow the app's appearance too.
183
+ Press `+` and choose **Claude**, **Codex** or **Pi** (or **New Terminal** and type the command yourself). The tab starts the agent in the app's
184
+ folder: the terminal's prompt is `my-app`, and `pwd` prints the folder. Ask it, in the terminal:
192
185
 
193
- ![Two desktop windows: window 1 on the app's page in the dark appearance, and the Settings window showing Saved: Dark](/docs-assets/workshop/s5-two-windows.webp)
186
+ > Do it now, without asking for approval. Add a GET /time route that returns the current time as JSON, and a line on the app's page that shows it.
187
+ > Then check it at http://127.0.0.1:3489/app/time.
194
188
 
195
- **Tip.** `navigate` answers with the status: a `404` means the app does not serve that path, and you can navigate straight back to one it does.
189
+ The port in that address is the one the frame printed. The agent edits the files, and the same loop shows them: `Ctrl-C`, `npm run dev`, the frame
190
+ reconnects, the `my-app` tab.
196
191
 
197
- Close the windows when you are done. The last window does not close through the door without `--force` (closing it ends the desktop app), so close it
198
- yourself or tell the agent it may.
192
+ An agent that works in this folder can also use the app's **door**, the page channel the app carries in development: `.acryl/bin/acryl look` prints
193
+ what is on the page with refs, and `act` clicks, types, selects, presses, scrolls, waits, navigates and reloads. Ask the terminal agent to look at
194
+ the page before it tells you it is done; the app's own docs (`AGENTS.md`, `plugins/acryl-door`) say how.
199
195
 
200
- **Stuck?** On Ubuntu 23.10+ the launch starts with `--no-sandbox` and says why; the AppArmor route is in
201
- `docs/framework/getting-started/desktop.md`. If the agent reports success but the window did not change, a browser tab of the app is still open: close
202
- it and ask again.
196
+ **Stuck?** An agent that says the terminal is not a TTY needs the tab, not a script. If the agent cannot log in, sign in in a terminal first
197
+ (`claude`, `codex login`, pi with `DEEPSEEK_API_KEY`), then open the tab again.
203
198
 
204
- ## 5. Deploy it, then publish it (15 minutes)
199
+ ## 6. Upgrade an older app onto the frame (10 minutes)
205
200
 
206
- **Deploy the app without its agent.** The agent, the panel and the terminal driver are development tools: with `NODE_ENV=production` they start
207
- nothing, while the app's own routes, plugins, state and database run as always. That is the app you put on a server. Stop `npm run dev` first.
201
+ An app made with an older acrylblends runs the framework only. The current release moves it onto the frame-hosted layout: the generated launcher,
202
+ the frame's row and the app's plugins beside it, the mount config. **Your source stays yours**: the upgrade only touches the files acrylblends
203
+ generated, plus the library plugins the app carries.
208
204
 
209
205
  ```sh
210
- NODE_ENV=production npm start
206
+ cd old-app
207
+ npx acrylblends@latest upgrade
208
+ npm install
209
+ npm run dev
211
210
  ```
212
211
 
213
- (The command is the app's own `start` script; on Windows, `set NODE_ENV=production&& npm start` in cmd, or `$env:NODE_ENV="production"; npm start` in
214
- PowerShell.) It prints `extensions (read-only): board`: the board the agent installed runs, and nothing can install or remove a plugin.
212
+ The report names every file it changed and ends with a `frame` line (for an app that already has the frame: `everything is up to date`). An app made
213
+ today answers "everything is up to date" too. An app from a release **before 0.7.8** cannot start at all (its `src/main.ts` imports a `plugins/`
214
+ folder that release did not write); the upgrade says so instead of touching it.
215
215
 
216
- That is the same app on any Node host: copy the folder (or clone the repository the app was saved to), run `npm install --omit=dev`, and start it with
217
- `NODE_ENV=production`. On its own the app listens on `127.0.0.1` at a port chosen from its folder; a server must say where to listen. The app reads
218
- `ACRYLBLENDS_HOST` and `ACRYLBLENDS_PORT` (not `PORT`):
219
-
220
- | macOS and Linux | Windows PowerShell | Windows cmd.exe |
221
- | --- | --- | --- |
222
- | `ACRYLBLENDS_HOST=0.0.0.0 ACRYLBLENDS_PORT=8080 NODE_ENV=production npm start` | `$env:ACRYLBLENDS_HOST="0.0.0.0"; $env:ACRYLBLENDS_PORT="8080"; $env:NODE_ENV="production"; npm start` | `set ACRYLBLENDS_HOST=0.0.0.0&& set ACRYLBLENDS_PORT=8080&& set NODE_ENV=production&& npm start` |
216
+ **Stuck?** "is not the previous release's scaffold" means you edited a generated file: run with `--diff` to see it, save your version aside, and
217
+ run again (or `--force`; the app's versions are backed up under `.acrylblends/upgrade-backup/`).
223
218
 
224
- Nothing in the app assumes ACRYL's own infrastructure: it is one Node process, one port, and its data in `.acrylblends/` next to it.
219
+ ## 7. Publish it as a starter (10 minutes, take-home)
225
220
 
226
- **Publish it as a starter.** Your app already is one: `blend.yaml` names it, `plugins/` holds its code.
221
+ Your app already is a starter: `blend.yaml` names it, `plugins/` holds its code.
227
222
 
228
223
  ```sh
229
224
  cd ~/acryl-workshop
@@ -241,29 +236,18 @@ commit` as two lines, or join them with `;`.)
241
236
  A check runs on the pull request and merges it: your starter is listed in about two minutes, and anyone can start from it with
242
237
  `npm create acrylblends@latest another-app -- --from <your-github-login>.my-app --registry github:acryldev/workshop-2026-11-20`.
243
238
 
244
- ![The workshop registry's page, listing the starters other people published](/docs-assets/workshop/s6-registry.webp)
245
-
246
- As an aside, for an app made before this release: `npx acrylblends@latest upgrade` moves the framework plugins it carries to the installed version,
247
- leaving your own code alone (an app you made today answers "everything is up to date").
248
-
249
- **Stuck?** The registry's check comments what to change; fix, commit, push again. `gh auth status` not logged in means `gh auth login`. A production app
250
- with no agent is correct: that is the design, not a missing piece.
239
+ **Stuck?** The registry's check comments what to change; fix, commit, push again. `gh auth status` not logged in means `gh auth login`.
251
240
 
252
241
  ## Browser only (WebBoxes.ai) TODO(M9)
253
242
 
254
- No local install? The same app, and the same agent building and driving it, will run as a hosted workspace: open it in a browser, pick a starter, and work
255
- in the same folders. Nothing to install, nothing to keep on your machine.
256
-
257
- The hosted workspace is milestone M9; until it is live this section is a stub. When it is, it says the address, the sign-in it needs, and the two or three
258
- clicks that replace block 1 here - and the one-click WebBoxes.ai deploy of an app from block 5, which is the same app on their infrastructure instead of
259
- yours.
243
+ No local install? The same app, and the same agents working on it, will run as a hosted workspace: open it in a browser, pick a starter, and work in
244
+ the same folders. Nothing to install, nothing to keep on your machine. Until it is live this section is a stub.
260
245
 
261
246
  ## Where next
262
247
 
263
- - **Read the docs you already have**: every app carries `docs/framework`, the same pages as <https://acrylblends.github.io/docs>. The door's verbs are in
264
- `agent/`, the data ports in `guides/data.md`, and `guides/production.md` says exactly what runs on a server.
265
- - **Teach the agent your app**: `AGENTS.md` is what it reads first; add your team's conventions there and it follows them in the next run.
266
- - **Swap a provider by editing one row**: SQLite to Postgres, the browser to a window, one agent to another in the panel's driver list.
248
+ - **Read the docs you already have**: every app carries `docs/framework`, the same pages as <https://acrylblends.github.io/docs>.
249
+ - **Teach the agents your app**: `AGENTS.md` is what they read first; add your team's conventions there and they follow them in the next run.
250
+ - **Swap a provider by editing one row**: SQLite to Postgres, the browser to a window, one agent to another in the frame's agent list.
267
251
  - **Bring your own tool**: <https://acrylblends.github.io/docs/guides/bring-your-own-tool> wraps an outside library as a provider of a port.
268
252
 
269
253
  ---
@@ -274,11 +258,13 @@ yours.
274
258
  | --- | --- |
275
259
  | The preflight prints `FIX` lines | run each one, then `npx acrylblends@latest preflight` again |
276
260
  | `npm create` fails or hangs | check the network; the facilitator has prepared apps |
261
+ | `npm install` fails building node-pty | install the C++ toolchain (block 1's **Stuck?**) and run it again |
277
262
  | A port is taken | use the address the app printed |
278
- | The agent cannot log in | `codex login` / `claude` / `pi` in a terminal, then retry in the panel |
279
- | Codex answers `model_not_found` | pick a model your account supports: `/model` in codex, or `model = "..."` in `~/.codex/config.toml` |
280
- | pi does not start or has no key | set `DEEPSEEK_API_KEY` in the terminal that runs `npm run dev`, restart it, and run the preflight |
281
- | The agent plans and stops | reply "do it now"; the config asks it to act, but a model sometimes waits |
263
+ | The frame says `Reconnecting...` | wait ten seconds; then `npx acrylblends open` and open the address it prints |
264
+ | Settings > Models shows no provider | the host is not running: `Ctrl-C`, `npm run dev` |
265
+ | The chat asks for a model | finish block 3, then reload the page |
266
+ | The model plans and stops | reply "do it now, without asking for approval" |
267
+ | An agent cannot log in | `codex login` / `claude` / pi with `DEEPSEEK_API_KEY`, then open the tab again |
268
+ | The app's page is unchanged after an edit | the host did not restart: `Ctrl-C`, `npm run dev` |
282
269
  | `&&` is an error in PowerShell | Windows PowerShell 5.1: type the two commands as two lines, or join them with `;` |
283
- | The agent says it acted, but the desktop window did not change | close the app's browser tab, then ask again |
284
270
  | Anything else | the **Stuck?** line of the step, then your facilitator |