Script buttons, live mode and macro recorder pages (PRs #1219-#1225, #1227, #1228, pending); report-arrow submenu fix (#1218, pending)

New pages script_buttons, assistant_live_mode, macro_recorder, linked from the
sidebar, scripting, mcp_server and ai_assistants. ai_assistants: the 29 Sep
section no longer says 'Not merged yet'.
ispyisail
2026-10-02 14:24:13 +13:00
parent 369484cb02
commit 3f935ee183
8 changed files with 769 additions and 1 deletions
+6
@@ -157,6 +157,12 @@
**[Connecting an AI assistant](ai_assistants)** — setup for Claude, Copilot, Gemini, Codex, Cursor, LM Studio
**[Script buttons](script_buttons)** — stored scripts with an icon, by hand or by an assistant _(pending)_
**[Live mode](assistant_live_mode)** — an assistant working in the open project while you watch _(pending)_
**[Macro recorder](macro_recorder)** — record a task by hand, for an assistant to script _(pending)_
**[Development Roadmap](development_roadmap)**
**[Vision](vision)** — _proposal, under discussion_
+20 -1
@@ -230,7 +230,7 @@ The server speaks MCP over standard input and output.
---
## Not merged yet
## Added on 29 September 2026
Four changes make this simpler. All four merged on 29 September 2026, so
they are in builds made after that (on Windows, nightlies newer than
@@ -278,6 +278,24 @@ It also tells you, in bold, when something is missing:
| *Python est introuvable sur cet ordinateur* | the Python the setup names is not there. On Windows, run the QElectroTech installer again and tick *Python pour l'assistant IA*, or install Python; elsewhere, install Python 3 from your system's packages |
| *Python n'est peut-être pas installé* (Windows) | only the Microsoft Store shortcut answers to `python`, which opens the Store instead of running the server |
## Coming next: buttons, live mode, recordings
> **Status: pending.** Described on their own pages, each in open pull
> requests ([#1219](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1219)–[#1225](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1225),
> [#1227](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1227),
> [#1228](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1228)).
> None works until they are merged.
- **[Script buttons](script_buttons)**: ask the assistant for a button; it
writes the script, tests it on a copy of a project, and stores it with an
icon. You press it.
- **[Live mode](assistant_live_mode)**: with a setting turned on and a warning
accepted at each start, the assistant works in the project you have open,
one Ctrl+Z per action.
- **[Macro recorder](macro_recorder)**: do the task once by hand while
recording, paste the request, and the assistant writes a script it has
checked does the same.
## ChatGPT, and Claude or Copilot in a web browser
These reach a server only through the internet, from their own computers.
@@ -290,3 +308,4 @@ still use the server's reading tools on a project you upload to it. See
- **[MCP server](mcp_server)**: every tool and setting
- **[JavaScript Scripting](scripting)**: what edits run underneath
- **[Script buttons](script_buttons)**, **[Live mode](assistant_live_mode)**, **[Macro recorder](macro_recorder)**: pending
+222
@@ -0,0 +1,222 @@
# Live mode: an AI assistant working in the open project
Normally an AI assistant connected through the **[MCP server](mcp_server)**
works on files: it reads a `.qet`, tests changes on copies, and never touches
the drawing you have open. **Live mode** adds a second way of working: the
assistant on one screen, QElectroTech on the other, and each thing it does
happens in front of you, in the project you have open — where you can watch
it, refuse it, undo it, or carry on by hand.
> **Status: pending.** Nothing on this page is merged yet:
>
> | PR | What it adds | Builds on |
> |---|---|---|
> | [#1222](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1222) | the setting, the startup warning, the status-bar indicator, running scripts live | [#1221](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1221) ([script buttons](script_buttons)) |
> | [#1223](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1223) | the *Assistant* panel, ask-first, the allowed commands, the screenshot | #1222 |
> | [#1225](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1225) | the `qet_live_*` MCP tools | [#1224](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1224) |
>
> Check those PRs before trying any of this against your own build. The
> proposal is
> [discussion #1226](https://github.com/qelectrotech/qelectrotech-source-mirror/discussions/1226).
Menu and option names are given in French, as QElectroTech shows them until
the translations are updated, with an English gloss in italics.
---
## The two ways an assistant works
| | Headless (the usual way) | Live |
|---|---|---|
| works on | `.qet` files and copies of them | the project open in your QElectroTech |
| QElectroTech running? | no — started in the background for each call | yes, your own window |
| MCP tools | `qet_*`, `qet_script_*` | `qet_live_*` only |
| what you must switch on | `QET_ENABLE_SCRIPTING=1` | that, **and** the live setting, **and** the warning at this start |
| undo | nothing of yours changed | one Ctrl+Z per assistant action |
A script tested headless runs the same way live; only where it runs changes.
The tools are kept apart so one can never be taken for the other.
---
## Switching it on: three switches
1. **The MCP server** is started with `QET_ENABLE_SCRIPTING=1`, as for the
editing tools (see [Scripting gate](mcp_server#scripting-gate)).
2. **The setting.** In **Configurer QElectroTech > Général** (*Settings >
General*): *Autoriser un assistant IA à agir sur le projet ouvert (mode
direct)* (*Allow an AI assistant to act on the open project (live mode)*).
Off by default. It takes effect at the next start; unticking it cuts the
connection at once.
3. **The warning, at every start.** While the setting is on, each time
QElectroTech starts it shows, before anything can connect:
> *Le mode direct est activé : un assistant IA connecté pourra exécuter des
> scripts sur le projet ouvert. Chaque action s'annule d'un Ctrl+Z, et le
> bouton « Arrêter » de la barre d'état coupe la connexion.*
>
> (*Live mode is on: a connected AI assistant will be able to run scripts on
> the open project. Each action is undone with Ctrl+Z, and the "Stop" button
> on the status bar cuts the connection.*)
| Button | Does |
|---|---|
| *Continuer* (*Continue*) | opens the connection for this session |
| *Pas pour cette session* (*Not this session*) | stays closed until the next start |
| *Désactiver* (*Turn off*) | stays closed and turns the setting off |
So a setting you forgot about can never leave the door open silently.
With the setting off, QElectroTech opens nothing at all and behaves exactly as
it does without this feature; the `qet_live_*` tools answer that live mode is
off and do nothing. When they cannot connect, they say which of the three
switches is missing.
---
## While the assistant is connected
### The status bar
Shows *Mode direct : en attente d'un assistant* (*Live mode: waiting for an
assistant*) or *Mode direct : assistant connecté* (*assistant connected*), then
the last thing it did, with ✓ or ✗ and the time. Hover it for the error, if
there was one.
**Arrêter** (*Stop*) beside it cuts the connection for the rest of the session.
### The Assistant panel
> **Status: pending** — [PR #1223](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1223).
A panel called **Assistant** opens on the right while live mode is open. It
lists every action, newest first: the time, ✓ or ✗, and its undo step's name.
Hover an entry, or double-click it, for the details: the error, what the
script logged, and the script itself.
At the top: *Demander avant d'exécuter un script écrit par l'assistant* (*Ask
before running a script the assistant wrote*), **ticked at every start**. While
it is ticked, a script the assistant wrote on the spot is shown to you first,
in a box titled *L'assistant veut exécuter un script* (*The assistant wants to
run a script*):
| Button | Does |
|---|---|
| *Exécuter* (*Run*) | runs it |
| *Refuser* (*Refuse*) | nothing happens; the assistant is told you refused |
| *Toujours pour cette session* (*Always this session*) | runs it and stops asking until the next start |
Stored scripts — the **[script buttons](script_buttons)** you already have —
run without asking: you put them there.
### Undo
Each assistant action is **one undo step**, named *Assistant : <what it
did>*, in the same undo history as your own work. Ctrl+Z takes it back.
The assistant can undo too (`qet_live_undo_last`), but **only its own last
step**. If the newest step is something you did, it is refused: what you do by
hand stays yours to undo.
---
## What the assistant can do
> **Status: pending** — [PR #1225](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1225)
> (and #1223 for the commands and the screenshot).
| Tool | Does | Needs `QET_ENABLE_SCRIPTING=1` |
|---|---|---|
| `qet_live_status` | is QElectroTech there and live mode open; the project and sheet on screen, how many sheets, what is selected, the last undo step; the stored scripts; whether a [macro recording](macro_recorder) is under way | no |
| `qet_live_run_script` | runs script text on the open project (asks you first, see above); returns what it logged, its error, and the undo step's name | yes |
| `qet_live_run_stored` | presses one of your stored script buttons, by its id | yes |
| `qet_live_command` | runs one editor command from a fixed list (below) | no |
| `qet_live_show_folio` | shows another sheet of the open project | no |
| `qet_live_undo_last` | undoes the newest step, only if it was the assistant's | no |
| `qet_live_screenshot` | an image of the sheet on screen, so the assistant sees what you see | no |
### The commands it may use
Only commands that open no window, so nothing can end up waiting for an
answer nobody gives. Everything else — saving, deleting, exporting, printing —
is refused; for edits it runs a script, which you can undo.
| Command id (`diagrameditor.…`) | |
|---|---|
| `select_all`, `select_nothing`, `select_invert`, `select_all_conductors`, `select_all_text_fields` | selection |
| `zoom_in`, `zoom_out`, `zoom_content`, `zoom_fit`, `zoom_reset` | view |
| `rotate_selection`, `rotate_texts`, `snap_selection_to_grid` | arrange |
| `group_selection`, `ungroup_selection` | [groups](grouping_items) |
| `conductor_reset` | redraw the selected wires' path |
### What it cannot do
- **Click on the screen.** Clicking at coordinates breaks at every layout
change and can be steered by anything drawn on a sheet. The assistant acts
only through the same calls a script button uses.
- **Open a dialog.** `qet.showMessage()` in a live script goes to the log
instead of opening a box.
- **Run two things at once.** One request at a time; a second one meanwhile is
answered "busy". A script still stops after 30 seconds.
- **Reach you over the network.** The connection is a local socket (a named
pipe on Windows), on your own machine only.
---
## How the assistant finds QElectroTech
When you press *Continuer*, QElectroTech adds the connection's name and a
random token to `qet-assistant.json` (see
[script buttons](script_buttons#qet-assistantjson)), readable only by you, and
removes them on *Arrêter* or when it closes. The MCP server reads them from
there; a connection without the token is closed.
The token keeps out other users of the computer and stale connections. A
program already running as you could read your projects anyway, which is why
what you can see — the indicator, the panel, ask-first, undo — matters more
than the token.
---
## The risk, stated plainly
Live mode is the one place an assistant changes the project you have open. The
risk it adds: **text inside a project you received** (a label, a note, a
title-block field) could try to steer the assistant into editing your drawing.
The answers are ask-first for anything the assistant writes itself, the log,
and one Ctrl+Z per action. If you do not need it, leave the setting off.
---
## A session, start to finish
1. Tick the live setting, restart QElectroTech, press *Continuer*. The status
bar says *en attente d'un assistant*; the Assistant panel opens.
2. Open your project. In the assistant's chat: *"number the wires on the sheet
I'm looking at, starting at 100"*.
3. The assistant calls `qet_live_status`, sees the project and sheet, and may
take a `qet_live_screenshot`.
4. It writes a script and sends it with `qet_live_run_script`. The ask-first
box shows it; you press *Exécuter*.
5. The wires are numbered; the panel shows *Assistant : …* with ✓.
Not what you wanted? Ctrl+Z.
6. **Arrêter** when you are done.
---
## Limitations
- **macOS has not been tested.** Linux, and a Windows build under Wine with a
Windows-side client, have.
- **No questions back.** A live script cannot ask you for a value; the
assistant asks in its chat instead.
---
## See also
- **[Script buttons](script_buttons)** — the stored scripts live mode can press
- **[Macro recorder](macro_recorder)** — show the assistant a task instead of describing it
- **[MCP server](mcp_server)** and **[Connecting an AI assistant](ai_assistants)**
- **[JavaScript Scripting](scripting)** — what a script can do
- [Discussion #1226](https://github.com/qelectrotech/qelectrotech-source-mirror/discussions/1226) — the proposal
+12
@@ -93,6 +93,18 @@ A project that has none yet gets the common collection's **Coming arrow** and
**Going arrow**. If the common collection isn't available either, the
submenu is hidden. It is also hidden on a read-only sheet.
> **Status: pending.** The paragraph below describes
> [PR #1218](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1218),
> not yet merged. Until it lands, current builds show the bug it fixes
> ([#1210](https://github.com/qelectrotech/qelectrotech-source-mirror/issues/1210)):
> once you place a Coming arrow, the Going arrow drops out of the submenu
> (and the other way round), and comes back only after closing the project
> without saving.
With #1218 the submenu always lists the standard **Coming arrow** and
**Going arrow**, after the report symbols the project already uses, and each
name appears once. Placing one arrow no longer hides the other.
For what a sheet report does once placed, see
**[Linking wires across pages](folio_links)**.
+167
@@ -0,0 +1,167 @@
# Macro recorder
Do a task once by hand in QElectroTech, with recording on. Then hand the
recording to an AI assistant, which turns it into a general, tested
**[script button](script_buttons)** — "rotate the selected coils half a
turn" rather than "rotate KA1 and KA2".
> **Status: pending.** Nothing on this page is merged yet:
>
> | PR | What it adds | Builds on |
> |---|---|---|
> | [#1227](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1227) | recording in QElectroTech: start, stop, the files, the status bar, the request to paste | [#1223](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1223) |
> | [#1228](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1228) | the `qet_recording_*` MCP tools | [#1225](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1225) |
>
> Both sit at the end of the [script buttons](script_buttons) series. Check
> the PRs before trying any of this against your own build.
> **Not the same "macros" as templates.** QElectroTech's
> **[templates](templates)** — reusable blocks of symbols — live in a folder
> called `macros`. The macro recorder has nothing to do with them: it records
> *what you do*, and its result is a script.
Menu and option names are given in French, as QElectroTech shows them until
the translations are updated, with an English gloss in italics.
---
## Why a recording, and not a replay
Describing a drawing task in words to an assistant is slow and easy to get
wrong. Showing it is quicker. But replaying your mouse clicks would break as
soon as anything on the sheet moved, so the recorder does not keep clicks. It
keeps **what changed**, step by step, and the whole project before and after.
The assistant writes a script from that, and checks the script reproduces
exactly the change you made.
QElectroTech cannot send anything to an assistant itself: the assistant asks,
QElectroTech answers. So the recording is saved where the assistant's
**[MCP server](mcp_server)** can read it, and you hand it over with one paste.
---
## Recording
> **Status: pending** — [PR #1227](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1227).
1. Open the project and select what the task starts from (the selection is
recorded too).
2. **Projet > Scripts > Enregistrer une macro** (*Project > Scripts > Record a
macro*). It is also a command in command search (**Ctrl+Shift+M**) and on
the **S** shortcut bar if you add it.
3. Do the task. The status bar shows *● Enregistrement : N étape(s)*
(*Recording: N steps*) with an **Arrêter** (*Stop*) button.
4. Stop: **Arrêter**, or the same menu entry, which is ticked while recording.
A box, *Macro enregistrée* (*Macro recorded*), gives the recording's name
(*Macro du 02/10/2026 14:30*), its number of steps and its folder:
| Button | Does |
|---|---|
| *Copier la demande pour l'assistant* (*Copy the request for the assistant*) | copies a ready-made request to paste into the assistant's chat |
| *Ouvrir le dossier* (*Open the folder*) | opens the recording's folder |
| *Fermer* (*Close*) | closes the box; the recording stays saved |
Recording needs no setting: it only writes files. Turning it into a script
does — see below.
### What counts as a step
Every entry the task adds to the undo history (*Annulations*, *Undo* panel) is
one step: its name as the Undo panel shows it, which sheet, what
was selected after it, and the sheet as it was after it. Because steps come
from the undo history, any command QElectroTech has is recorded with nothing
to teach the recorder.
- **An undo during the recording** is recorded as a step too.
- **Several moves of the same item in a row** merge into one step, as they do
in the undo history. The before-and-after result is still exact.
- **Closing the project while recording** stops it and keeps the steps so far,
but there is then no "after" project, and the recording says so.
### Where it is saved
In the `recordings` folder of your QElectroTech data folder, one folder per
recording:
| System | Folder |
|---|---|
| Linux | `~/.local/share/QElectroTech/QElectroTech/recordings/` |
| Windows | `%APPDATA%\QElectroTech\QElectroTech\recordings\` |
| macOS | `~/Library/Application Support/QElectroTech/QElectroTech/recordings/` |
```
recordings/<id>/
recording.json name, project, start and stop time, the steps
before.qet the whole project when you started recording
after.qet the whole project when you stopped
steps/003.xml the sheet the step happened on, as it was after step 3
```
`qet-assistant.json` (see
[script buttons](script_buttons#qet-assistantjson)) lists the recordings and
whether one is under way; in **[live mode](assistant_live_mode)**,
`qet_live_status` says so too.
On a very large project, saving `before.qet` and `after.qet` can take a few
seconds, as saving the project does — at start and stop only, not at each
step.
---
## Turning it into a script
> **Status: pending** — [PR #1228](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1228).
Paste the copied request into the assistant's chat. It names the recording and
asks the assistant to read it with `qet_recording_read`, write a script that
does the same **in general** (on the selected items rather than on those
particular ones), check it with `qet_recording_check` until it matches, then
offer it as a button with `qet_script_install`. You can add to it: *"…and make
it work on every sheet"*.
| Tool | Does | Needs `QET_ENABLE_SCRIPTING=1` |
|---|---|---|
| `qet_recording_list` | the recordings, newest first: id, name, steps, project | no |
| `qet_recording_read` | one recording as structured changes — each step's name, sheet, selection and what changed on the sheet ("element KA1 moved by (20, 0)", "wire added between …") — and the overall change from before to after | no |
| `qet_recording_check` | runs a script on a copy of `before.qet`, starting from the same sheet and selection you had, and compares the result with `after.qet`: **matches**, or what differs | yes |
| `qet_recording_remove` | deletes one recording | yes |
`qet_recording_check` is what makes "the script does what I did" a measured
fact rather than the assistant's guess. A rotation by the wrong angle, a
script that does nothing, or one that fails — each is reported, the last with
the line that failed.
---
## Worked example
1. Select the two coils on a sheet.
2. **Projet > Scripts > Enregistrer une macro**.
3. Rotate the selection twice (Space, Space).
4. **Arrêter** → *Copier la demande pour l'assistant* → paste into the chat.
5. The assistant reads 2 steps, writes "rotate every selected symbol by 180°",
and `qet_recording_check` reports a match. A first try at 90° would be
reported a quarter turn off.
6. It installs the script; a **Scripts** toolbar button appears. Next time,
select any symbols and click it.
---
## Limitations
- **One project per recording.**
- **No clicks or positions replayed** — on purpose, see above.
- **QElectroTech does not call an assistant itself.** That would mean API
keys, network access and a choice of provider inside QElectroTech: a
different project.
- **macOS has not been tested.**
---
## See also
- **[Script buttons](script_buttons)** — where the resulting script ends up
- **[Live mode](assistant_live_mode)** — the assistant acting in the open project
- **[MCP server](mcp_server)** and **[Connecting an AI assistant](ai_assistants)**
- **[JavaScript Scripting](scripting)**
+13
@@ -244,6 +244,17 @@ from before the setting existed need nothing.
\* Needs `QET_ENABLE_SCRIPTING=1`.
> **Status: pending.** Three more groups of tools are in open pull requests,
> each described on its own page:
>
> | Tools | Page | PR |
> |---|---|---|
> | `qet_script_api`, `qet_script_test`, `qet_script_install`, `qet_script_list`, `qet_script_read`, `qet_script_remove`, `qet_about` | [Script buttons](script_buttons#letting-an-ai-assistant-write-the-script) | [#1224](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1224) |
> | `qet_live_status`, `qet_live_run_script`, `qet_live_run_stored`, `qet_live_command`, `qet_live_show_folio`, `qet_live_undo_last`, `qet_live_screenshot` | [Live mode](assistant_live_mode#what-the-assistant-can-do) | [#1225](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1225) |
> | `qet_recording_list`, `qet_recording_read`, `qet_recording_check`, `qet_recording_remove` | [Macro recorder](macro_recorder#turning-it-into-a-script) | [#1228](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1228) |
>
> None of them works until its PR is merged.
---
## Worked examples
@@ -460,6 +471,8 @@ regression in the thing under test, not a missing switch.
- **[Connecting an AI assistant](ai_assistants)** — setup for each assistant
- **[JavaScript Scripting](scripting)** — the `qet.*` engine `qet_edit` and
`qet_query` drive underneath
- **[Script buttons](script_buttons)**, **[Live mode](assistant_live_mode)**,
**[Macro recorder](macro_recorder)** — the pending script, live and recording tools
- **[The project database](project_database)** — what `qet_query` reads
- **[CLI Reference](cli_reference)** — the export flags `qet_export` wraps
- **[Automating QElectroTech](api_reference)** — the file-format and
+303
@@ -0,0 +1,303 @@
# Script buttons
Keep a JavaScript script in QElectroTech, give it an icon and a shortcut, and
run it from a button, a menu, the shortcut bar or command search — instead of
picking the file again every time. You can write the script yourself, or let
an AI assistant write, test and store it through the
**[MCP server](mcp_server)**. Both end in the same place: a file in your
scripts folder, which QElectroTech turns into a button.
> **Status: pending.** Nothing on this page is merged yet; the series starts
> with [PR #1219](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1219). Each section names
> its own pull request; check it before trying any of this against your own
> build. The whole series:
>
> | PR | What it adds | Builds on |
> |---|---|---|
> | [#1219](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1219) | `qet.currentFolio()`, `qet.apiSignatures()`, one undo step per run | — |
> | [#1220](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1220) | stored scripts, the *Scripts* menu and toolbar | #1219 |
> | [#1221](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1221) | the script manager window | #1220 |
> | [#1224](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1224) | MCP tools to write, test and store scripts | — |
>
> The proposal and its open questions are in
> [discussion #1226](https://github.com/qelectrotech/qelectrotech-source-mirror/discussions/1226).
> The same series continues with **[live mode](assistant_live_mode)** and the
> **[macro recorder](macro_recorder)**.
Menu and option names are given in French, as QElectroTech shows them until
the translations are updated, with an English gloss in italics.
---
## Why this exists
**[JavaScript Scripting](scripting)** already lets a script read a project,
edit it with real undo, and export it. But from the editor, *Exécuter un
script…* (*Run script*) asks for a file every time, and a script cannot tell
which sheet you are looking at. So a repeated task — put a revision note on
this sheet, renumber the selected wires, rotate the selected coils — stays a
chore. Script buttons make a script a command like any other.
## Before you start: scripting must be on
Scripts are **off by default**
([PR #984](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/984)).
A script runs with your rights: it can read and change the open project and
write files. The setting is in **Configurer QElectroTech > Général** (*Settings
> General*): *Autoriser l'exécution de scripts JavaScript* (*Allow running
JavaScript scripts*). If it is off, the first time you press a script button
QElectroTech asks whether to turn it on. Nothing on this page gets around that
switch.
---
## The scripts folder
> **Status: pending** — [PR #1220](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1220).
Each script is one `.js` file in the `scripts` folder of your QElectroTech
data folder:
| System | Folder |
|---|---|
| Linux | `~/.local/share/QElectroTech/QElectroTech/scripts/` |
| Windows | `%APPDATA%\QElectroTech\QElectroTech\scripts\` |
| macOS | `~/Library/Application Support/QElectroTech/QElectroTech/scripts/` |
If you start QElectroTech with `--data-dir`, the folder moves with it.
**Projet > Scripts > Ouvrir le dossier des scripts** (*Project > Scripts >
Open the scripts folder*) opens it, creating it if needed.
QElectroTech watches the folder. Drop a script in and its button appears
straight away; delete it and the button, its menu entry and its shortcut go.
No restart, and nothing to register.
Scripts are yours, not the project's: nothing is added to the `.qet` file, and
a project you receive cannot bring a script with it.
### The header
The top of the file says how the button looks. One file holds both, so there
is nothing to keep in step and one file to share:
```js
// ==QETScript==
// @name Add revision note
// @icon note.svg
// @tooltip Puts a "Rev A" note on the sheet you are looking at
// @shortcut Ctrl+Alt+R
// @context canvas
// @api 1
// ==/QETScript==
var f = qet.currentFolio();
qet.addText(f, "Rev A", 40, 40);
```
| Key | Required | Meaning |
|---|---|---|
| `@name` | **yes** | the button's text, and the name shown in menus, command search and the undo history |
| `@icon` | no | a picture file next to the script (`note.svg`, `note.png`), or `builtin:<name>` for an icon from QElectroTech's theme. Left out: a tile with the name's initials |
| `@tooltip` | no | the text shown when you hover the button |
| `@shortcut` | no | a keyboard shortcut, written as Qt writes them (`Ctrl+Alt+R`). A shortcut you set in the shortcut settings wins over it |
| `@context` | no | when the button is usable — see the next table. Default `canvas` |
| `@api` | no | the header version; only `1` exists |
| `@context` | The button works when… |
|---|---|
| `canvas` | a project is open (always) |
| `selection` | something is selected on the sheet |
| `conductor` | at least one wire is selected |
Without an open project every script button is greyed out.
**A wrong header is refused, not ignored.** An unknown key (`@shortcutt`), a
missing `@name`, an unknown `@context` or an `@api` other than `1` means no
button. The file is listed greyed in **Projet > Scripts** as *Ignoré :
broken.js: unknown header key @shortcutt* (*Ignored*), so you can see which
line is wrong. A misspelt shortcut that silently did nothing would be harder
to find.
A file name becomes the script's id: `add-revision-note.js` is
`diagrameditor.script.add-revision-note` in the shortcut settings.
---
## Running a script
> **Status: pending** — [PR #1220](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1220).
Every stored script is an ordinary command, so you can reach it any of these
ways:
| Where | How |
|---|---|
| **Projet > Scripts** (*Project > Scripts*) | one entry per script, with its icon |
| the **Scripts** toolbar | one button per script. Hidden while the folder has no script, shown once the first one arrives |
| its keyboard shortcut | `@shortcut`, or one you set in the shortcut settings |
| the **S** shortcut bar | add it with "…" → Customise, like any command (see [Drawing faster](drawing_faster)) |
| command search, **Ctrl+Shift+M** | type the script's name |
Below the scripts, the **Projet > Scripts** menu holds:
| Entry | Does |
|---|---|
| *Enregistrer une macro* (*Record a macro*) | see **[Macro recorder](macro_recorder)** (PR #1227) |
| *Gérer les scripts…* (*Manage scripts*) | the script manager, below |
| *Exécuter un script...* (*Run script*) | run any `.js` file once, as before — it moves here from the *Projet* menu |
| *Ouvrir le dossier des scripts* | open the scripts folder |
### One click, one Ctrl+Z
> **Status: pending** — [PR #1219](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1219).
A script run from the editor is **one undo step**, named *Script : &lt;name&gt;*.
A button that adds twenty items is undone with one Ctrl+Z, not twenty. This
also applies to *Exécuter un script…*. A script that changes nothing leaves no
empty step behind. Headless `--run` keeps one step per call, as before.
### Which sheet the script works on
> **Status: pending** — [PR #1219](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1219).
`qet.currentFolio()` returns the index of the sheet on screen, so a button
acts where you are looking. Headless (`--run`, or an assistant testing a copy)
it returns `0`, the first sheet, so the same script can be tried without a
window. It returns `-1` if the project has no sheet.
---
## The script manager
> **Status: pending** — [PR #1221](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1221).
**Projet > Scripts > Gérer les scripts…** (*Manage scripts*) lists your
scripts with their icons on the left, and edits the selected one on the right.
| Field | Header line it writes |
|---|---|
| *Nom :* (*Name*) | `@name` |
| *Icône :* (*Icon*) | `@icon`. Leave it empty for the initials tile, type `builtin:<name>` for a theme icon, or click the preview to choose an SVG or PNG — the file is copied into the scripts folder |
| *Info-bulle :* (*Tooltip*) | `@tooltip` |
| *Raccourci :* (*Shortcut*) | `@shortcut` |
| *Actif :* (*Active*) | `@context`: *Toujours* (*Always*), *Avec une sélection* (*With a selection*), *Avec un conducteur sélectionné* (*With a wire selected*) |
Below the fields is the script's text, a plain text editor.
| Button | Does |
|---|---|
| *Nouveau* (*New*) | starts a script called *Nouveau script* from a template |
| *Enregistrer* (*Save*) | writes the file; the button appears or updates |
| *Tester* (*Test*) | saves, then runs it on the current project. Ctrl+Z takes it back |
| *Supprimer* (*Delete*) | asks, then deletes the file, and its icon if no other script uses it |
| *Ouvrir le dossier* | opens the scripts folder |
| *Fermer* (*Close*) | asks whether to save first if the script was changed |
A script whose header is wrong is listed with the reason (*Pas de bouton :
…*, *No button*), and *Enregistrer* refuses to save a header that would give
no button, with the reason under the editor.
The manager only writes files. The folder does the rest, so the manager, a
text editor and an AI assistant can never disagree about what a script is.
---
## Letting an AI assistant write the script
> **Status: pending** — [PR #1224](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1224).
With the **[MCP server](mcp_server)** set up
(**[Connecting an AI assistant](ai_assistants)**), you can ask: *"make me a
button that puts a Rev A note on the sheet I'm looking at"*. The assistant:
1. reads the call list with `qet_script_api`,
2. writes the script and tries it with `qet_script_test` — on a **copy** of
one of your projects, which it then compares with the original, so you see
what it would change,
3. stores it with `qet_script_install`, optionally with an SVG icon it drew.
The button appears in your open QElectroTech. **The assistant never presses
it**: you do. (To let it act on the open project, see
**[live mode](assistant_live_mode)**.)
| Tool | Does | Needs `QET_ENABLE_SCRIPTING=1` |
|---|---|---|
| `qet_script_api` | every call a script can make, with its arguments, taken from the QElectroTech it targets | yes |
| `qet_script_test` | runs script text on a copy of a project and returns what changed (a `qet_diff`); the project is never modified | yes |
| `qet_script_install` | stores a script as a button: checks the header, writes `<id>.js` and optionally `<id>.svg`. Given `test_project`, it tests first and refuses a script that fails | yes |
| `qet_script_list` | the stored scripts, with their header fields, and the files that give no button and why | no |
| `qet_script_read` | the text and icon of one stored script | no |
| `qet_script_remove` | deletes a stored script, and its icon if no other script uses it | yes |
| `qet_about` | what QElectroTech last wrote about itself: its folders, whether scripting is on, its stored scripts | no |
`QET_ENABLE_SCRIPTING=1` goes in the environment the MCP server is started in,
as for the editing tools (see [Scripting gate](mcp_server#scripting-gate)).
**Where the server puts scripts.** The server chooses the folder; a tool call
cannot. In order: `QET_MCP_SCRIPTS_DIR` if set; else the folder QElectroTech
named in `qet-assistant.json`; else the platform folder in the table above.
Set `QET_MCP_SCRIPTS_DIR` if you start QElectroTech with `--data-dir` and it
has not run since.
### qet-assistant.json
Whenever an editor window opens, and whenever the stored scripts or the
settings change, QElectroTech writes `qet-assistant.json` in the platform data
folder (`~/.local/share/QElectroTech/QElectroTech/` on Linux,
`%APPDATA%\QElectroTech\QElectroTech\` on Windows) — there even when
`--data-dir` moves everything else, so the server can always find it. It
lists QElectroTech's version, every folder in use (data, settings, scripts,
element and title block collections), whether scripting and live mode are on,
every script call, the stored scripts and the ones refused, and — only while
live mode is open — how to reach it. Only you can read it. `qet_about` shows
it to the assistant, without the live-mode token.
---
## Worked example: a button by hand
1. **Projet > Scripts > Ouvrir le dossier des scripts**.
2. Save this as `rotate-selected.js` there:
```js
// ==QETScript==
// @name Rotate selected half a turn
// @tooltip Rotates every selected symbol on this sheet by 180°
// @context selection
// ==/QETScript==
var f = qet.currentFolio();
var uuids = qet.selectedElements(f);
for (var i = 0; i < uuids.length; i++)
qet.rotateElement(f, uuids[i], 180);
qet.log("rotated " + uuids.length + " symbol(s)");
```
With no `@icon`, the button shows a tile with the name's initials. Other calls are
listed on **[JavaScript Scripting](scripting)**, and `qet.apiSignatures()`
returns every call your QElectroTech knows.
3. The **Scripts** toolbar appears with the new button, greyed until you
select something.
4. Select some symbols, click. One Ctrl+Z undoes all the rotations.
---
## Limitations
- **Your folder only.** No scripts per project or shared across a company yet
(open question 3 in discussion #1226).
- **No questions to the user.** A script cannot yet ask for a value when you
press its button; one button does one thing.
- **macOS has not been tested.** Linux and Windows have, including a Windows
build run under Wine.
- **No arbitrary menu commands from a script**, as before — see
[JavaScript Scripting](scripting#limitations-on-purpose).
---
## See also
- **[JavaScript Scripting](scripting)** — every call a script can make
- **[Live mode](assistant_live_mode)** — an assistant running scripts in the open project while you watch
- **[Macro recorder](macro_recorder)** — do a task by hand once, and let an assistant turn it into a button
- **[MCP server](mcp_server)** and **[Connecting an AI assistant](ai_assistants)**
- **[Drawing faster](drawing_faster)** — the shortcut bar and command search scripts appear in
- [Discussion #1226](https://github.com/qelectrotech/qelectrotech-source-mirror/discussions/1226) — the proposal
+26
@@ -52,6 +52,15 @@ qelectrotech --run export_after_revision.js "$1"
and runs the chosen script against the *currently open* project. Useful for
one-off macros you don't want to wire into CI.
> **Status: pending.** [PR #1220](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1220)
> moves this entry to **Projet → Scripts → Exécuter un script...**, and adds
> stored scripts with their own button, icon and shortcut — see
> **[Script buttons](script_buttons)**.
> [PR #1219](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1219)
> makes a run from the editor **one undo step**, named *Script : &lt;name&gt;*,
> so one Ctrl+Z undoes the whole script; headless `--run` keeps one step per
> call. Neither is merged yet.
---
## What a script can do
@@ -245,6 +254,20 @@ Every method above is either non-blocking by construction, or — for
`showMessage` — safe under QET's existing non-interactive mode, which is
already on for the whole process before any headless script runs.
### Which sheet is on screen, and what calls exist
> **Status: pending** — [PR #1219](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1219), not yet merged.
```js
var f = qet.currentFolio() // index of the sheet on screen; 0 headless; -1 if the project has none
qet.apiSignatures() // every call this build offers, with its arguments
```
`currentFolio()` lets a script act where the user is looking, which a
[script button](script_buttons) needs. `apiSignatures()` comes from the
running build itself, so a list made from it (as the MCP server's
`qet_script_api` does) cannot drift from what the build really has.
### Logging
```js
@@ -353,5 +376,8 @@ change of mind shows up in one obvious place:
- **[Automating QElectroTech](api_reference)** — the file-format and headless
export ground this builds on
- **[MCP server](mcp_server)** — an AI assistant driving this engine through `qet_edit`/`qet_query`
- **[Script buttons](script_buttons)** — store a script and run it from a button _(pending, [PR #1220](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1220))_
- **[Live mode](assistant_live_mode)** — an assistant running scripts in the open project _(pending, [PR #1222](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1222))_
- **[Macro recorder](macro_recorder)** — record a task by hand for an assistant to script _(pending, [PR #1227](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1227))_
- [PR #891](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/891) — implementation, with the exact tests run against it
- [Issue #162](https://github.com/qelectrotech/qelectrotech-source-mirror/issues/162) — the original request and design discussion