acrylblends 1.0.10 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +15 -1
- package/dist/index.js +13 -7
- package/dist/index.js.map +1 -1
- package/docs/framework/api/summary.md +1 -1
- package/docs/framework/guides/production.md +20 -0
- package/docs/framework/workshop/README.md +177 -274
- package/docs/framework/workshop/facilitator.md +107 -84
- package/lib/{audit-Dw-siYTp.d.ts → audit-BFpULBCj.d.ts} +15 -3
- package/lib/cordis/door.d.ts +3 -1
- package/lib/cordis/door.js +11 -1
- package/lib/cordis/state.d.ts +3 -2
- package/lib/cordis/state.js +370 -6
- package/lib/door/host.d.ts +1 -1
- package/lib/door/host.js +1 -1
- package/lib/door/page.d.ts +10 -0
- package/lib/door/page.js +29 -7
- package/lib/{snapshot-text-BfEbEOjA.js → snapshot-text-BwM6T2nG.js} +36 -4
- package/package.json +1 -1
- package/plugins/acryl-door/src/host/channel.ts +42 -4
- package/plugins/acryl-door/src/host/door.ts +5 -0
- package/plugins/acryl-door/src/host/page-routes.ts +1 -1
- package/plugins/acryl-door/src/host/page-socket.ts +1 -1
- package/plugins/acryl-door/src/page/channel.ts +8 -0
- package/plugins/acryl-door/src/page/driver/driver.ts +17 -3
- package/plugins/acryl-door/src/page/index.ts +6 -1
- package/plugins/acryl-door/src/page/indicator.ts +14 -6
- package/plugins/acryl-state/plugin.json +4 -3
- package/plugins/acryl-state/src/client-source.ts +244 -0
- package/plugins/acryl-state/src/service.ts +33 -6
- package/plugins/acryl-state/src/socket.ts +96 -0
- package/plugins/agent-panel/client/main.ts +105 -55
- package/plugins/agent-panel/index.ts +42 -5
- package/plugins/instance/index.ts +6 -3
- package/templates/agent/AGENTS.md +3 -1
- package/templates/agent/src/routes.ts +38 -5
- package/templates/agent/test/app.test.ts +38 -2
- package/templates/chat/src/main.ts +1 -6
- package/templates/nodejs/src/main.ts +1 -6
- package/templates/notes/src/main.ts +1 -6
|
@@ -1,191 +1,164 @@
|
|
|
1
|
-
#
|
|
1
|
+
# An app that builds and drives itself: the ACRYL Blends workshop
|
|
2
2
|
|
|
3
|
-
Ninety minutes,
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
starter other people can pull from the registry.
|
|
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.
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
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.
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
This guide is for **acrylblends 1.0.10 or newer**; `npm create acrylblends@latest` gives you that.
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
| --- | --- | --- | --- |
|
|
16
|
-
| Node.js 22.19 or newer (24 LTS or 26 tested) | `node -v` | `node -v` | `node -v` |
|
|
17
|
-
| npm, which comes with Node | `npm -v` | `npm -v` | `npm -v` |
|
|
18
|
-
| git | `git --version` | `git --version` | `git --version` |
|
|
19
|
-
| a coding agent, logged in | `codex login status` or `claude --version` | same | same |
|
|
20
|
-
| a GitHub account and the `gh` CLI, logged in | `gh auth status` | same | same |
|
|
13
|
+
## 0. Before you start (10 minutes)
|
|
21
14
|
|
|
22
|
-
|
|
23
|
-
install GitHub.cli`, or <https://cli.github.com>), and one agent with `npm i -g @openai/codex` (then `codex login` once) or Claude Code. Run
|
|
24
|
-
`gh auth login` once, in any repository: step 10 publishes your app with a pull request. No prior knowledge of ACRYL, Cordis or Blends is needed;
|
|
25
|
-
every new word is explained where it appears.
|
|
26
|
-
|
|
27
|
-
Make a folder and open a terminal in it:
|
|
15
|
+
Run this first. It checks everything below and prints one line per check, with the exact command for anything missing:
|
|
28
16
|
|
|
29
17
|
```sh
|
|
30
|
-
|
|
18
|
+
npx acrylblends@latest preflight
|
|
31
19
|
```
|
|
32
20
|
|
|
33
|
-
|
|
21
|
+
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).
|
|
34
23
|
|
|
35
|
-
|
|
|
36
|
-
| --- | --- | --- |
|
|
37
|
-
|
|
|
38
|
-
|
|
|
39
|
-
|
|
|
40
|
-
|
|
|
41
|
-
| 30-38 | 4. Data: JSON, then SQLite *(optional)* | a counter kept in a file, then in SQL |
|
|
42
|
-
| 38-45 | 5. A desktop window | the same app as a window |
|
|
43
|
-
| 45-53 | 6. Pull a starter from the registry | someone else's app in your folder |
|
|
44
|
-
| 53-60 | 7. Create from a template | the six starters, one table, one run |
|
|
45
|
-
| 60-75 | 8. An agent builds a feature | your app changed by the agent, still running |
|
|
46
|
-
| 75-82 | 9. Upgrade | the app moved to the current framework |
|
|
47
|
-
| 82-90 | 10. Publish it | your app as a registry starter |
|
|
48
|
-
|
|
49
|
-
> **Checkpoint 15 minutes:** your app answers in a browser. Without that, read the "Stuck?" line of step 1.
|
|
50
|
-
> **Checkpoint 45 minutes:** your app is open in a desktop window. Behind? Step 4 is the optional one; skip it and carry on.
|
|
51
|
-
> **Checkpoint 75 minutes:** the agent's page is live. Still waiting? Give it five more minutes, then skip step 9.
|
|
52
|
-
|
|
53
|
-
## 1. Create and run (5 minutes)
|
|
24
|
+
| | macOS | Windows | Linux |
|
|
25
|
+
| --- | --- | --- | --- |
|
|
26
|
+
| Node.js 22.19 or newer (24 and 26 work) | `node -v` | `node -v` | `node -v` |
|
|
27
|
+
| git | `git --version` | `git --version` | `git --version` |
|
|
28
|
+
| one coding agent, logged in | `codex login status` or `claude --version` or `pi --version` | same | same |
|
|
29
|
+
| GitHub account and `gh`, for the last block | `gh auth status` | same | same |
|
|
54
30
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
cd my-hero
|
|
58
|
-
npm install
|
|
59
|
-
npm run dev
|
|
60
|
-
```
|
|
31
|
+
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
|
+
login` once), and one agent:
|
|
61
33
|
|
|
62
|
-
|
|
34
|
+
- **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
|
+
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)`.
|
|
63
39
|
|
|
64
|
-
|
|
65
|
-
|
|
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-...` |
|
|
66
43
|
|
|
67
|
-
|
|
68
|
-
cd my-hero
|
|
69
|
-
npm install
|
|
70
|
-
npm run dev
|
|
71
|
-
```
|
|
44
|
+
No prior knowledge of ACRYL, Cordis or Blends is needed; every new word is explained where it appears.
|
|
72
45
|
|
|
73
|
-
|
|
46
|
+
Make the workshop folder:
|
|
74
47
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
48
|
+
| macOS and Linux | Windows PowerShell | Windows cmd.exe |
|
|
49
|
+
| --- | --- | --- |
|
|
50
|
+
| `mkdir ~/acryl-workshop && cd ~/acryl-workshop` | `mkdir ~/acryl-workshop` then `cd ~/acryl-workshop` | `mkdir %USERPROFILE%\acryl-workshop` then `cd %USERPROFILE%\acryl-workshop` |
|
|
78
51
|
|
|
79
|
-
|
|
52
|
+
**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
|
+
them with `;`. PowerShell 7 (`pwsh`) accepts `&&`. In cmd.exe, `Ctrl-C` asks `Terminate batch job (Y/N)?`: answer `Y`.
|
|
80
54
|
|
|
81
|
-
**
|
|
82
|
-
|
|
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.
|
|
83
58
|
|
|
84
|
-
##
|
|
59
|
+
## The path
|
|
85
60
|
|
|
86
|
-
|
|
87
|
-
|
|
61
|
+
| Minutes | Block | What you get |
|
|
62
|
+
| --- | --- | --- |
|
|
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 |
|
|
88
68
|
|
|
89
|
-
|
|
90
|
-
|
|
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)
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
npm create acrylblends@latest my-app agent
|
|
78
|
+
cd my-app
|
|
79
|
+
npm install
|
|
80
|
+
npm run dev
|
|
91
81
|
```
|
|
92
82
|
|
|
93
|
-
|
|
94
|
-
|
|
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.
|
|
95
85
|
|
|
96
|
-
|
|
86
|
+

|
|
97
87
|
|
|
98
|
-
|
|
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.
|
|
99
90
|
|
|
100
|
-
|
|
91
|
+
Open `src/routes.ts` and add one line to the chain, just above `.get('/health', …)`, keeping the indentation of the lines around it:
|
|
101
92
|
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
npm run check
|
|
93
|
+
```ts
|
|
94
|
+
.get('/hello', (c) => c.json({ hello: 'workshop' }))
|
|
105
95
|
```
|
|
106
96
|
|
|
107
|
-
`
|
|
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.
|
|
108
100
|
|
|
109
|
-
|
|
110
|
-
again; a failure names the file and line.
|
|
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.
|
|
111
102
|
|
|
112
|
-
|
|
103
|
+
## 2. The agent builds the interface (30 minutes)
|
|
113
104
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
An app keeps data through a **port**: a small interface a plugin provides. The smallest is `kv`, a JSON file in the app's own folder.
|
|
105
|
+
Start the app (on pi, in the terminal where `DEEPSEEK_API_KEY` is set):
|
|
117
106
|
|
|
118
107
|
```sh
|
|
119
|
-
|
|
120
|
-
npm install
|
|
108
|
+
npm run dev
|
|
121
109
|
```
|
|
122
110
|
|
|
123
|
-
|
|
111
|
+
Open the address it prints and click "Ask the agent". Ask it, in one message:
|
|
124
112
|
|
|
125
|
-
|
|
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.
|
|
126
117
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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.
|
|
131
122
|
|
|
132
|
-
|
|
123
|
+

|
|
133
124
|
|
|
134
|
-
|
|
135
|
-
import * as kvJson from '../plugins/acryl-kv-json/src/index.ts'
|
|
136
|
-
```
|
|
125
|
+

|
|
137
126
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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.
|
|
141
130
|
|
|
142
|
-
|
|
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`.
|
|
143
133
|
|
|
144
|
-
|
|
145
|
-
import type {} from '../plugins/acryl-kv/src/cordis.ts'
|
|
146
|
-
```
|
|
134
|
+
## 3. The agent drives the app (20 minutes)
|
|
147
135
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
```
|
|
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).
|
|
151
138
|
|
|
152
|
-
|
|
153
|
-
.get('/hello', async (c) => {
|
|
154
|
-
const visits = await ctx.kv.update('visits', (n) => (n ?? 0) + 1)
|
|
155
|
-
return c.json({ hello: 'workshop', visits })
|
|
156
|
-
})
|
|
157
|
-
```
|
|
139
|
+
Ask it:
|
|
158
140
|
|
|
159
|
-
|
|
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.
|
|
160
143
|
|
|
161
|
-
|
|
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.
|
|
162
148
|
|
|
163
|
-
|
|
164
|
-
npx acrylblends add acryl-db-sqlite
|
|
165
|
-
mkdir migrations
|
|
166
|
-
printf 'CREATE TABLE visits (id INTEGER PRIMARY KEY, at TEXT NOT NULL);\n' > migrations/001-visits.sql
|
|
167
|
-
npm install
|
|
168
|
-
```
|
|
149
|
+
Then ask it to check its own work in the way a person would:
|
|
169
150
|
|
|
170
|
-
|
|
171
|
-
there, not in the manifest, because a relative path in the manifest has no folder to resolve against.
|
|
151
|
+
> Do it now, without asking for approval. Click "New card" twice, look at the board, and tell me whether the counts agree.
|
|
172
152
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
// in the registry: 'acryl-db-sqlite': dbSqlite
|
|
176
|
-
const projectRoot = fileURLToPath(new URL('..', import.meta.url))
|
|
177
|
-
// in the compose options next to server:
|
|
178
|
-
db: { migrations: join(projectRoot, 'migrations') },
|
|
179
|
-
```
|
|
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.
|
|
180
155
|
|
|
181
|
-
|
|
182
|
-
`await ctx.db.run('INSERT INTO visits (at) VALUES (?)', new Date().toISOString())` before the reply. The database is `my-hero/.acrylblends/data.sqlite`,
|
|
183
|
-
and the migrations run at start, in order.
|
|
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.
|
|
184
157
|
|
|
185
|
-
|
|
186
|
-
from the app folder; move it into `src/app.ts` as above, or update (`npx acrylblends@latest upgrade`). "no such table" means the file is not in `migrations/` at the app root.
|
|
158
|
+
## 4. The same app in a desktop window (15 minutes)
|
|
187
159
|
|
|
188
|
-
|
|
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.
|
|
189
162
|
|
|
190
163
|
```sh
|
|
191
164
|
npx acrylblends add desktop
|
|
@@ -193,189 +166,119 @@ npm install
|
|
|
193
166
|
npm run desktop
|
|
194
167
|
```
|
|
195
168
|
|
|
196
|
-
|
|
197
|
-
and the window's browser data stays inside `my-hero/.acrylblends/electron`. Close the window when you are done (`Cmd-Q`, `Alt-F4`).
|
|
198
|
-
|
|
199
|
-
**Stuck?** The first `npm run desktop` downloads Electron (about 200 MB). No display (a bare server)? Skip this step; nothing later needs it.
|
|
169
|
+
The first `npm run desktop` downloads Electron (about 200 MB), then the window attaches to the running server and says so:
|
|
200
170
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
`runtime: acrylblends`; older ACRYL app starters are refused with a line saying so). Pull one by id, straight into a new folder:
|
|
205
|
-
|
|
206
|
-
```sh
|
|
207
|
-
cd ~/acryl-workshop
|
|
208
|
-
npm create acrylblends@latest from-the-registry -- --from <starter-id>
|
|
209
|
-
cd from-the-registry
|
|
210
|
-
npm install
|
|
211
|
-
npm run dev
|
|
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)
|
|
212
174
|
```
|
|
213
175
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
`Next:` block asks for the same `npm install` as step 1.
|
|
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.
|
|
217
178
|
|
|
218
|
-
|
|
179
|
+

|
|
219
180
|
|
|
220
|
-
|
|
221
|
-
npm create acrylblends@latest from-the-workshop -- --from <id> --registry github:acryldev/workshop-2026-11-20
|
|
222
|
-
```
|
|
181
|
+
Then hand the agent the window itself, not only the page inside it. Ask:
|
|
223
182
|
|
|
224
|
-
|
|
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.
|
|
225
184
|
|
|
226
|
-
|
|
227
|
-
|
|
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.
|
|
228
188
|
|
|
229
|
-
|
|
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.
|
|
230
192
|
|
|
231
|
-
|
|
193
|
+

|
|
232
194
|
|
|
233
|
-
|
|
234
|
-
| --- | --- |
|
|
235
|
-
| `blank` | the router, the server and one route: what you just built |
|
|
236
|
-
| `nodejs` | a page rendered with JSX and a client component, without a bundler |
|
|
237
|
-
| `notes` | a multi-user notes app on the `db` port: sign-up, sessions, migrations, search, a typed client |
|
|
238
|
-
| `chat` | an answer streamed over server-sent events from an OpenAI-compatible API, history in SQLite |
|
|
239
|
-
| `todo` | a to-do list on the router and live state |
|
|
240
|
-
| `agent` | the blank app with an offline agent that writes and installs plugins into the running app |
|
|
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.
|
|
241
196
|
|
|
242
|
-
|
|
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.
|
|
243
199
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
cd notes-app && npm install
|
|
248
|
-
npx acrylblends add desktop && npm install && npm run desktop
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
Sign up, add a note, close the window; run `npm run dev` and the note is still there, because it lives in `notes-app/.acrylblends/data.sqlite`.
|
|
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.
|
|
252
203
|
|
|
253
|
-
|
|
204
|
+
## 5. Deploy it, then publish it (15 minutes)
|
|
254
205
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
The agent panel turns a coding agent you already use into a chat in the corner of the page. It needs the plugins the `agent` template ships (its model,
|
|
258
|
-
tools and memory), so this step builds a second, small app from that template; it is the app you publish in step 10.
|
|
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.
|
|
259
208
|
|
|
260
209
|
```sh
|
|
261
|
-
|
|
262
|
-
npm create acrylblends@latest agent-app agent
|
|
263
|
-
cd agent-app
|
|
264
|
-
npm install
|
|
265
|
-
npx acrylblends add agent-panel driver-pty
|
|
266
|
-
npx acrylblends add desktop
|
|
267
|
-
npm install
|
|
268
|
-
npm run dev
|
|
210
|
+
NODE_ENV=production npm start
|
|
269
211
|
```
|
|
270
212
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
`claude`, or `pi` when pi has its DeepSeek login in your home folder), and ask:
|
|
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.
|
|
274
215
|
|
|
275
|
-
|
|
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`):
|
|
276
219
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
A terminal agent works too: choose `pty:codex` (or `pty:claude`, `pty:pi`) for its normal interactive session inside the app folder, where it can use
|
|
281
|
-
the door (`.acryl/bin/acryl`) to look at the page it built.
|
|
282
|
-
|
|
283
|
-
**Stuck?** The panel uses your own agent account: `codex login` (or `claude`) in a terminal first. Your own agent settings travel with it: skills or hooks of your own can make it stop and ask for approval instead of acting, so write the task as "do it now, without asking for approval", or start the agent from a clean configuration (a fresh `CODEX_HOME`, or no personal skills). If `npm install` warns that npm blocked
|
|
284
|
-
`node-pty`'s install script, ignore it: prebuilt binaries ship. Only if the panel lists no `pty:` terminal, run `npm approve-scripts node-pty` and
|
|
285
|
-
`npm rebuild node-pty` (the `add` output says the same).
|
|
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` |
|
|
286
223
|
|
|
287
|
-
|
|
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.
|
|
288
225
|
|
|
289
|
-
|
|
290
|
-
**`npx acrylblends@latest`**, because an app's own copy of `acrylblends` shadows the bare command and an older copy has no `upgrade` at all.
|
|
226
|
+
**Publish it as a starter.** Your app already is one: `blend.yaml` names it, `plugins/` holds its code.
|
|
291
227
|
|
|
292
228
|
```sh
|
|
293
|
-
cd ~/acryl-workshop
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
229
|
+
cd ~/acryl-workshop
|
|
230
|
+
gh repo fork acryldev/workshop-2026-11-20 --clone
|
|
231
|
+
cd workshop-2026-11-20
|
|
232
|
+
node scripts/make-entry.mjs ../my-app <your-github-login>.my-app --description "the board my agent built"
|
|
233
|
+
git add blends && git commit -m "add <your-github-login>.my-app"
|
|
234
|
+
git push
|
|
235
|
+
gh pr create --fill --repo acryldev/workshop-2026-11-20
|
|
297
236
|
```
|
|
298
237
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
`everything is up to date`: that is the mechanism working, and an app made by an earlier release lists what it would move. Your tests still pass
|
|
302
|
-
afterwards.
|
|
303
|
-
|
|
304
|
-
## 10. Publish it, and the hero moment (8 minutes)
|
|
305
|
-
|
|
306
|
-
The app you publish is `agent-app`, the one the agent changed in step 8 (keep `my-hero` too: it is yours, saved the same way). It is already a
|
|
307
|
-
**starter**: `blend.yaml` names it, lists its rows, and `plugins/` holds its code. Two parts make it public: your own copy, then the registry.
|
|
308
|
-
|
|
309
|
-
**Your own copy first.** `npm run save` commits the app and pushes it to its remote (it refuses a file that looks like a secret, and refuses to push a
|
|
310
|
-
private app to a public remote). Create an empty repository on your git host, set it as `origin`, run `npm run save`.
|
|
311
|
-
|
|
312
|
-
**The registry.** Publishing is a pull request to the workshop registry, `github.com/acryldev/workshop-2026-11-20`, and it is four commands.
|
|
313
|
-
|
|
314
|
-
1. Fork and clone it, then let its script build the entry from your app:
|
|
315
|
-
|
|
316
|
-
```sh
|
|
317
|
-
cd ~/acryl-workshop
|
|
318
|
-
gh repo fork acryldev/workshop-2026-11-20 --clone
|
|
319
|
-
cd workshop-2026-11-20
|
|
320
|
-
node scripts/make-entry.mjs ../agent-app <your-github-login>.agent-app --description "the app I built in the workshop"
|
|
321
|
-
```
|
|
238
|
+
(On Windows PowerShell 5.1, `cd ~/acryl-workshop` works as written; in cmd.exe use `cd %USERPROFILE%\acryl-workshop`. Type the `git add` and `git
|
|
239
|
+
commit` as two lines, or join them with `;`.)
|
|
322
240
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
it, so whoever pulls it gets the desktop shell without adding it again. The id is lowercase, `<login>.<name>` with letters, digits and dashes.
|
|
241
|
+
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
|
+
`npm create acrylblends@latest another-app -- --from <your-github-login>.my-app --registry github:acryldev/workshop-2026-11-20`.
|
|
326
243
|
|
|
327
|
-
|
|
244
|
+

|
|
328
245
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
git push
|
|
332
|
-
gh pr create --fill --repo acryldev/workshop-2026-11-20
|
|
333
|
-
```
|
|
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").
|
|
334
248
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
`git rm -r blends/<your-github-login>.agent-app`.
|
|
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.
|
|
338
251
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
```sh
|
|
342
|
-
npm create acrylblends@latest my-app -- --from <your-github-login>.agent-app --registry github:acryldev/workshop-2026-11-20
|
|
343
|
-
```
|
|
252
|
+
## Browser only (WebBoxes.ai) TODO(M9)
|
|
344
253
|
|
|
345
|
-
|
|
346
|
-
|
|
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.
|
|
347
256
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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.
|
|
351
260
|
|
|
352
261
|
## Where next
|
|
353
262
|
|
|
354
|
-
- **Read the docs you already have**: every app carries `docs/framework`, the same pages as <https://acrylblends.github.io/docs>.
|
|
355
|
-
`
|
|
356
|
-
- **
|
|
357
|
-
|
|
358
|
-
- **Teach your agent**: `AGENTS.md` in your app is what it reads first; add your team's conventions there and the next run follows them.
|
|
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.
|
|
359
267
|
- **Bring your own tool**: <https://acrylblends.github.io/docs/guides/bring-your-own-tool> wraps an outside library as a provider of a port.
|
|
360
268
|
|
|
361
|
-
## Browser only (WebBoxes.ai) TODO(M9)
|
|
362
|
-
|
|
363
|
-
No local install? The same app, and the same agent, will run as a hosted workspace: open it in a browser, pick a starter, and work in the same three
|
|
364
|
-
folders. Nothing to install, nothing to keep on your machine.
|
|
365
|
-
|
|
366
|
-
The hosted workspace is milestone M9 and is due before the workshop, so this section is a stub until it is live: write the address, the sign-in it
|
|
367
|
-
needs, and the two or three clicks that replace steps 1-2 here, then let the local steps stand for anyone who wants the app on their own disk.
|
|
368
|
-
|
|
369
269
|
---
|
|
370
270
|
|
|
371
271
|
## If something goes wrong
|
|
372
272
|
|
|
373
273
|
| Symptom | Do |
|
|
374
274
|
| --- | --- |
|
|
275
|
+
| The preflight prints `FIX` lines | run each one, then `npx acrylblends@latest preflight` again |
|
|
375
276
|
| `npm create` fails or hangs | check the network; the facilitator has prepared apps |
|
|
376
277
|
| A port is taken | use the address the app printed |
|
|
377
|
-
| The agent cannot log in | `codex login` / `claude` in a terminal, then retry in the panel |
|
|
378
|
-
|
|
|
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 |
|
|
282
|
+
| `&&` 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 |
|
|
379
284
|
| Anything else | the **Stuck?** line of the step, then your facilitator |
|
|
380
|
-
|
|
381
|
-
Behind at a checkpoint? Skip step 4 (data) first, then the second app in step 7. Steps 1-3, 5, 8-10 are the spine.
|