@hera-al/server 1.6.12 → 1.6.13

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 (61) hide show
  1. package/bundled/a2ui/SKILL.md +339 -0
  2. package/bundled/buongiorno/SKILL.md +151 -0
  3. package/bundled/council/SKILL.md +168 -0
  4. package/bundled/council/scripts/council.mjs +202 -0
  5. package/bundled/dreaming/SKILL.md +177 -0
  6. package/bundled/google-workspace/SKILL.md +229 -0
  7. package/bundled/google-workspace/scripts/auth.sh +87 -0
  8. package/bundled/google-workspace/scripts/calendar.sh +508 -0
  9. package/bundled/google-workspace/scripts/drive.sh +459 -0
  10. package/bundled/google-workspace/scripts/gmail.sh +452 -0
  11. package/bundled/humanizer/SKILL.md +488 -0
  12. package/bundled/librarian/SKILL.md +155 -0
  13. package/bundled/plasma/SKILL.md +1417 -0
  14. package/bundled/sera/SKILL.md +143 -0
  15. package/bundled/the-skill-guardian/SKILL.md +103 -0
  16. package/bundled/the-skill-guardian/scripts/scan.sh +314 -0
  17. package/bundled/unix-time/SKILL.md +58 -0
  18. package/bundled/wandering/SKILL.md +174 -0
  19. package/bundled/xai-search/SKILL.md +91 -0
  20. package/bundled/xai-search/scripts/search.sh +197 -0
  21. package/dist/a2ui/parser.d.ts +76 -0
  22. package/dist/a2ui/parser.js +1 -0
  23. package/dist/a2ui/types.d.ts +147 -0
  24. package/dist/a2ui/types.js +1 -0
  25. package/dist/a2ui/validator.d.ts +32 -0
  26. package/dist/a2ui/validator.js +1 -0
  27. package/dist/agent/agent-service.d.ts +17 -11
  28. package/dist/agent/agent-service.js +1 -1
  29. package/dist/agent/session-agent.d.ts +1 -1
  30. package/dist/agent/session-agent.js +1 -1
  31. package/dist/agent/session-error-handler.js +1 -1
  32. package/dist/commands/debuga2ui.d.ts +13 -0
  33. package/dist/commands/debuga2ui.js +1 -0
  34. package/dist/commands/debugdynamic.d.ts +13 -0
  35. package/dist/commands/debugdynamic.js +1 -0
  36. package/dist/commands/mcp.d.ts +6 -3
  37. package/dist/commands/mcp.js +1 -1
  38. package/dist/gateway/node-registry.d.ts +29 -1
  39. package/dist/gateway/node-registry.js +1 -1
  40. package/dist/installer/hera.js +1 -1
  41. package/dist/memory/concept-store.d.ts +109 -0
  42. package/dist/memory/concept-store.js +1 -0
  43. package/dist/nostromo/nostromo.js +1 -1
  44. package/dist/server.d.ts +3 -2
  45. package/dist/server.js +1 -1
  46. package/dist/tools/a2ui-tools.d.ts +23 -0
  47. package/dist/tools/a2ui-tools.js +1 -0
  48. package/dist/tools/concept-tools.d.ts +3 -0
  49. package/dist/tools/concept-tools.js +1 -0
  50. package/dist/tools/dynamic-ui-tools.d.ts +25 -0
  51. package/dist/tools/dynamic-ui-tools.js +1 -0
  52. package/dist/tools/node-tools.js +1 -1
  53. package/dist/tools/plasma-client-tools.d.ts +28 -0
  54. package/dist/tools/plasma-client-tools.js +1 -0
  55. package/installationPkg/AGENTS.md +168 -22
  56. package/installationPkg/SOUL.md +56 -0
  57. package/installationPkg/TOOLS.md +126 -0
  58. package/installationPkg/USER.md +54 -1
  59. package/installationPkg/config.example.yaml +145 -34
  60. package/installationPkg/default-jobs.json +77 -0
  61. package/package.json +3 -2
@@ -0,0 +1,1417 @@
1
+ ---
2
+ name: plasma
3
+ description: Event-sourced dynamic UI system for AI-generated interactive interfaces with HTML/CSS/JS
4
+ user-invocable: true
5
+ command-dispatch: true
6
+ ---
7
+
8
+ # PLASMA — Event-Sourced Dynamic UI System v2
9
+
10
+ **Plasma** is Hera's Dynamic UI system that allows you to generate and control fully custom HTML/CSS/JS interfaces on connected nodes (ElectroNode) with complete change history.
11
+
12
+ Unlike template-based UI systems, Plasma gives you complete freedom to create any interface using standard web technologies, external libraries (Three.js, D3.js, Chart.js), and your own custom code.
13
+
14
+ ---
15
+
16
+ ## 🤖 Agent Usage Guidelines
17
+
18
+ **IMPORTANT**: You (the agent) call these tools based on the user's natural language requests. The user NEVER types tool calls directly.
19
+
20
+ ### Prerequisite: Verify Plasma-Capable Nodes
21
+
22
+ Before using ANY Plasma or Dynamic UI tool, you MUST call `dynamic_ui_list_nodes` to check if there are connected nodes with `plasma` capability. If no nodes are found, inform the user that they need to connect an ElectroNode with the Plasma capability enabled. Do NOT attempt to call `plasma_create`, `plasma_mutate`, `plasma_load`, or `dynamic_ui_render`/`dynamic_ui_update` without a Plasma-capable node.
23
+
24
+ ### When to Use Which Tool
25
+
26
+ | User Says | You Do |
27
+ |-----------|--------|
28
+ | "Create a form for customers" | Call `plasma_create` with appropriate HTML/CSS/JS |
29
+ | "Build a dashboard" | Call `plasma_create` with dashboard layout |
30
+ | "Make a calculator app" | Call `plasma_create` with calculator UI |
31
+ | "Add validation to the form" | Call `plasma_mutate` with validation JS |
32
+ | "Change the button color to blue" | Call `plasma_mutate` with color change JS |
33
+ | "Fix the layout" | Call `plasma_mutate` with layout fix JS |
34
+ | "Add a cancel button" | Call `plasma_mutate` with new button JS |
35
+ | "Show me the customer form" | Call `plasma_load` with organism name |
36
+ | "Open the dashboard" | Call `plasma_load` with organism name |
37
+ | "Launch the calculator" | Call `plasma_load` with organism name |
38
+ | "What apps do I have?" | Call `plasma_list` |
39
+ | "List my organisms" | Call `plasma_list` |
40
+ | "Show my UIs" | Call `plasma_list` |
41
+ | "Delete the old form" | Call `plasma_delete` with organism name |
42
+ | "Remove the test app" | Call `plasma_delete` with organism name |
43
+ | "What's in the form right now?" | Call `dynamic_ui_query` with JS to read values |
44
+ | "Read the current data from the app" | Call `dynamic_ui_query` with JS expression |
45
+
46
+ ### Discovery Flow
47
+
48
+ When the user asks to load/open an app but you're not sure which one:
49
+
50
+ 1. Call `plasma_list` to see available organisms
51
+ 2. Check folder names (BASIC convention: descriptive, a-zA-Z0-9_)
52
+ 3. If uncertain, read manifest.yaml frontmatter (name + description)
53
+ 4. Select best match or ask user to clarify
54
+ 5. Call `plasma_load` with selected organism
55
+
56
+ **Example**:
57
+ ```
58
+ User: "Show me the form"
59
+ You: [Call plasma_list]
60
+ [See: customer_form, invoice_form, contact_form]
61
+ [If ambiguous: ask "Which form? I have customer_form, invoice_form, and contact_form"]
62
+ [If clear match: call plasma_load({name: "customer_form", node_id: ...})]
63
+ ```
64
+
65
+ ### Naming Organisms
66
+
67
+ When creating organisms, generate descriptive names following BASIC convention:
68
+ - **Format**: a-zA-Z0-9_ only, max 4 words
69
+ - **Style**: snake_case preferred
70
+ - **Descriptive**: Name reflects content
71
+
72
+ **Good names**: `customer_form`, `sales_dashboard`, `task_manager`, `chat_ui`
73
+ **Bad names**: `form1`, `app`, `my-form`, `very_long_descriptive_name_here`
74
+
75
+ ### Response Style
76
+
77
+ After calling tools, respond to the user in natural language:
78
+
79
+ ❌ **Bad**: "I called plasma_create with parameters {name: 'customer_form', ...}"
80
+ ✅ **Good**: "I've created a customer entry form with name and email fields. It's ready to use!"
81
+
82
+ ❌ **Bad**: "Tool returned: ✅ Organism 'customer_form' created successfully..."
83
+ ✅ **Good**: "The form is now live on your ElectroNode. You can start entering customer data!"
84
+
85
+ ---
86
+
87
+ ## Core Concept v2: Event Sourcing
88
+
89
+ **Create once, mutate incrementally, replay from history.**
90
+
91
+ - **main.code**: Initial app version (YAML structured: HTML/CSS/JS/activities)
92
+ - **Mutations**: Incremental JavaScript updates (1_add_validation.code, 2_change_color.code, ...)
93
+ - **Snapshots**: Automatic mechanical snapshots every 20 mutations for fast loading
94
+ - **No reloads**: Maintain animations, timers, Three.js scenes, canvas state during mutations
95
+
96
+ This enables smooth, interactive experiences where the interface evolves based on user actions with complete auditability and rollback capability.
97
+
98
+ ---
99
+
100
+ ## Organism Architecture
101
+
102
+ ### File Structure
103
+ ```
104
+ .plasma/organisms/customer_form/ ← BASIC naming (a-zA-Z0-9_, max 4 words)
105
+ ├── manifest.yaml ← Metadata with frontmatter
106
+ ├── main.code ← Initial version (YAML structured)
107
+ ├── 1_add_validation.code ← Mutation #1 (JavaScript only)
108
+ ├── 2_change_theme.code ← Mutation #2 (JavaScript only)
109
+ ├── ...
110
+ ├── 19_fix_layout.code
111
+ ├── snapshot_20.code ← Automatic snapshot (every 20)
112
+ ├── 20_add_button.code
113
+ ├── ...
114
+ ├── state.json ← Optional persistent state
115
+ └── .archive/ ← Backups (for LLM optimization)
116
+ └── backup_2026-02-21_14-30/
117
+ ```
118
+
119
+ ### manifest.yaml
120
+ ```yaml
121
+ ---
122
+ name: customer_form
123
+ description: Add and manage customer records
124
+ created: 2026-02-21T10:00:00Z
125
+ updated: 2026-02-21T14:30:00Z
126
+ mutations: 25
127
+ tags: [forms, database, customers]
128
+ ---
129
+ ```
130
+
131
+ ### main.code (YAML structured)
132
+ ```yaml
133
+ ---
134
+ activities:
135
+ - id: btn-submit
136
+ type: button
137
+ context: {action: submit_customer}
138
+ - id: name-input
139
+ type: input
140
+ context: {field: name}
141
+ ---
142
+ html: |
143
+ <div class="form">
144
+ <input id="name-input" placeholder="Name">
145
+ <input id="email-input" placeholder="Email">
146
+ <button id="btn-submit">Submit</button>
147
+ <div id="result"></div>
148
+ </div>
149
+
150
+ css: |
151
+ .form { padding: 20px; max-width: 400px; }
152
+ button { background: #e91e8c; color: white; padding: 10px 20px; }
153
+ input { width: 100%; padding: 8px; margin: 4px 0; }
154
+
155
+ js: |
156
+ window.app = {
157
+ resetForm: function() {
158
+ document.getElementById('name-input').value = '';
159
+ document.getElementById('email-input').value = '';
160
+ }
161
+ };
162
+ ```
163
+
164
+ ### Mutation Files (JavaScript only)
165
+ ```javascript
166
+ // 1_add_validation.code
167
+ window.app.validate = function() {
168
+ const name = document.getElementById('name-input').value;
169
+ if (!name) {
170
+ alert('Name is required');
171
+ return false;
172
+ }
173
+ return true;
174
+ };
175
+
176
+ document.getElementById('btn-submit').onclick = function() {
177
+ if (window.app.validate()) {
178
+ // Submit logic
179
+ }
180
+ };
181
+ ```
182
+
183
+ ---
184
+
185
+ ## Activities & Feedback Loop
186
+
187
+ Activities are the bridge between the UI on the node and you (the agent). They let you receive user interactions and respond with feedback on the user's chat (Telegram, WhatsApp, WebChat, etc.).
188
+
189
+ ### How Activities Work
190
+
191
+ When you define an `activities` array, the node client **auto-injects event listeners** matching element IDs in your HTML. You don't write addEventListener code — just declare the activity and ensure your HTML element has a matching `id`.
192
+
193
+ ### Activity Types
194
+
195
+ | Type | Auto-Wired Event | What Gets Sent |
196
+ |------|------------------|----------------|
197
+ | `button` | `click` (with preventDefault) | `[Dynamic UI Action] click on #btn-submit context={...} provided={...}` |
198
+ | `input` | `change` | `[Dynamic UI Action] change on #email-input data={value: "user@mail.com"} context={...} provided={...}` |
199
+ | `canvas` | None (manual) | Whatever you send via `window.sendAction()` |
200
+ | `custom` | None (manual) | Whatever you send via `window.sendAction()` |
201
+
202
+ ### The `dataProvider` Field
203
+
204
+ Use `dataProvider` to attach a **JS expression** to a `button` or `input` activity. The expression is evaluated **at event time** (when the user clicks/changes), and its result is included as `provided` in the action payload.
205
+
206
+ This replaces the clone-button hack for sending runtime data with auto-wired activities.
207
+
208
+ ```yaml
209
+ activities:
210
+ - id: btn-submit
211
+ type: button
212
+ context: {action: submit_form}
213
+ dataProvider: "({name: document.getElementById('name').value, email: document.getElementById('email').value})"
214
+ ```
215
+
216
+ When clicked, the agent receives:
217
+ ```
218
+ [Dynamic UI Action] click on #btn-submit context={action: "submit_form"} provided={name: "Mario", email: "mario@email.com"}
219
+ ```
220
+
221
+ **Key points**:
222
+ - The expression is wrapped in `eval('(' + expr + ')')` — return an object literal by wrapping in parentheses
223
+ - Errors in `dataProvider` are caught and logged; `provided` will be `undefined` on failure
224
+ - Works on both `button` and `input` activity types
225
+ - `context` is static metadata (set at creation), `provided` is dynamic data (evaluated at event time)
226
+
227
+ **Examples**:
228
+
229
+ ```yaml
230
+ # Single field value
231
+ dataProvider: "document.getElementById('search').value"
232
+
233
+ # Multiple fields as object
234
+ dataProvider: "({name: document.getElementById('name').value, qty: parseInt(document.getElementById('qty').value)})"
235
+
236
+ # App state
237
+ dataProvider: "window.app.getFormData()"
238
+
239
+ # Computed value
240
+ dataProvider: "document.querySelectorAll('.item.selected').length"
241
+ ```
242
+
243
+ **When to use `dataProvider` vs `custom` type**:
244
+
245
+ | Scenario | Use |
246
+ |----------|-----|
247
+ | Auto-wired button that also needs form values | `type: button` + `dataProvider` |
248
+ | Complex custom event handling (multiple events, debounce, etc.) | `type: custom` + `window.sendAction()` |
249
+ | Simple "notify agent" button with no runtime data | `type: button` (no dataProvider) |
250
+
251
+ ### The Feedback Loop
252
+
253
+ This is the key flow — **your response to an action is delivered to the user's chat as text feedback**:
254
+
255
+ ```
256
+ 1. User clicks a button on the PLASMA form (on node screen)
257
+ 2. Node sends action → gateway → routed to your session
258
+ 3. You receive: [Dynamic UI Action] click on #btn-submit data={...} context={action: "submit_form"}
259
+ 4. You process the action (validate, save data, call APIs, etc.)
260
+ 5. Your text response is sent to the user's chat (Telegram, WhatsApp, etc.)
261
+ 6. Optionally, you also update the UI via dynamic_ui_update
262
+ ```
263
+
264
+ **Example**: User fills a form and clicks "Submit" on the PLASMA surface displayed on their Mac:
265
+ - You receive: `[Dynamic UI Action] click on #btn-submit data={} context={action: "submit_customer"}`
266
+ - You read the form data from context or via a follow-up dynamic_ui_update that collects values
267
+ - You respond: "Customer Mario Rossi saved successfully!" → this text appears on Telegram
268
+ - You also call `dynamic_ui_update` to show a green checkmark on the form UI
269
+
270
+ ### Collecting Form Data
271
+
272
+ For forms, you need the input values. Two approaches:
273
+
274
+ **A. Use `input` activities** — each field change sends the value automatically:
275
+ ```yaml
276
+ activities:
277
+ - id: name-input
278
+ type: input
279
+ context: {field: name}
280
+ - id: email-input
281
+ type: input
282
+ context: {field: email}
283
+ - id: btn-submit
284
+ type: button
285
+ context: {action: submit_form}
286
+ ```
287
+ You receive a `change` action for each field as the user types/blurs, then a `click` for submit.
288
+
289
+ **B. Use `custom` type + `window.sendAction()`** — collect all values at once on submit:
290
+ ```javascript
291
+ // In your JS code:
292
+ document.getElementById('btn-submit').addEventListener('click', function(e) {
293
+ e.preventDefault();
294
+ window.sendAction('btn-submit', 'submit', {
295
+ name: document.getElementById('name-input').value,
296
+ email: document.getElementById('email-input').value,
297
+ phone: document.getElementById('phone-input').value
298
+ });
299
+ });
300
+ ```
301
+ ```yaml
302
+ activities:
303
+ - id: btn-submit
304
+ type: custom
305
+ context: {action: submit_form}
306
+ ```
307
+ You receive a single action with all form data in `data={name: "...", email: "...", phone: "..."}`.
308
+
309
+ **Approach B is recommended for forms** — it's simpler and sends all data at once.
310
+
311
+ ### window.sendAction(activityId, type, data)
312
+
313
+ For `canvas` and `custom` activity types, a global `window.sendAction()` function is available in the PLASMA surface. Call it from your JS to send any action back to the agent:
314
+
315
+ ```javascript
316
+ // Send a click with form data
317
+ window.sendAction("btn-submit", "submit", {
318
+ name: document.getElementById("name").value,
319
+ email: document.getElementById("email").value
320
+ });
321
+
322
+ // Send a custom drawing event
323
+ window.sendAction("canvas-draw", "draw", { x: 100, y: 200, tool: "pen" });
324
+
325
+ // Send a selection event
326
+ window.sendAction("item-list", "select", { itemId: 42, label: "Product A" });
327
+ ```
328
+
329
+ ### The context Field
330
+
331
+ Use `context` to pass static metadata that helps you identify what the action means. It is echoed back verbatim in the action message:
332
+
333
+ ```yaml
334
+ activities:
335
+ - id: btn-approve
336
+ type: button
337
+ context: {action: approve, target: invoice, invoiceId: "INV-2026-001"}
338
+ - id: btn-reject
339
+ type: button
340
+ context: {action: reject, target: invoice, invoiceId: "INV-2026-001"}
341
+ ```
342
+
343
+ When clicked, you receive:
344
+ ```
345
+ [Dynamic UI Action] click on #btn-approve context={action: "approve", target: "invoice", invoiceId: "INV-2026-001"}
346
+ ```
347
+
348
+ This lets you handle different buttons in the same form without ambiguity.
349
+
350
+ ### Serializing Runtime Data in Actions
351
+
352
+ **Critical pattern**: Auto-wired `button` activities only send the static `context` — they do NOT include dynamic data from the UI (form values, accumulated records, canvas state, etc.). The data lives in the browser and the agent never sees it unless you explicitly include it.
353
+
354
+ **The problem** — a button declared as `type: button` without `dataProvider`:
355
+ ```yaml
356
+ activities:
357
+ - id: btn-send
358
+ type: button
359
+ context: {action: send_records}
360
+ ```
361
+ The agent receives only: `[Dynamic UI Action] click on #btn-send context={action: "send_records"}` — no actual records data.
362
+
363
+ **Solution A (preferred)** — add `dataProvider` to the activity:
364
+ ```yaml
365
+ activities:
366
+ - id: btn-send
367
+ type: button
368
+ context: {action: send_records}
369
+ dataProvider: "JSON.parse(JSON.stringify(window.app.records))"
370
+ ```
371
+ The agent receives: `[Dynamic UI Action] click on #btn-send context={action: "send_records"} provided=[{nome: "Mario", ...}, ...]`
372
+
373
+ **Solution B** — declare the button as `type: custom` and call `window.sendAction()` with serialized data:
374
+
375
+ ```yaml
376
+ activities:
377
+ - id: btn-send
378
+ type: custom
379
+ context: {action: send_records}
380
+ ```
381
+ ```javascript
382
+ // In your JS: handle the click yourself and include runtime data
383
+ document.getElementById('btn-send').addEventListener('click', function(e) {
384
+ e.preventDefault();
385
+ if (!window.app.records.length) return;
386
+
387
+ // Serialize runtime data into the action payload
388
+ window.sendAction('btn-send', 'click', {
389
+ context: { action: 'send_records' },
390
+ records: JSON.parse(JSON.stringify(window.app.records))
391
+ });
392
+ });
393
+ ```
394
+
395
+ The agent now receives:
396
+ ```
397
+ [Dynamic UI Action] click on #btn-send data={context: {action: "send_records"}, records: [{nome: "Mario", cognome: "Rossi", email: "mario@email.com"}, ...]}
398
+ ```
399
+
400
+ #### Retrofitting an existing `type: button` activity
401
+
402
+ If a button was already declared as `type: button`, the node has auto-wired a click listener on it. To replace it with a custom handler that sends data, clone the element to strip all listeners:
403
+
404
+ ```javascript
405
+ // Remove auto-wired listener via clone trick
406
+ var oldBtn = document.getElementById('btn-send');
407
+ var newBtn = oldBtn.cloneNode(true);
408
+ oldBtn.parentNode.replaceChild(newBtn, oldBtn);
409
+
410
+ // Attach custom handler with data serialization
411
+ newBtn.addEventListener('click', function(e) {
412
+ e.preventDefault();
413
+ window.sendAction('btn-send', 'click', {
414
+ records: JSON.parse(JSON.stringify(window.app.records))
415
+ });
416
+ });
417
+ ```
418
+
419
+ This is a valid workaround via `plasma_mutate`, but **prefer declaring `type: custom` from the start** for any button that needs to send runtime data.
420
+
421
+ #### Which type to use — decision guide
422
+
423
+ | Scenario | Activity Type | Why |
424
+ |----------|--------------|-----|
425
+ | Button that just notifies the agent ("user clicked X") | `button` | Auto-wired, no JS needed |
426
+ | Button that sends form values or simple computed data | `button` + `dataProvider` | Auto-wired with runtime data, no custom JS |
427
+ | Button with complex event handling (debounce, multi-event, etc.) | `custom` | Full control via `window.sendAction()` |
428
+ | Button that only does client-side work (no agent involvement) | Don't declare as activity | No activity needed — just use normal JS |
429
+ | Input field whose value changes matter to the agent | `input` | Auto-sends value on change |
430
+ | Complex interactive element (canvas, drag-drop, etc.) | `custom` | Full control via `window.sendAction()` |
431
+
432
+ #### Real-world example — multi-record form
433
+
434
+ This pattern was used in the Anagrafica organism: a form where the user adds multiple records client-side, then sends them all to the agent at once.
435
+
436
+ ```yaml
437
+ activities:
438
+ - id: btn-add
439
+ type: button
440
+ context: {action: add_record} # notifies agent a record was added
441
+ - id: btn-export
442
+ type: button
443
+ context: {action: export_csv} # notifies agent of CSV export
444
+ - id: btn-send
445
+ type: custom # custom: sends serialized records
446
+ context: {action: send_records}
447
+ ```
448
+
449
+ ```javascript
450
+ // btn-add and btn-export: client-side handlers (no sendAction needed)
451
+ document.getElementById('btn-add').addEventListener('click', function() {
452
+ window.app.addRecord(); // client-side only
453
+ });
454
+
455
+ // btn-send: serialize and send all records to the agent
456
+ document.getElementById('btn-send').addEventListener('click', function(e) {
457
+ e.preventDefault();
458
+ var records = window.app.records;
459
+ if (!records.length) { alert('No records'); return; }
460
+
461
+ // Visual feedback while sending
462
+ this.innerHTML = '💎 Invio...';
463
+ this.style.opacity = '0.7';
464
+ var btn = this;
465
+
466
+ window.sendAction('btn-send', 'click', {
467
+ context: { action: 'send_records' },
468
+ records: JSON.parse(JSON.stringify(records))
469
+ });
470
+
471
+ setTimeout(function() {
472
+ btn.innerHTML = '💎 Inviato ✓';
473
+ setTimeout(function() { btn.innerHTML = '💎 Invia'; btn.style.opacity = '1'; }, 2000);
474
+ }, 400);
475
+ });
476
+ ```
477
+
478
+ The agent receives all records and can respond on the user's chat:
479
+ ```
480
+ [Dynamic UI Action] click on #btn-send data={context: {action: "send_records"}, records: [{nome: "Mario", cognome: "Rossi", ...}, {nome: "Giulia", cognome: "Bianchi", ...}]}
481
+ ```
482
+
483
+ Agent responds on Telegram: "Received 2 records: Mario Rossi, Giulia Bianchi. Saved to database."
484
+
485
+ ---
486
+
487
+ ## Available Tools
488
+
489
+ ### 1. `plasma_create`
490
+ Create a new organism (app).
491
+
492
+ **When to use**: User requests a new UI application (form, dashboard, calculator, etc.)
493
+
494
+ **User says**: "Create a form", "Build a dashboard", "Make a calculator"
495
+
496
+ **You do**: Call this tool with appropriate HTML/CSS/JS
497
+
498
+ **Parameters**:
499
+ - `name`: Organism name (a-zA-Z0-9_, max 4 words, descriptive)
500
+ - `description`: What this organism does
501
+ - `html`: HTML content
502
+ - `css`: CSS styles (optional)
503
+ - `js`: JavaScript code (optional)
504
+ - `activities`: Array of interactive elements
505
+ - `tags`: Category tags (optional)
506
+
507
+ **Naming convention**: Use descriptive names following BASIC rules
508
+ - ✅ Good: `customer_form`, `sales_dashboard`, `task_manager`, `chat_ui`
509
+ - ❌ Bad: `form1`, `my-app`, `SuperCoolApp123`, `very_long_name_with_many_words`
510
+
511
+ **Example conversation**:
512
+ ```
513
+ User: "Create a customer entry form with name and email fields"
514
+
515
+ You: [Call plasma_create tool internally]
516
+ ```
517
+
518
+ **Tool call** (you make this call, not the user):
519
+ ```javascript
520
+ plasma_create({
521
+ name: "customer_form",
522
+ description: "Entry form for customer records",
523
+ html: `
524
+ <div class="form">
525
+ <input id="name" placeholder="Name">
526
+ <input id="email" placeholder="Email">
527
+ <button id="btn-submit">Submit</button>
528
+ </div>
529
+ `,
530
+ css: `
531
+ .form { padding: 20px; }
532
+ button { background: #e91e8c; color: white; }
533
+ `,
534
+ js: `
535
+ window.app = {
536
+ submitForm: function() { ... }
537
+ };
538
+ `,
539
+ activities: [
540
+ {id: "btn-submit", type: "button", context: {action: "submit"}}
541
+ ],
542
+ tags: ["forms", "database"]
543
+ })
544
+ ```
545
+
546
+ **Tool result** (internal):
547
+ ```
548
+ ✅ Organism 'customer_form' created successfully
549
+ Saved to: .plasma/organisms/customer_form/
550
+ Files: manifest.yaml, main.code (350 bytes)
551
+ Activities: 1 (#btn-submit)
552
+ ```
553
+
554
+ **You respond to user**:
555
+ "I've created a customer entry form with name and email fields. The form has a submit button that will send you the data when clicked. Would you like me to load it on your ElectroNode now?"
556
+
557
+ ---
558
+
559
+ ### 2. `plasma_mutate`
560
+ Apply an incremental mutation to an existing organism.
561
+
562
+ **When to use**: User requests changes to an existing app
563
+
564
+ **User says**:
565
+ - "Add validation to the form"
566
+ - "Change the button color to blue"
567
+ - "Fix the layout"
568
+ - "Add a cancel button"
569
+
570
+ **You do**: Call this tool with JavaScript that implements the change
571
+
572
+ **Parameters**:
573
+ - `name`: Organism name
574
+ - `mutation_name`: Descriptive name for mutation (a-zA-Z0-9_)
575
+ - `js`: JavaScript code for the mutation
576
+ - `node_id`: Optional node ID to apply immediately
577
+
578
+ **Mutation naming**: Be descriptive
579
+ - ✅ Good: `add_validation`, `change_theme_blue`, `fix_button_layout`
580
+ - ❌ Bad: `update`, `fix`, `change`
581
+
582
+ **Example conversation**:
583
+ ```
584
+ User: "Add validation to the customer form - name should be required"
585
+
586
+ You: [Call plasma_mutate tool internally]
587
+ ```
588
+
589
+ **Tool call** (you make this call):
590
+ ```javascript
591
+ plasma_mutate({
592
+ name: "customer_form",
593
+ mutation_name: "add_validation",
594
+ js: `
595
+ window.app.validate = function() {
596
+ const name = document.getElementById('name').value;
597
+ if (!name) {
598
+ alert('Name required');
599
+ return false;
600
+ }
601
+ return true;
602
+ };
603
+
604
+ document.getElementById('btn-submit').onclick = function() {
605
+ if (window.app.validate()) {
606
+ window.app.submitForm();
607
+ }
608
+ };
609
+ `,
610
+ node_id: "electr-abc123" // Apply immediately
611
+ })
612
+ ```
613
+
614
+ **Tool result** (internal):
615
+ ```
616
+ ✅ Mutation applied: 1_add_validation.code
617
+ Total mutations: 1
618
+ Applied to node electr-abc123
619
+ ```
620
+
621
+ **You respond to user**:
622
+ "I've added name validation to the form. It will now show an alert if the user tries to submit without entering a name. The validation is active on your current session and will persist for future loads."
623
+
624
+ **Automatic snapshots**: Every 20 mutations, a snapshot is created automatically:
625
+ ```
626
+ ✅ Mutation applied to organism 'customer_form'
627
+
628
+ Mutation: 20_optimize_render.code
629
+ Total mutations: 20
630
+
631
+ 📸 Snapshot created (snapshot_20.code) for fast loading
632
+ ```
633
+
634
+ ---
635
+
636
+ ### 3. `plasma_load`
637
+ Load a saved organism and render it on a node.
638
+
639
+ **When to use**: User wants to view/open an existing app
640
+
641
+ **User says**:
642
+ - "Show me the customer form"
643
+ - "Open the sales dashboard"
644
+ - "Launch the calculator"
645
+ - "Load my task manager"
646
+
647
+ **You do**:
648
+ 1. If organism name is ambiguous, call `plasma_list` first
649
+ 2. Call `plasma_load` with the organism name and node_id
650
+
651
+ **Parameters**:
652
+ - `name`: Organism name
653
+ - `node_id`: Target node ID
654
+
655
+ **Loading strategy** (automatic, transparent):
656
+ 1. Find best snapshot (if available) → fast load
657
+ 2. Load main.code if no snapshot
658
+ 3. Apply remaining mutations in sequence
659
+ 4. Render on node
660
+
661
+ **Example conversation**:
662
+ ```
663
+ User: "Show me the customer form"
664
+
665
+ You: [Call dynamic_ui_list_nodes to get node_id]
666
+ [Call plasma_load with organism name and node_id]
667
+ ```
668
+
669
+ **Tool call** (you make this call):
670
+ ```javascript
671
+ plasma_load({
672
+ name: "customer_form",
673
+ node_id: "electr-abc123"
674
+ })
675
+ ```
676
+
677
+ **Tool result** (internal):
678
+ ```
679
+ ✅ Loaded and rendered on ElectroNode-darwin
680
+ Total mutations: 25
681
+ Loaded from: snapshot_20.code
682
+ Applied 5 additional mutations
683
+ ```
684
+
685
+ **You respond to user**:
686
+ "The customer form is now displayed on your ElectroNode. It includes all 25 updates you've made, including the validation and styling changes. Ready to use!"
687
+
688
+ **Performance**: With snapshots, loading 100+ mutations takes ~100ms vs ~2s without.
689
+
690
+ ---
691
+
692
+ ### 4. `plasma_list`
693
+ List all saved organisms.
694
+
695
+ **When to use**: User asks what apps/organisms are available, or when you need to discover organism names
696
+
697
+ **User says**:
698
+ - "What apps do I have?"
699
+ - "List my organisms"
700
+ - "Show me my UIs"
701
+
702
+ **You do**: Call this tool (no parameters needed)
703
+
704
+ **Example conversation**:
705
+ ```
706
+ User: "What apps do I have?"
707
+
708
+ You: [Call plasma_list]
709
+ ```
710
+
711
+ **Tool result** (internal):
712
+ ```
713
+ 5 PLASMA organism(s) available:
714
+
715
+ - customer_form (customer_form) — 25 mutations [forms, database]
716
+ Entry form for customer records
717
+
718
+ - sales_dashboard (sales_dashboard) — 12 mutations [dashboard, charts]
719
+ Real-time sales metrics and visualization
720
+
721
+ - task_manager (task_manager) — 8 mutations [productivity]
722
+ Simple task list with drag-and-drop
723
+
724
+ - chat_ui (chat_ui) — 45 mutations [communication]
725
+ Real-time chat interface with typing indicators
726
+
727
+ - invoice_gen (invoice_gen) — 3 mutations [pdf, forms]
728
+ Generate PDF invoices from form data
729
+ ```
730
+
731
+ **You respond to user**:
732
+ "You have 5 Plasma apps:
733
+ 1. **Customer Form** (25 updates) - Entry form for customer records
734
+ 2. **Sales Dashboard** (12 updates) - Real-time sales metrics
735
+ 3. **Task Manager** (8 updates) - Simple task list with drag-and-drop
736
+ 4. **Chat UI** (45 updates) - Real-time chat interface
737
+ 5. **Invoice Generator** (3 updates) - Generate PDF invoices
738
+
739
+ Which one would you like to open?"
740
+
741
+ ---
742
+
743
+ ### 5. `plasma_delete`
744
+ Delete an organism permanently.
745
+
746
+ **When to use**: User wants to remove an app they no longer need
747
+
748
+ **User says**:
749
+ - "Delete the old form"
750
+ - "Remove the test app"
751
+ - "I don't need the calculator anymore"
752
+
753
+ **You do**: Call this tool with the organism name
754
+
755
+ **Important**: Always confirm with the user before deleting unless they explicitly say to delete
756
+
757
+ **Example conversation**:
758
+ ```
759
+ User: "Delete the test form"
760
+
761
+ You: "Are you sure you want to delete 'test_form'? This will remove it permanently along with all its mutations."
762
+
763
+ User: "Yes"
764
+
765
+ You: [Call plasma_delete]
766
+ ```
767
+
768
+ **Tool call** (you make this call):
769
+ ```javascript
770
+ plasma_delete({name: "test_form"})
771
+ ```
772
+
773
+ **Tool result** (internal):
774
+ ```
775
+ ✅ Organism 'test_form' deleted permanently
776
+ ```
777
+
778
+ **You respond to user**:
779
+ "The test form has been deleted permanently. All mutations and history have been removed."
780
+
781
+ ---
782
+
783
+ ### 6. `dynamic_ui_query`
784
+ Execute JavaScript in the DynamicUI surface on a node and return the result.
785
+
786
+ **When to use**: You need to read runtime state from the UI — form values, accumulated data, DOM state, computed values — without the user triggering an action.
787
+
788
+ **User says**:
789
+ - "What's in the form right now?"
790
+ - "How many records have been added?"
791
+ - "Read the current settings from the app"
792
+
793
+ **You do**: Call this tool with a JS expression; the result comes back to you directly.
794
+
795
+ **Parameters**:
796
+ - `node_id`: Target node ID
797
+ - `js`: JavaScript expression to evaluate (result is returned)
798
+
799
+ **Example conversation**:
800
+ ```
801
+ User: "What data is in the form?"
802
+
803
+ You: [Call dynamic_ui_query with JS to read form fields]
804
+ ```
805
+
806
+ **Tool call** (you make this call):
807
+ ```javascript
808
+ dynamic_ui_query({
809
+ node_id: "osxnode-abc123",
810
+ js: "({name: document.getElementById('name').value, email: document.getElementById('email').value})"
811
+ })
812
+ ```
813
+
814
+ **Tool result** (internal):
815
+ ```
816
+ Result: {"name": "Mario Rossi", "email": "mario@email.com"}
817
+ ```
818
+
819
+ **You respond to user**:
820
+ "The form currently has: Name = Mario Rossi, Email = mario@email.com"
821
+
822
+ **More examples**:
823
+ ```javascript
824
+ // Read app state
825
+ dynamic_ui_query({ node_id: "...", js: "JSON.stringify(window.app.records)" })
826
+
827
+ // Count elements
828
+ dynamic_ui_query({ node_id: "...", js: "document.querySelectorAll('.item').length" })
829
+
830
+ // Check visibility
831
+ dynamic_ui_query({ node_id: "...", js: "document.getElementById('panel').style.display !== 'none'" })
832
+ ```
833
+
834
+ **`dataProvider` vs `dynamic_ui_query`**:
835
+ - `dataProvider`: Evaluated **at event time** (user clicks button) — data travels with the action
836
+ - `dynamic_ui_query`: Evaluated **on demand** (agent calls it) — agent proactively reads UI state
837
+
838
+ ---
839
+
840
+ ## Best Practices
841
+
842
+ ### 0. Use Bootstrap for Forms and Form-Based Applications
843
+
844
+ **When the user requests a form, a form-based application, or any UI that is primarily form-driven** (contact forms, registration, data entry, surveys, settings panels, etc.), **always use Bootstrap** as the CSS framework.
845
+
846
+ **Why**: Bootstrap provides consistent, responsive, accessible form layouts out of the box — radio buttons, checkboxes, selects, validation states, input groups, floating labels, and grid alignment all work correctly without custom CSS.
847
+
848
+ **How**: Load Bootstrap from CDN in the `css` field or via `<link>` in the HTML:
849
+
850
+ ```html
851
+ <!-- In the html field of plasma_create -->
852
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
853
+ ```
854
+
855
+ Or load both CSS + JS (for components like modals, tooltips, accordions):
856
+
857
+ ```html
858
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
859
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
860
+ ```
861
+
862
+ **Example form with Bootstrap**:
863
+ ```javascript
864
+ plasma_create({
865
+ name: "customer_form",
866
+ description: "Customer registration form",
867
+ html: `
868
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
869
+ <div class="container py-4" style="max-width: 600px;">
870
+ <h3 class="mb-4">New Customer</h3>
871
+ <form id="customer-form">
872
+ <div class="mb-3">
873
+ <label for="name" class="form-label">Full Name</label>
874
+ <input type="text" class="form-control" id="name" required>
875
+ </div>
876
+ <div class="mb-3">
877
+ <label for="email" class="form-label">Email</label>
878
+ <input type="email" class="form-control" id="email" required>
879
+ </div>
880
+ <div class="mb-3">
881
+ <label for="phone" class="form-label">Phone</label>
882
+ <input type="tel" class="form-control" id="phone">
883
+ </div>
884
+ <button type="submit" id="btn-submit" class="btn btn-primary">Submit</button>
885
+ </form>
886
+ <div id="status" class="mt-3"></div>
887
+ </div>
888
+ `,
889
+ activities: [
890
+ {id: "btn-submit", type: "button", context: {action: "submit_customer"}}
891
+ ],
892
+ tags: ["forms", "customers"]
893
+ })
894
+ ```
895
+
896
+ **When NOT to use Bootstrap**: Dashboards, 3D visualizations, games, custom creative UIs, canvas-based apps — use custom CSS or other frameworks as appropriate.
897
+
898
+ ### 1. Always Expose Global State in main.code
899
+
900
+ **Why**: Mutations need access to app state
901
+
902
+ ```javascript
903
+ // GOOD: In main.code js section
904
+ window.app = {
905
+ scene: scene,
906
+ cube: cube,
907
+ camera: camera,
908
+ submitForm: function() { ... }
909
+ };
910
+ ```
911
+
912
+ ```javascript
913
+ // BAD: Everything local
914
+ const scene = new THREE.Scene(); // Can't access in mutations!
915
+ ```
916
+
917
+ ### 2. Descriptive Mutation Names
918
+
919
+ ```javascript
920
+ // GOOD
921
+ plasma_mutate({
922
+ name: "customer_form",
923
+ mutation_name: "add_email_validation",
924
+ js: ...
925
+ })
926
+
927
+ // BAD
928
+ plasma_mutate({
929
+ name: "customer_form",
930
+ mutation_name: "fix", // Too vague
931
+ js: ...
932
+ })
933
+ ```
934
+
935
+ ### 3. Small, Focused Mutations
936
+
937
+ ```javascript
938
+ // GOOD: One concern per mutation
939
+ 1_add_validation.code → Validation logic
940
+ 2_change_button_color.code → Visual change
941
+ 3_add_cancel_button.code → New feature
942
+
943
+ // BAD: Giant mutation doing everything
944
+ 1_big_update.code → Changes 10 different things
945
+ ```
946
+
947
+ ### 4. Use node_id for Immediate Feedback
948
+
949
+ ```javascript
950
+ // If user is actively using the app, apply mutation immediately
951
+ plasma_mutate({
952
+ name: "customer_form",
953
+ mutation_name: "change_theme_dark",
954
+ js: `
955
+ document.body.style.background = '#1a1a1a';
956
+ document.body.style.color = '#ffffff';
957
+ `,
958
+ node_id: currentNodeId // ← Apply now
959
+ })
960
+ ```
961
+
962
+ ### 5. Load Libraries from CDN in main.code
963
+
964
+ ```javascript
965
+ // In main.code js section:
966
+ const script = document.createElement('script');
967
+ script.src = 'https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.min.js';
968
+ script.onload = function() {
969
+ // Three.js loaded, create scene
970
+ const scene = new THREE.Scene();
971
+ // ...
972
+ window.app = { scene, ... };
973
+ };
974
+ document.head.appendChild(script);
975
+ ```
976
+
977
+ ---
978
+
979
+ ## Client-Side vs Server-Side Logic
980
+
981
+ **Golden Rule**: Handle as much as possible client-side. Only involve the server for actions that REQUIRE server capabilities.
982
+
983
+ ### Handle CLIENT-SIDE (via mutations):
984
+ - ✅ Visual changes (color, size, position, rotation)
985
+ - ✅ Animations and transitions
986
+ - ✅ Form validation (basic)
987
+ - ✅ UI state changes (show/hide, enable/disable)
988
+ - ✅ Local filtering/sorting
989
+ - ✅ Canvas drawing
990
+ - ✅ Three.js scene manipulation
991
+
992
+ **Why**: Instant response, no network latency, preserves state.
993
+
994
+ ### Handle SERVER-SIDE (via activity → agent responds):
995
+ - 📡 Data fetching from external APIs
996
+ - 📡 Database operations
997
+ - 📡 Complex computations
998
+ - 📡 Form submissions requiring persistence
999
+ - 📡 Authentication/authorization
1000
+ - 📡 File uploads
1001
+ - 📡 IoT device control
1002
+
1003
+ **Why**: Requires server capabilities you can't provide in browser.
1004
+
1005
+ **Important**: For server-side operations (database, API calls, file processing), use existing MCP tools that the agent already has access to. The agent can invoke any available tool in response to UI actions.
1006
+
1007
+ ### Example: Color Picker
1008
+
1009
+ **USER REQUEST**: "I want to change the cube color"
1010
+
1011
+ **CLIENT-SIDE APPROACH** (PREFERRED):
1012
+ ```javascript
1013
+ // Initial render includes color picker activity
1014
+ activities: [{id: "color-picker", type: "input", context: {}}]
1015
+
1016
+ // User changes color → you receive action
1017
+ // [Dynamic UI Action] change on #color-picker data={value: "#ff0000"}
1018
+
1019
+ // Response: Direct update (instant)
1020
+ dynamic_ui_update({
1021
+ node_id: "...",
1022
+ js: `window.app.cube.material.color.set('${value}');`
1023
+ })
1024
+ ```
1025
+
1026
+ **Why this works**: Color change is purely visual, no server needed.
1027
+
1028
+ ### Example: Weather Data Form
1029
+
1030
+ **USER REQUEST**: "Show me a form to get weather for a city"
1031
+
1032
+ **HYBRID APPROACH**:
1033
+ ```javascript
1034
+ // 1. Initial render with form (client-side)
1035
+ dynamic_ui_render({
1036
+ html: `
1037
+ <input id="city-input" type="text" placeholder="Enter city">
1038
+ <button id="btn-fetch">Get Weather</button>
1039
+ <div id="weather-result"></div>
1040
+ `,
1041
+ activities: [
1042
+ {id: "btn-fetch", type: "button", context: {action: "fetch_weather"}}
1043
+ ]
1044
+ })
1045
+
1046
+ // 2. User clicks button → you receive:
1047
+ // [Dynamic UI Action] click on #btn-fetch
1048
+
1049
+ // 3. You fetch weather from server API (server-side)
1050
+ const weather = await fetchWeatherAPI(city);
1051
+
1052
+ // 4. Update UI with result (client-side)
1053
+ dynamic_ui_update({
1054
+ js: `
1055
+ document.getElementById('weather-result').innerHTML = '
1056
+ <h3>${weather.city}</h3>
1057
+ <p>Temperature: ${weather.temp}°C</p>
1058
+ <p>Conditions: ${weather.conditions}</p>
1059
+ ';
1060
+ `
1061
+ })
1062
+ ```
1063
+
1064
+ **Why hybrid**: Form display is client-side, but weather API requires server.
1065
+
1066
+ ---
1067
+
1068
+ ## When to Use PLASMA vs Dynamic UI Directly
1069
+
1070
+ **Use `plasma_create` + `plasma_load` when**:
1071
+ - UI will be reused multiple times
1072
+ - App should load instantly from disk
1073
+ - Want complete change history (event sourcing)
1074
+ - Building library of reusable apps
1075
+
1076
+ **Use `dynamic_ui_render` directly when**:
1077
+ - One-off visualization
1078
+ - Highly dynamic content that changes every time
1079
+ - Prototyping/testing
1080
+
1081
+ **Typical workflow**:
1082
+ ```javascript
1083
+ // 1. Create organism (saved to disk)
1084
+ plasma_create({ name: "my_app", ... })
1085
+
1086
+ // 2. Evolve it incrementally
1087
+ plasma_mutate({ name: "my_app", mutation_name: "add_feature", js: "..." })
1088
+
1089
+ // 3. Load it any time
1090
+ plasma_load({ name: "my_app", node_id: nodeId })
1091
+ ```
1092
+
1093
+ ---
1094
+
1095
+ ## Common Patterns
1096
+
1097
+ ### Pattern 1: Form with Progressive Enhancement
1098
+
1099
+ ```javascript
1100
+ // 1. Create base form
1101
+ plasma_create({
1102
+ name: "contact_form",
1103
+ description: "Contact form with progressive enhancements",
1104
+ html: `
1105
+ <div class="form">
1106
+ <input id="name" placeholder="Name">
1107
+ <input id="email" placeholder="Email">
1108
+ <textarea id="message" placeholder="Message"></textarea>
1109
+ <button id="btn-submit">Submit</button>
1110
+ <div id="status"></div>
1111
+ </div>
1112
+ `,
1113
+ activities: [
1114
+ {id: "btn-submit", type: "button", context: {action: "submit"}}
1115
+ ]
1116
+ })
1117
+
1118
+ // 2. Add validation (mutation #1)
1119
+ plasma_mutate({
1120
+ name: "contact_form",
1121
+ mutation_name: "add_validation",
1122
+ js: `
1123
+ window.app.validate = function() {
1124
+ const email = document.getElementById('email').value;
1125
+ if (!email.includes('@')) {
1126
+ document.getElementById('status').textContent = '❌ Invalid email';
1127
+ return false;
1128
+ }
1129
+ return true;
1130
+ };
1131
+ `
1132
+ })
1133
+
1134
+ // 3. Add character counter (mutation #2)
1135
+ plasma_mutate({
1136
+ name: "contact_form",
1137
+ mutation_name: "add_char_counter",
1138
+ js: `
1139
+ const textarea = document.getElementById('message');
1140
+ const counter = document.createElement('div');
1141
+ counter.id = 'counter';
1142
+ textarea.after(counter);
1143
+
1144
+ textarea.oninput = function() {
1145
+ counter.textContent = this.value.length + ' characters';
1146
+ };
1147
+ `
1148
+ })
1149
+ ```
1150
+
1151
+ ### Pattern 2: Interactive 3D Visualization
1152
+
1153
+ ```javascript
1154
+ // Create Three.js app
1155
+ plasma_create({
1156
+ name: "cube_3d",
1157
+ description: "Interactive rotating cube",
1158
+ html: `<div id="container" style="width:100%; height:500px;"></div>`,
1159
+ js: `
1160
+ const script = document.createElement('script');
1161
+ script.src = 'https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.min.js';
1162
+ script.onload = () => {
1163
+ const scene = new THREE.Scene();
1164
+ const camera = new THREE.PerspectiveCamera(75, 800/500, 0.1, 1000);
1165
+ const renderer = new THREE.WebGLRenderer({antialias: true});
1166
+ renderer.setSize(800, 500);
1167
+ container.appendChild(renderer.domElement);
1168
+
1169
+ const cube = new THREE.Mesh(
1170
+ new THREE.BoxGeometry(2,2,2),
1171
+ new THREE.MeshPhongMaterial({color: 0xe91e8c})
1172
+ );
1173
+ scene.add(cube);
1174
+
1175
+ const light = new THREE.DirectionalLight(0xffffff, 1);
1176
+ light.position.set(5,5,5);
1177
+ scene.add(light);
1178
+ camera.position.z = 5;
1179
+
1180
+ function animate() {
1181
+ requestAnimationFrame(animate);
1182
+ cube.rotation.x += 0.01;
1183
+ cube.rotation.y += 0.01;
1184
+ renderer.render(scene, camera);
1185
+ }
1186
+ animate();
1187
+
1188
+ // EXPOSE STATE for mutations
1189
+ window.app = { scene, camera, renderer, cube };
1190
+ };
1191
+ document.head.appendChild(script);
1192
+ `,
1193
+ activities: []
1194
+ })
1195
+
1196
+ // Mutation: Change color
1197
+ plasma_mutate({
1198
+ name: "cube_3d",
1199
+ mutation_name: "change_color_blue",
1200
+ js: `window.app.cube.material.color.set('#0000ff');`,
1201
+ node_id: nodeId
1202
+ })
1203
+
1204
+ // Mutation: Double size
1205
+ plasma_mutate({
1206
+ name: "cube_3d",
1207
+ mutation_name: "double_size",
1208
+ js: `window.app.cube.scale.set(2, 2, 2);`,
1209
+ node_id: nodeId
1210
+ })
1211
+ ```
1212
+
1213
+ ### Pattern 3: Dashboard with Live Updates
1214
+
1215
+ ```javascript
1216
+ // Create dashboard
1217
+ plasma_create({
1218
+ name: "system_monitor",
1219
+ description: "System monitoring dashboard",
1220
+ html: `
1221
+ <div class="dashboard">
1222
+ <h2>System Status</h2>
1223
+ <div id="cpu" class="metric">CPU: --</div>
1224
+ <div id="memory" class="metric">Memory: --</div>
1225
+ <div id="disk" class="metric">Disk: --</div>
1226
+ </div>
1227
+ `,
1228
+ css: `
1229
+ .dashboard { padding: 20px; font-family: monospace; }
1230
+ .metric { font-size: 18px; margin: 10px 0; }
1231
+ `,
1232
+ activities: []
1233
+ })
1234
+
1235
+ // Server periodically sends updates via mutations
1236
+ // (Agent calls plasma_mutate when new data arrives)
1237
+ plasma_mutate({
1238
+ name: "system_monitor",
1239
+ mutation_name: "update_metrics",
1240
+ js: `
1241
+ document.getElementById('cpu').textContent = 'CPU: 45%';
1242
+ document.getElementById('memory').textContent = 'Memory: 62%';
1243
+ document.getElementById('disk').textContent = 'Disk: 78%';
1244
+ `,
1245
+ node_id: nodeId
1246
+ })
1247
+ ```
1248
+
1249
+ ---
1250
+
1251
+ ## Snapshots (Automatic)
1252
+
1253
+ Snapshots are created **automatically every 20 mutations** to optimize loading performance.
1254
+
1255
+ ### What is a Snapshot?
1256
+
1257
+ A snapshot is a **mechanical concatenation** of main.code + all mutations up to N:
1258
+
1259
+ ```javascript
1260
+ // snapshot_20.code (auto-generated)
1261
+ // Snapshot at mutation 20
1262
+ // Auto-generated: 2026-02-21T14:30:00.000Z
1263
+
1264
+ // === main.code ===
1265
+ [... full main.code content ...]
1266
+
1267
+ // === 1_add_validation.code ===
1268
+ [... mutation 1 content ...]
1269
+
1270
+ // === 2_change_color.code ===
1271
+ [... mutation 2 content ...]
1272
+
1273
+ ...
1274
+
1275
+ // === 20_optimize_render.code ===
1276
+ [... mutation 20 content ...]
1277
+ ```
1278
+
1279
+ ### Loading Strategy
1280
+
1281
+ When loading an organism with 45 mutations:
1282
+
1283
+ **Without snapshot** (slow):
1284
+ ```
1285
+ Load: main.code + 1.code + 2.code + ... + 45.code
1286
+ = 46 file reads + 45 sequential updates
1287
+ ```
1288
+
1289
+ **With snapshot** (fast):
1290
+ ```
1291
+ Load: snapshot_40.code (includes main + 1-40)
1292
+ Apply: 41.code + 42.code + 43.code + 44.code + 45.code
1293
+ = 1 snapshot read + 5 mutations
1294
+ ```
1295
+
1296
+ **Result**: ~10x faster loading for mature organisms.
1297
+
1298
+ ### Snapshot Management
1299
+
1300
+ - **Creation**: Automatic at mutations 20, 40, 60, 80, ...
1301
+ - **Storage**: Separate .code files (snapshot_N.code)
1302
+ - **Selection**: Automatically picks best snapshot when loading
1303
+ - **No maintenance needed**: System handles everything
1304
+
1305
+ ---
1306
+
1307
+ ## Future: LLM-Based Optimization (plasma_optimize)
1308
+
1309
+ **Status**: Planned, not yet implemented
1310
+
1311
+ **Concept**: Use LLM to intelligently compact mutations
1312
+
1313
+ ```javascript
1314
+ // Future tool
1315
+ plasma_optimize({
1316
+ name: "customer_form",
1317
+ strategy: "smart" // vs "mechanical"
1318
+ })
1319
+ ```
1320
+
1321
+ **What it does**:
1322
+ 1. Read main.code + all mutations
1323
+ 2. LLM analyzes and refactors into optimized main.code
1324
+ 3. Removes dead code (mutation 5 overwrites mutation 2)
1325
+ 4. Simplifies redundant logic
1326
+ 5. Validates result in sandbox
1327
+ 6. Creates backup in .archive/
1328
+ 7. Replaces main.code if validation passes
1329
+
1330
+ **When to use** (future):
1331
+ - Organism has >50 mutations
1332
+ - Loading is slow even with snapshots
1333
+ - Code has accumulated technical debt
1334
+ - User requests optimization
1335
+
1336
+ **Safety**: Always validates result and creates backup first.
1337
+
1338
+ ---
1339
+
1340
+ ## Workflow Examples
1341
+
1342
+ ### Example 1: Create and Evolve a Form
1343
+
1344
+ ```
1345
+ User: "Create a customer entry form with name and email fields"
1346
+
1347
+ You: [Call plasma_create internally with HTML/CSS/JS]
1348
+ "I've created a customer form with name and email input fields and a submit button.
1349
+ Ready to use!"
1350
+
1351
+ ---
1352
+
1353
+ User: "Add validation - email must contain @"
1354
+
1355
+ You: [Call plasma_mutate with email validation JS]
1356
+ "Added email validation. The form will now check that the email contains an @ symbol
1357
+ before allowing submission."
1358
+
1359
+ ---
1360
+
1361
+ User: "Make the submit button blue"
1362
+
1363
+ You: [Call plasma_mutate with button color change]
1364
+ "Changed the submit button color to blue."
1365
+
1366
+ ---
1367
+
1368
+ User: "Show me the form"
1369
+
1370
+ You: [Call dynamic_ui_list_nodes to get node]
1371
+ [Call plasma_load with customer_form]
1372
+ "The customer form is now displayed on your ElectroNode with all updates
1373
+ (validation + blue button). Ready to collect customer data!"
1374
+ ```
1375
+
1376
+ ### Example 2: Dashboard with Live Data
1377
+
1378
+ ```
1379
+ User: "Create a sales dashboard showing revenue and orders"
1380
+
1381
+ You: [Call plasma_create with dashboard HTML/CSS/JS including Chart.js]
1382
+ "I've created a sales dashboard with revenue and orders metrics.
1383
+ It's ready to display on your node. Want me to load it?"
1384
+
1385
+ User: "Yes, and update it with today's data"
1386
+
1387
+ You: [Call plasma_load to display]
1388
+ [Fetch sales data from API/database using other tools]
1389
+ [Call plasma_mutate with data update]
1390
+ "Dashboard is live! Showing today's revenue: $15,234 and 42 orders.
1391
+ The chart reflects the hourly breakdown."
1392
+
1393
+ ---
1394
+
1395
+ [Later, when new sales data arrives via webhook/polling]
1396
+
1397
+ You: [Call plasma_mutate to update numbers]
1398
+ [Update displayed automatically]
1399
+ "Dashboard updated - revenue now at $18,450 (+$3,216)."
1400
+ ```
1401
+
1402
+ ---
1403
+
1404
+ ## Summary
1405
+
1406
+ **PLASMA v2 = Event-Sourced UI with Complete History**
1407
+
1408
+ - **Create** organisms with `plasma_create`
1409
+ - **Mutate** incrementally with `plasma_mutate`
1410
+ - **Load** instantly with `plasma_load` (snapshot support)
1411
+ - **Automatic snapshots** every 20 mutations
1412
+ - **Complete history** of all changes
1413
+ - **Rollback capable** (load specific mutation range)
1414
+ - **Zero LLM cost** for snapshots (mechanical)
1415
+ - **Future-ready** for LLM optimization
1416
+
1417
+ **Three core tools, infinite possibilities, complete auditability.**