Home (All Topics) → Technology → Software → AI-Created Software
The following AI-generated aka vibe-coded software. The software is specific to my needs and my system and may not work for you or your system. Support is limited, but if you report a bug I'll certainly look into it. All code is provided in a zip file for you to review should you choose.
A Windows desktop library for your Python, PowerShell and batch scripts. Scriptary reads each script’s arguments and turns them into a form. It remembers the values you use and runs scripts in a built-in console with full colour and live progress output. It also records changes to your library so you can undo them, roll them back or restore a single script.
.py, .ps1 and .bat scripts, with groups, virtual folders, labels, clones and notes.argparse code, PowerShell arguments from the param() block, and batch arguments from %1–%9.\r updates display correctly, and you can type input back to the script.%OneDrive% or %SCRIPTARY_HOME%, so a shared library works on several machines.
| Component | Needed? | Purpose |
|---|---|---|
| Windows | Required | Scriptary uses Windows APIs (ConPTY, UAC, Explorer integration). |
| Python 3.9 or later | Required | Runs Scriptary itself. |
pyte |
Required | Terminal emulation for the output console. |
pywinpty |
Rarely needed | A fallback pseudo-console for Windows versions older than 10/1809. Scriptary uses the pseudo-console built into Windows directly, so on current Windows this is not required. |
pystray and Pillow |
Optional | System tray icon; closing the window then minimises to the tray. |
| Archivo font | Optional | The interface is designed around Archivo. Put its .ttf files in Resources\Fonts next to scriptary.pyw (no installation needed) or install it; otherwise Segoe UI is used. |
PowerShell 7 (pwsh.exe) |
Optional | Needed only for PowerShell scripts written for version 7. See Which PowerShell?. |
Install everything with:
python -m pip install pyte pystray pillow
If pyte is missing when Scriptary starts, it offers to install it for you.
Put scriptary.pyw (and scriptary.ico, if you have it) in a folder of your choice.
Double-click scriptary.pyw, or run:
pythonw scriptary.pyw
Click + Add to register a script, or 🔍 Scan to add every script in a folder tree. Both are in the button grid at the bottom of the sidebar.
Select a script, fill in its parameters, and click ▶ Run.
Only one copy of the GUI runs at a time. Starting it again brings the existing window to the front.
By default, Scriptary keeps its data files next to scriptary.pyw — or next to the executable, when it has been built into one. To keep them somewhere else, pass --config-dir:
pythonw scriptary.pyw --config-dir "C:\Scriptary\config"
pythonw scriptary.pyw --config-dir configs\myteam
A relative path is resolved from the folder containing scriptary.pyw (or the executable).
For picking up changes to Scriptary’s own code, start it with --show-self-restart-option TRUE:
pythonw scriptary.pyw --show-self-restart-option TRUE
Manage ▾ then ends with Restart Scriptary, and the tray menu has Restart above Exit. Scriptary closes and starts again with the same command line, --config-dir included, and reopens as it always does (same window, sort, collapsed sections and selected script; no output tabs). The option also accepts =TRUE, and 1, YES or ON in any case; anything else, or leaving it out, keeps the entry hidden.
Restarting, like exiting, asks first when parameter changes are unsaved or scripts are still running. Scripts running in output tabs are stopped. A script running as administrator in its own window keeps running, but its result is not recorded.
| Action | What it does |
|---|---|
| + Add | Register one script. If the file is already in the library, a clone is added instead (see below). The new script goes into the selected script’s group or folder. |
| 🔍 Scan | Recursively add every .py, .ps1 and .bat file in a folder. Files already registered are skipped. |
| ⟳ Refresh | Re-read every script. Files that haven’t changed since the last read are skipped; files that have disappeared are marked missing. |
| Refresh This Script (right-click) | Re-read one script regardless of its modification time. Its clones are refreshed with it, and unsaved values are kept for arguments that still exist. |
| Clone (right-click) | Add a second entry for the same file, with its own label and saved parameters. Useful for keeping several presets of one script. |
| Locate File… / Change File… (right-click) | Point an entry at a moved or renamed file. If other missing scripts moved the same way (for example, a whole folder was moved), Scriptary offers to relink them too. |
| − Remove | Remove the selected script from the library. The file on disk is not touched, and the removal can be undone. |
When a registered file can’t be found, the script’s detail panel shows a red banner with a Locate file… button.
| Script type | Method | Badge |
|---|---|---|
| Python | Static analysis of argparse calls. The script is only read, never run. |
⬤ detected via static analysis |
| Python, with Argument detection enabled | Runtime probe, then static analysis, then parsing --help output. More accurate for scripts that build their parsers dynamically, but the script is executed. |
⬤ detected via runtime probe / –help output |
| PowerShell | The param() block: parameter names, types and [switch] parameters. The .SYNOPSIS comment is used as the description. |
⬤ PowerShell script |
| Batch | %1–%9 tokens. A REM or :: comment on the line above a token’s first use becomes its help text. |
⬤ Batch script |
For a single Python script, Detect Arguments by Running Script… (right-click) runs the full detection once without turning the global option on. You are asked to confirm first, because any side effects of running the script will really happen.
Scriptary also looks for two other traits, shown next to the detection method and usable as filters:
Out-GridView or message boxes in PowerShell.
.bat, .ps*, .py*. Ticking several options narrows the list further. While filters or a search are active, a strip under the search box shows each filter as a chip (click one to remove it) and how many scripts are shown, e.g. 9 of 31.
Above the parameters, the selected script’s name is shown with a red ADMIN badge if it needs elevation. Under it is a line giving the script’s path, how its arguments were read and how many there are. ✎ Note, Clone and History on the right do the same as the matching right-click menu items.
Each detected argument gets a row:
*, and ⓘ shows the argument’s help text.%USERPROFILE%\Documents are expanded when the script runs.Panel actions:
| Button | Action |
|---|---|
| Save | Save the current values for this script. |
| Clear | Empty every field. |
| ↕ Fit | Resize the panel to show every parameter, while keeping room for the console. |
| ▶ Run | Run with the current values; they don’t have to be saved first. |
| ⛨ Admin | Shown for scripts that need elevation (see below). |
Unsaved edits are kept when you switch between scripts. The ● Unsaved cell in the sidebar turns red and shows how many scripts have unsaved changes; clicking it jumps to the first one.
Scriptary warns you before discarding unsaved edits.
The COMMAND box under the parameters shows the exact command that will be run, updated as you type, with the flags highlighted. A command too long for one line wraps, and the box grows to show it — up to six lines, after which it scrolls. Copy puts it on the clipboard.
Elevated scripts run in their own console window after a UAC prompt, because Windows doesn’t let an elevated process’s output be captured in a non-elevated window. The exit code is still recorded in the library.
Run as administrator is also available from the right-click menu for any script.
If Scriptary itself is already running as administrator, ▶ Run is enough and the extra button is hidden.
Every run opens a new tab in the output area.
\r updates display as they would in a terminal (requires pyte).pythonw.exe scripts: if the Python path points at pythonw.exe, the matching python.exe is used, since pythonw has no console to show output in.The minimum console height can be set with the console_min_height key in the settings file.
The Interpreters & execution strip at the top always shows which interpreters will run, e.g. python 3.12.4 · pwsh 7.4.5 · cmd /K /E:ON (versions are read in the background). Click it to open or close the settings below it; it starts closed on a new install. Every field remembers its history; the 🗑 button next to a field removes the current entry from that history.
| Field | Purpose |
|---|---|
| Python path | The interpreter used for Python scripts. Leave empty to use the Python that runs Scriptary. |
| Python execute | Run any Python command line in a new tab. |
| PowerShell path | The PowerShell executable, plus any options, used for .ps1 scripts, e.g. "C:\Program Files\PowerShell\pwsh.exe" -NoLogo -NonInteractive -File.Leave empty to use powershell.exe -NoProfile -ExecutionPolicy Bypass -File (Windows PowerShell 5.1). |
| PowerShell execute | Run any PowerShell command line in a new tab. |
| Command execute | Run any command line in a new tab. |
| Command options | /C exits after running, /K keeps cmd.exe open (and takes priority over /C), and /E turns command echoing on. |
| Argument detection | Allows Python scripts to be executed when their arguments are detected (see How arguments are detected). |
pwsh.exe (PowerShell 7) is the current, actively developed version. Use it for new scripts, for scripts marked #Requires -Version 7, and when you want UTF-8 file handling by default.powershell.exe (Windows PowerShell 5.1) is built into Windows. Use it for scripts that depend on older Windows-only modules or commands such as Get-WmiObject.The two versions have separate profiles, module folders and execution-policy settings, so a script can behave differently between them.
Note: with the PowerShell path left empty, every PowerShell run (normal, elevated and command-line) uses
powershell.exe -NoProfile -ExecutionPolicy Bypass -File, i.e. Windows PowerShell 5.1. Set the path topwsh.exeto use PowerShell 7 everywhere.
Scriptary records every meaningful change to the library, saved parameters and interpreter settings, and lets you reverse them.
↶ Undo (Ctrl+Z) and ↷ Redo (Ctrl+Y), on the right of the Interpreters & execution strip, reverse and reapply library changes:
A confirmation lists what the change did and warns if the same scripts were changed again afterwards. Hovering over ↶ Undo shows what it would undo. When a removed script comes back, it is selected and scrolled into view, even inside a collapsed group or behind an active search.
In text fields, Ctrl+Z and Ctrl+Y keep their normal text undo and redo.
Open it with History in the top strip, or with History… in a script’s right-click menu to see only that script’s changes. The list shows every recorded change, newest first; undone changes are greyed out. The pane below shows exactly what changed, with old → new values.
| Action | Available in | What it does |
|---|---|---|
| Undo this change | All changes | Reverses only the selected change. On an entry that was itself an undo, this becomes Redo. |
| Roll back to before this | All changes | Returns the library, saved parameters and recorded settings to their state just before the selected change. The roll-back is recorded as a single change, so it can be undone too. |
| Restore this script | One script (the Only … checkbox) | Puts that script back as it was before the selected change. Its library entry (arguments, description, note, label, group, folder) is restored and saved. Its parameter values are loaded as unsaved edits, so you can review them and press Save to keep them. Other scripts are not affected. |
Recorded: – script entries, groups, folders, labels and notes; – saved parameters; – Python and PowerShell paths, command options, the argument-detection option, and the minimum console height.
Not recorded: – window size and position, pane sizes, collapsed groups, the list’s sort, and the selected script; – the text in the execute fields, and field histories; – last-run times and results.
To keep the history small and readable: – Saves that change nothing are skipped. – Repeated edits with the same label within two minutes are merged into one entry, and an edit that ends up back where it started disappears. – Only the previous values of what changed are stored, not copies of whole files. – Old entries are pruned after 60 days, or beyond 300 entries.
A chain runs scripts one after another, each in its own output tab, stopping at the first that does not exit 0. It saves writing a wrapper script for “back up, then sync, then tidy”.
A chain is a thing of its own, with its own name and its own order — not an order stored on the scripts. A script can appear in several chains, or more than once in one, and where it is filed stays a separate question from what runs after it.
Manage ▾ → Chains…
| Action | What it does |
|---|---|
| + New chain | Create an empty chain and name it. |
| + Add selected | Append whatever is selected in Scriptary’s list. The list stays usable while the editor is open, so search it, filter it or open a group to find what you want. A script that cannot be a step is refused, with the reason. |
| ↑ / ↓ | Move the selected step earlier or later. |
| − Remove step | Take a step out of the chain. |
| Rename / − Remove | Rename the chain, or delete it. The scripts stay in the library. |
| Shortcut… | Give the chain a keyboard shortcut (see Keyboard shortcuts). |
| Select in Library | Jump to the selected step’s script. |
| ▶ Run chain | Run it now. |
Every change to a chain is recorded, so Undo reverses it like any other library change.
Chains ▾, next to Manage, lists your chains — click one to run it. Or press ▶ Run chain in the editor, or the chain’s keyboard shortcut if it has one (the menu shows it).
You can also build a chain without opening the editor: right-click a script → Add to chain, which lists your chains and the step the script would become, and offers New chain….
Each step opens its own tab, named 2/4 sync.ps1, and the tab is brought to the front as its step starts. At the top of each tab is a line saying where it sits in the chain and how the previous step ended. When a step fails, its tab says so and names the steps that were not run:
Chain 'Nightly' stopped: step 2 of 4 exited 3.
Not run: 3/4 tidy.py, 4/4 report.py
Stopping a step with ⏹ Stop counts as a failure and ends the chain.
A chain is checked before it starts, and will not start at all if any step cannot run — better to be told up front than to stop half way.
/C. A .bat normally runs inside a cmd.exe that is kept open for you to type into, which never ends — and so would never hand the chain its exit code. Chained batch steps exit instead, whatever Command options says.
A schedule attaches times to a script and does one of two things when a time comes round:
A schedule belongs to one script entry. For a script with clones, each clone has its own schedules and runs on its own saved values.
Right-click a script → Schedule ▸:
| Item | What it does |
|---|---|
| Run Automatically… | Make a schedule that runs the script. |
| Remind Me to Run It… | Make a reminder. |
| Change: … | One item for each schedule the script already has. |
| All Schedules… | Open Manage ▾ → Schedules…. |
Choose when it should happen:
| When | Example |
|---|---|
| On chosen days at a time | Every day at 02:00; weekdays at 09:00 |
| Every N minutes, hours or days, from a start time | Every 15 minutes from 14:05 (:05, :20, :35, :50) |
| Monthly on a day at a time | The 1st at 09:00. A day the month doesn’t have (the 31st in April) means its last day. |
| Once at a date and time | 2026-10-03 at 18:00. It removes itself once done. |
| N days after its last successful run (reminders only) | 30 days after the script last exited 0 |
The dialog shows the next few times as you type, so you can check it before saving.
Manage ▾ → Schedules… lists every schedule with what it does, when it next happens and how the last one went. From there you can add a schedule for the selected script, change one, turn it off and on, or remove it.
Adding, changing, turning off and removing a schedule are recorded in History, so Undo reverses them.
A scheduled run differs from clicking ▶ Run in a few ways, all because nobody is at the panel when it starts:
⏱ backup.py), headed with its schedule. The tab you are looking at stays in front, and the status bar says the run started. When the schedule’s next run starts, it replaces the previous run’s tab if that run has finished./C, as chain steps do, so that they finish and return their exit code.Missed runs. If Scriptary wasn’t running at a scheduled time, or the computer was asleep, the schedule runs once when Scriptary is next running, however many times were missed. Untick If Scriptary was not running at the time, run it once when it next is to skip missed times instead.
Several runs due at once start a few seconds apart. A run counts as missed when it starts more than five minutes late.
Changing a schedule starts it afresh. Times before the change, or before a schedule was turned back on, never count as missed.
scriptary.pyw run (a command-line run counts once the window next reads the library: ⟳ Refresh or a restart).
Schedules are stored in the library (COMPUTER_registry.json). What has happened to each schedule is stored in COMPUTER_settings.json and isn’t part of History: when it last ran, what it noted, snoozes and skips. Like everything else, schedules are per computer, so a shared configuration folder doesn’t run a script on every PC.
Manage ▾, on the right of the Interpreters & execution strip, opens reports over the whole library. Each shows a count beside its name when there is something to look at.
| Report | Shows |
|---|---|
| Parameter Names | Every parameter name in the library, grouped so that different spellings of one name sit together, with a bulk rename. |
| Parameters Without Help | Every parameter whose ⓘ would have nothing to show (see below). |
| Unused Saved Values | Values saved under a name no parameter of the script has any more, and values left behind by scripts you removed. |
| Run Report | Runs, successes, typical durations and failing streaks per script. |
| Archived Scripts | Every archived script and the date it was archived, to unarchive or remove from Scriptary (see below). |
Manage ▾ also opens the Chains and Schedules editors and the Keyboard Shortcuts list, with counts. The Schedules count includes how many reminders are due.
Each Manage window is open once at most: choosing it again, from the menu or with its keyboard shortcut, brings the open window to the front.
Select in Library, in the reports that offer it, opens every group and folder so the script is reached even if its section is collapsed. A search that narrows the script out of the list is the one thing that can hide it; the status bar says so.
A parameter’s help text is read from the script itself — help= on a Python argument, a comment above a PowerShell parameter, a REM or :: comment above a batch token — and it is what the ⓘ beside the parameter shows. Anything without one leaves you guessing when you fill the form.
The report lists one row per undocumented parameter, with the script, the parameter, what the script is written in, and the folder the file is in. Select a row and click Select in Library (or double-click it) to jump to that script.
Write the help in the script, then use Refresh This Script from the right-click menu to read it again. Clones share their file’s parameters, so each file is listed once, and scripts whose file is missing are left out — their parameters are the last ones read and there is no file to edit.
Right-click a script → Archive takes it out of the list and out of search results without forgetting it: its label, note, group, saved parameter values and run history all stay, and the date and time it was archived is recorded. Archived scripts are also left out of Parameter Names, Parameters Without Help and the Run Report, and out of the command line’s list.
A script that is a step of a chain can’t be archived — the chain would stop running with nothing in the list to explain why. Scriptary tells you which chains use it; remove it from them in Manage ▾ → Chains… first.
Manage ▾ → Archived Scripts… lists every archived script, newest first, with the date it was archived, what it is written in and its folder. Select one or more rows, then:
| Button | What it does |
|---|---|
| Unarchive | Puts the scripts back in the list, in the group or folder they were in, and selects the first. |
| Remove from Scriptary… | After asking, removes the scripts from the library together with their saved parameter values. The files on disk are not deleted. |
Both are recorded in the change history, so Undo reverses either. Adding a file that is only in the archive (+ Add) offers to unarchive it instead of adding it again.
All files are prefixed with the computer name, so several PCs can share one config folder (for example, on OneDrive) without overwriting each other’s data.
| File | Contents |
|---|---|
COMPUTER_registry.json |
The script library: entries, detected arguments, groups, folders, labels, notes, chains, schedules and last-run results. |
COMPUTER_saved_params.json |
Saved parameter values for each script. |
COMPUTER_settings.json |
Interpreter settings, field histories, options, window layout, and what has happened to each schedule. |
COMPUTER_history.json |
The change history used by Undo and History. |
*.json.bak |
One last-known-good copy of each of the first three files, refreshed at start-up only when its contents have changed. |
*.corrupt-DATE.json |
A preserved copy of a file that couldn’t be read. Created only when damage is found. |
.corrupt-DATE.json, and Scriptary offers to restore the last good copy, showing its date. If you decline, Scriptary starts with empty data, and the backup is kept under a dated name.
Script paths are stored relative to the first matching location, with the longest match taking priority:
%SCRIPTARY_HOME% (the folder containing scriptary.pyw, or the executable it was built into), %OneDriveCommercial%, %OneDriveConsumer%, %OneDrive%, %LOCALAPPDATA%, %APPDATA%, %USERPROFILE%, %PUBLIC%, %ProgramData%, %ProgramFiles(x86)%, %ProgramFiles%, %SystemRoot%.
A library stored this way resolves correctly on any machine where the same folders exist.
Manage ▾ → Keyboard Shortcuts… lists every shortcut:
Give a script or a chain a shortcut, and pressing it runs that script or chain, whichever script is selected.
In the dialog, press the keys you want. Each check is made as you press them, and the dialog says whether the keys can be used:
@.Programs that watch the keyboard directly, such as keyboard remappers, can’t be detected and aren’t listed. If pressing a combination in the dialog shows nothing at all, such a program took the keys before Scriptary saw them.
Assigning, changing and removing a shortcut are recorded in History, so Undo reverses them. A clone doesn’t copy its original’s shortcut.
How a shortcut runs:
If a shortcut’s keys are taken by another program later on, Scriptary notices when it starts and says so in the status bar. The Keyboard Shortcuts list checks again each time it opens.
Shortcuts are kept in the library (COMPUTER_registry.json), so, like schedules, they are per computer.
+ Shortcut for an action… in the Keyboard Shortcuts list gives a key to one of these:
| Where | Actions |
|---|---|
| Manage ▾ | Parameter Names, Parameters Without Help, Unused Saved Values, Run Report, Archived Scripts, Chains, Schedules, Keyboard Shortcuts, and Restart Scriptary (only when it is offered) |
| Top strip | the Manage ▾ and Chains ▾ menus, History |
| Search row | the FILTER ▾ and SORT ▾ menus |
| Sidebar | + Add, ⟳ Refresh, ● Unsaved |
| Script header | ✎ Note, Clone |
| Parameter bar | ▶ Run, Save, ↕ Fit |
| Output tab in front | ⏹ Stop, Save output, Copy output |
The key does just what the menu item or button does. ▶ Run runs the selected script on the values on screen, unlike a script’s own shortcut, which runs its saved values. Stop, Save output and Copy output act on the output tab in front. If the button is hidden or can’t be clicked at that moment, the key does nothing and the status bar says why.
− Remove, Clear and CLOSE ALL are left out on purpose: each is one stray key press from losing something.
A button’s tooltip and the Manage ▾ menu show the key. These shortcuts are preferences, kept in COMPUTER_settings.json; they aren’t recorded in History, so Undo doesn’t reverse them.
| Shortcut | Action | Where |
|---|---|---|
| Ctrl+F | Go to the search box | Main window |
| ↑ / ↓ | Move through the script list | Main window |
| Ctrl+Z | Undo the last library change (text undo inside text fields) | Main window |
| Ctrl+Y | Redo (text redo inside text fields) | Main window |
| Esc | Clear the search | Search box |
| Ctrl+Y, Ctrl+Shift+Z | Redo typing | Text fields |
| Ctrl+C, Ctrl+X, Ctrl+V | Copy, cut, paste | Text fields |
| Ctrl+C | Copy the parameter’s name | Parameter names, in the parameter panel |
| Enter | Send what was typed to the running script | Output console’s input box |
| Enter | OK / Save | Name, schedule and shortcut dialogs |
| Enter | Go to the selected script | Parameters Without Help, Run Report |
| Delete | Remove the selected row | Unused Saved Values, Archived Scripts, Schedules, Keyboard Shortcuts |
| Esc | Close / Cancel | Dialogs |
The same library can be used without the GUI. Use python.exe, not pythonw.exe, so that output appears in your terminal. --config-dir can be added to any of these commands.
python scriptary.pyw add <path\to\script> Register a script
python scriptary.pyw list List scripts with their IDs (archived scripts are left out)
python scriptary.pyw run <script> Run a script with its saved parameters
python scriptary.pyw remove <script> Remove a script from the library
python scriptary.pyw --help Show usage
<script> can be any of the following, checked in this order:
list;backup.py or backup).Matching ignores letter case. If a name matches more than one script (for example, a script and its clones), nothing is run or removed.
Scriptary lists the matching scripts instead, so you can use a label or ID:
> python scriptary.pyw run backup
'backup' matches 2 scripts by file name. Use a label or ID instead:
75c240ad backup.py
609317a2 Backup to NAS (backup.py)
> python scriptary.pyw run "backup to nas"
run doesrun behaves like the GUI’s ▶ Run button, but in your terminal:
cmd.exe.run can be used in other scripts and scheduled tasks. The result also updates the script’s status dot in the GUI.Exit codes from Scriptary itself: 1 means the script or its file wasn’t found, or a data file is damaged; 2 means the name matched more than one script.
add and remove are recorded in the change history, so they can be undone from the GUI.
Output has no colours or progress bars. Scripts only run on a pseudo-console when pyte is installed and this Windows provides one (10/1809 and later); otherwise output comes through plain pipes. Install pyte and restart Scriptary.
Scripts take a few seconds to start. Scriptary uses the pseudo-console built into Windows. If that is unavailable it falls back to pywinpty, which ships its own console (conpty.dll and OpenConsole.exe) that on some machines takes about three seconds to start, whatever the command. In that case Scriptary measures both of pywinpty’s backends once and uses the faster, and the status bar says when it switches. To decide for yourself, set pty_backend in the settings file to system, conpty or winpty.
A PowerShell script is blocked by the execution policy. Each PowerShell version has its own execution policy.
Check it with Get-ExecutionPolicy -List in the same version your PowerShell path points at. Alternatively, add -ExecutionPolicy Bypass to the PowerShell path.
Accented or non-English characters are garbled in a PowerShell script. Windows PowerShell 5.1 reads a script without a byte-order mark using the system’s legacy code page. Save the script as UTF-8 with BOM, or run it with pwsh.exe.
run says a name matches several scripts. Use list to see the IDs, then run the script by its label or ID.
“Scriptary could not read its … file” at start-up. A data file was damaged, for example by an interrupted sync. Choose Yes to restore the last good copy. The damaged file is kept beside it as .corrupt-DATE.json if you need to recover anything from it by hand.
I undid something by mistake. Press Ctrl+Y, or open History, select the Undo: entry and click Redo.
A script’s arguments look wrong. Right-click it and choose Refresh This Script. For Python scripts that build their parsers dynamically, use Detect Arguments by Running Script….


Leave a Reply