Home (All Topics) → Technology → Software → AI-Created Software
The following is 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 color 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, .pyw, .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. Tabs can be pinned so they aren’t closed by accident, and are reopened with their output when Scriptary starts again.%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.8 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 minimizes 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 --working-folder-path:
pythonw scriptary.pyw --working-folder-path "C:\Scriptary\config"
pythonw scriptary.pyw --working-folder-path configs\myteam
A relative path is taken from the folder holding scriptary.pyw (or the executable). The folder is created if needed; if it can’t be, Scriptary says so and doesn’t start. The option’s old name, --config-dir, still works.
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, --working-folder-path 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; FALSE, 0, NO or OFF, or leaving it out, keeps the entry hidden. Any other value, or the option without a value, is a mistake, and Scriptary says so instead of starting.
When Scriptary isn’t already running as administrator, Restart as Administrator follows (in Manage ▾ below Restart Scriptary, in the tray menu below Restart): it closes Scriptary the same way, then starts it again elevated, through the usual UAC prompt. Scripts then run with administrator rights without a prompt of their own. If the prompt is declined, or the elevated start fails, Scriptary starts again without administrator rights, so it never just disappears. Drive letters mapped to network shares while unelevated may be missing in the elevated Scriptary, as Windows keeps them apart.
While Scriptary runs as administrator, Restart without Administrator Rights takes that entry’s place. Windows doesn’t let a program give up its rights, so Scriptary asks Explorer, which runs with your ordinary rights, to start it again. If Explorer can’t be asked, or itself runs as administrator (with UAC off, or as the built-in Administrator account), Scriptary says so and starts again as administrator. A plain Restart keeps the rights Scriptary has.
However it was started (Restart as Administrator, or Run as administrator from Explorer), Scriptary shows that it runs as administrator. The window’s title is Administrator: Scriptary, as Windows’ own Command Prompt shows it, on the taskbar and in Alt+Tab. The status bar has a red ⛨ Administrator badge, beside the RAM line, and the tray icon’s tooltip says Scriptary (Administrator).
Every script it runs then has administrator rights. With --show-self-restart-option TRUE, clicking the badge restarts Scriptary without them.
Restarting, like exiting, asks first when parameter changes are unsaved or scripts are still running. Scripts running in output tabs are stopped, including those running as administrator. A script running as administrator in a window of its own keeps running, but its result is not recorded. Scripts launched detached aren’t asked about: they keep running, and how they end is recorded when Scriptary next starts.
| 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, .pyw, .ps1 and .bat file in a folder. Files already registered are skipped (by path: a file with the name of a registered script in another folder is added), and so are virtual environments, site-packages, __pycache__, node_modules and hidden folders. Files and folders ignored in Manage ▾ → Find Unregistered Scripts… are skipped as well; to see the list first and pick, use that report. |
| ⟳ Refresh | Re-read every script. Files that haven’t changed since the last read are skipped; files that have disappeared are marked missing. |
| Refresh Arguments (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. |
| Several scripts at once (right-click) | Ctrl+click adds a script to the selection (or takes it out), Shift+click selects a run of scripts, and Ctrl+A every script shown. Right-click one of them to refresh, move, add to a chain, tag, tuck away, archive or remove them all; each is one step for Undo. Move To ticks a group or folder only when every selected script is in it, and Add to Chain appends them in the order they are listed; a script that can’t be a step is left out, and the menu says how many. The parameter panel shows the script clicked last. |
| 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, [switch] parameters and [ValidateSet(...)] values (shown as buttons, like argparse choices=). The .SYNOPSIS comment is used as the description, and each .PARAMETER comment (or else the HelpMessage) as the parameter’s help; the first paragraph of each is kept. |
⬤ 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 |
A Python script with no argparse calls of its own, such as a launcher that imports its app from a folder beside it, has its imports followed: the arguments come from the first module, among those in the script’s folder, that adds any (the standard library and installed packages are never read). The detail panel names that module after the method, e.g. argparse, read statically from scriptary_app/config.py, and ⟳ Refresh always reads such a script again, since a change to that module doesn’t change the script’s own date. Static analysis also reads choices= given as the name of a tuple or list of strings in the same module, and leaves out options hidden with help=argparse.SUPPRESS.
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. A Python launcher that imports no toolkit itself has its imports followed, as for its arguments, so an app whose window is in a module in its folder counts too.
Every tag change can be undone.
.bat, .ps*, .py*.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. If the script has a schedule or a reminder, even one turned off, and the values have changed, Scriptary first lists its schedules and asks you to confirm: OK saves, Cancel keeps your edits unsaved. |
| Cancel | Undo the unsaved changes to this script’s values and go back to the saved ones. |
| 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. |
| ⛨ Run as admin | Shown to the left of ▶ Run for scripts that need elevation (see below). |
PARAMETERS ▴, at the left of the bar, collapses the panel to the script’s title and that bar, giving the rest of the height to the output; the buttons on the bar still work. PARAMETERS ▾ opens it again at the height it had before, and so does dragging the divider under the bar (the panel then opens at the height you drag it to) or ↕ Fit. The panel stays as you left it the next time Scriptary starts.
The panel keeps the rows of the last eight scripts you showed, so going back to one of them shows it at once. Holding ↑ or ↓ in the script list moves the selection at the key’s pace, and the parameters follow when you let go.
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, opening only the group or folder that holds it. 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. The box shows one line until you click COMMAND ▾ to open it; open, a command too long for one line wraps and the box grows to show all of it (as long as the parameters keep room on the panel; past that it scrolls). COMMAND ▴ closes it to one line again, and the box stays as you left it the next time Scriptary starts. Copy puts it on the clipboard.
An alias is a name of your own for a parameter. Scriptary shows it in the parameter panel and its reports in place of the script’s name for the parameter. The script is not changed: it is still run with its own flags, so the command preview doesn’t change, and saved values stay where they are. Aliases are useful to give one parameter the same name in every script (output-dir, whether a script spells it --output_dir, --outputDir or -OutputDir), or to name a batch file’s %1.
- and _, up to 40 characters. Within one script it can’t be the alias or the name of another parameter. Case and the difference between - and _ don’t count for that, so Out_Dir and out-dir are the same name.
⛨ Run as admin asks Windows for administrator rights (the UAC prompt) and runs the script in an output tab like any other run: its colors, typed input, Stop and the exit code all work as usual. Run as administrator is also available from the right-click menu for any script.
For a script that can’t run at all without administrator rights (PowerShell’s #Requires -RunAsAdministrator), ⛨ Run as admin is the solid green button and ▶ Run the tinted one; for the others, ▶ Run stays the solid one. Either way, ▶ Run is always the button at the end of the bar, with ⛨ Run as admin to its left.
How it works: Windows doesn’t let a program that isn’t elevated read the console of one that is, so Scriptary starts a hidden, elevated copy of itself through the UAC prompt. That helper runs the script and passes its output back over a private connection that only this Scriptary can use. Each run asks once and has its own helper, which ends with the script. If Scriptary closes, the script is stopped, as it would be in any other tab. The script runs from its own folder.
If the helper can’t be used, the tab says so and the script runs in a console window of its own instead; Windows then asks once more. In a window of its own, only the exit code comes back to the library. To always use a window, untick Show the output in a Scriptary tab under Run as administrator in the Interpreters & execution settings (or set admin_runs_in_tab to false in the settings file).
A script that asks for elevation itself (⛨ requests elevation) is already elevated when run this way, so it doesn’t open a window of its own either.
If Scriptary itself is already running as administrator, ▶ Run is enough and the extra button is hidden.
A script with a graphical interface (⧉) doesn’t need a console, and an app it opens shouldn’t close when Scriptary does. Such a script is launched detached: ▶ Run reads ▶ Launch, and the script starts on its own, with no console window and no output tab, and keeps running when Scriptary closes or restarts. The status bar says it was launched.
launched detached in its footer. A clean exit only updates the list and the status bar.How it works: Scriptary starts a small helper, a copy of itself with no window, outside anything that would end it with Scriptary. The helper starts the script without a console window, writes what it prints to a log, waits for it to end and writes down its exit code. Python scripts run with python.exe, never pythonw.exe, so what they print reaches the log. Each launch’s files are kept in the COMPUTER_detached folder in the working folder until Scriptary has recorded it; the logs of the newest 50 launches are kept after that.
Every run opens a new tab in the output area.
Tab names leave out the script’s extension (.py, .pyw, .ps1, .bat). When the tabs don’t all fit, long names are shortened in the middle (backup_ph…to_nas), so the end of a name, often what tells two scripts apart, stays visible; short names keep their full width and the room they don’t need goes to the long ones. No name is shortened below about eight characters: past that, the tabs scroll. Hover over a tab to see its full name, how its run ended (or that it is still running), the chain that ran it and whether it is pinned.
Full terminal output: colors, cursor movement, progress bars and \r updates display as they would in a terminal (requires pyte). The 16 standard terminal colors are darkened to stay readable as text on the white background, each with a contrast of at least 4.5:1. Light gray and white stay light, since scripts use them on a dark background.
Input: type into the STDIN field at the bottom of a tab and press Send or Enter to answer prompts. While a script runs, its tab moves the keyboard to the field as output arrives, unless you are typing in another field, such as a parameter.
⏹ Stop ends the process. Copy output and Save output export the tab’s text.
Find: press Ctrl+F in a tab (in its output or its STDIN field), or click Find in its footer, to look through its output. Every match is highlighted, in any case, and the one you are on is filled blue, with 3 of 12 beside the field.
Enter or ▼ goes to the next match, Shift+Enter or ▲ to the previous one, round the end to the start; Esc or ✕ closes it. Text selected on one line of the output is what is looked for. Matches in output that arrives while Find is open are highlighted as it comes. Ctrl+F anywhere else still goes to the search box.
Closing a tab: point at its run state (■, ✓ or ✗, on the right) and it turns into a red ✕; click that, or middle-click anywhere on the tab. Elsewhere on the tab the run state stays in sight. Close all closes every tab except pinned ones.
‹ › beside Close all scroll the tabs when there are more than fit, even with their names shortened. Each is enabled only while tabs are hidden on its side, and the tab you select is always scrolled fully into view.
The command at the top of a tab shows one line, cut short with …, until you click COMMAND ▾ to show all of it; COMMAND ▴ closes it again. The choice applies to every tab and is kept the next time Scriptary starts.
Right-click a tab to Pin Tab or Unpin Tab, Unpin All Tabs, Select Script in Library (scrolls the script list to the script that ran in the tab and selects it, opening its group or folder), Close Tab, or Close Other Tabs (every other tab that is not pinned).
Pinned tabs: a pinned tab shows a thumbtack before its name, shows no ✕ on hover and can’t be closed (a middle-click doesn’t close it either), by Close all, Close Other Tabs or a schedule’s next run, until you unpin it. Its script can still be stopped.
Unpinning every tab: Unpin All Tabs, on a tab’s right-click menu or on Close all’s, unpins every pinned tab at once. Undo Unpin All, on the same menus, pins them again (those still open); the undo isn’t kept once Scriptary closes. Right-click Close all for Close All, Unpin All Tabs and Unpin and Close All, which asks first, since closed tabs can’t be brought back.
Run state: each tab shows a green ■ after its name while running, then a green ✓ or a red ✗. The tab’s footer shows the exit code, how long the run took and when it ended, for example ✓ Exited 0 — 53s (Fri Oct 9 @ 12:13pm), so a scheduled run that finished unattended says when it ran; and the script’s status dot in the list is updated.
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 open tabs are kept when Scriptary closes and reopened when it next starts, in the same order, with the same tab in front. Each keeps its output (colors included), how its run ended, whether it was a chain’s, and whether it was pinned. They are saved to COMPUTER_console.json when a run ends, when a tab is closed, pinned or unpinned, and when Scriptary closes, so they also survive Windows shutting down while Scriptary sits in the tray.
✓ Exited 0 — 3s (Fri Oct 9 @ 2:02pm) · restored.console_restore_lines key in the settings file.restore_console_tabs to false in the settings file. Tabs already kept are then forgotten.
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). |
| Output tabs | Whether the output tabs are reopened, with their output, when Scriptary starts (see Output tabs between sessions). |
| Run as administrator | Whether a run as administrator shows its output in a tab (the default) or runs in a console window of its own (see Run as administrator). |
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 grayed 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, notes and parameter aliases; – saved parameters; – Python and PowerShell paths, command options, the argument-detection option, the output-tabs option and the lines each tab keeps, 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; – the output tabs themselves.
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). A chain can also run at set times, or remind you to run it: Chains ▾ → Schedule ▸ (see Schedules for chains).
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…. With several scripts selected, it adds them all as steps in the order they are listed, as one step for Undo.
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 step that is launched detached opens no tab and isn’t waited for: the chain moves on to the next step as soon as it has started, and the next step’s tab says previous step launched detached. Only a launch that fails to start stops 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, or to one chain (see Schedules for chains). 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. Like every check box and radio button in Scriptary, its are drawn at your display’s scaling, so they stay in proportion on a 4K screen.
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, remove it, or clear a reminder (see Reminders). A schedule that pins its tab shows Runs, pins tab.
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.Launched with the time.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 --command run (a command-line run counts once the window next reads the library: ⟳ Refresh or a restart). A run that fails leaves it due, and the reminder says the last attempt failed.
A chain can be scheduled like a script: Chains ▾ → Schedule ▸ → the chain → Run Automatically… or Remind Me to Run It…. The same submenu lists the chain’s schedules to change, and Manage ▾ → Schedules… lists them with the scripts’, as Chain ‘name’.
⏱ 2/3 sync.ps1), the first headed with its schedule.
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, and how each chain last ran. 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 aliases for many parameters at once (see below). |
| 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, values left behind by scripts you removed, and aliases of parameters a script no longer has. |
| Saved Paths | Every file or folder path in the scripts’ saved values, one row per path, with its script and parameter: a sortable table to find paths that point at an old place or another computer’s drive. A value counts as a path by its shape (a drive, a share, an environment variable, ~, . or .. at the start), whether or not it exists here. |
| 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). |
| Tags | Every tag, to rename, merge or delete (see below). |
| Script List | Every script with its name, full path, group or folder and tags, to export as a TSV file (see below). |
| Find Unregistered Scripts | The .py, .pyw, .ps1 and .bat files in a folder, and the folders under it, that aren’t in the library, in a sortable table with their folder, language and modification date; files and folders you don’t want offered can be ignored (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.
Tables in these windows (and in History):
Where windows open: every popup window opens where you last closed it, including the small ones such as the name, note, schedule, shortcut and alias dialogs. The resizable ones also keep their size and whether they were maximized; the others are as large as their contents. A window whose place is off the screen, because a monitor has gone or the resolution changed, is pulled back onto it.
Select in Library, in the reports that offer it, opens the group or folder holding the script, and its tucked-away line if the script is behind it, so the script is reached even if it was hidden. Other groups and folders stay as you left them. A search that narrows the script out of the list is the one thing that can hide it; the status bar says so.
The list on the left has one row per name, whatever language the script is written in: --output-dir, --output_dir and -OutputDir sit together. A parameter with an alias is listed under its alias. Batch parameters (%1–%9) are listed once they have one. While Only names spelled more than one way is ticked, only those are listed; untick it to see every name.
Select one or more names to see where they are used on the right, with the script’s own name for each parameter. Then:
| Action | What it does |
|---|---|
| Set Alias | Gives every parameter listed on the right (or only the selected rows) the alias typed in Alias as, which starts as the most used spelling. Scriptary lists what it will change first. Parameters already called that are left alone, and a parameter whose own name is that loses its alias. |
| Remove Aliases | Removes the aliases of the parameters listed on the right (or of the selected rows). |
| Double-click a row | Opens that script’s Parameter Aliases. |
Either is one change, so one Undo reverses it.
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 Arguments 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, Saved Paths and the Run Report, and out of the command line’s --command 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.
Manage ▾ → Tags… (or Tags → Manage Tags… in a script’s right-click menu) lists every tag Scriptary knows, with how many listed scripts and how many archived scripts have it, and whether it is In use or Previously used. Previously used tags are grayed out. Select one or more rows, then:
| Button | What it does |
|---|---|
| Show in List | Filters the list by the tag, and by no other tag. Other ticked filters are kept. Only for a tag in use. |
| Rename… | Renames the tag everywhere. The name of another tag merges the two, after asking. Double-click a row to do the same. |
| Merge… | Merges two or more tags into one: one of them, another tag or a new name. Every script with any of them gets the kept tag, once. |
| Delete… | After asking, removes the tags from Scriptary and from every script that has them. Delete does the same. |
A tag ticked in the filter stays ticked when it is renamed or merged.
Every change is recorded in the change history, so Undo reverses it.
Manage ▾ → Script List… lists every script in the library, one row each:
| Column | What it holds |
|---|---|
| Name | The name as Scriptary’s list shows it: its label, if you gave it one. |
| Path | The full path of the script’s file on this computer, including the file name, with environment variables such as %OneDrive% filled in. |
| Group or folder | The group the script is in, or otherwise the folder section it is listed under. |
| Tags | Its tags as a comma-separated list, each in double quotes: "nas","nightly". A double quote inside a tag is doubled. |
Archived scripts are left out unless you tick Include archived scripts; they are then grayed out and marked (archived). Select in Library (or a double-click, or Enter) selects the script in the list.
Export TSV… saves the same four columns as a tab-separated file, with a heading line, in the order the table is sorted. The file is UTF-8 with a byte-order mark and Windows line ends, so Excel opens it with accented names intact. TSV has no quoting, so a tab or line break inside a value is saved as a space.
Manage ▾ → Find Unregistered Scripts… looks through a folder, and every folder under it, for .py, .pyw, .ps1 and .bat files that aren’t in the library. Type or paste the folder (environment variables such as %OneDrive% work) and press Enter or Scan, or pick it with Browse…. The folder is remembered, and looked through again the next time the window opens. A large folder is looked through in the background; Stop ends it early and keeps what was found so far.
| Column | What it holds |
|---|---|
| File | The script’s file name. |
| Folder | The folder it is in, relative to the one scanned (. for that folder itself). |
| Written in | Python, PowerShell or Batch. |
| Modified | When the file was last changed. |
A script counts as registered when any entry in the library points at its file — archived and tucked-away scripts included — compared by path, not by name: a backup.py in another folder than the registered one is listed. Virtual environments (any folder with a pyvenv.cfg, and venv), site-packages, __pycache__, node_modules and hidden folders (a name starting with .) are passed by unless you tick Include virtual environments, site-packages, pycache, node_modules and hidden folders.
Add to Library registers the selected scripts (Ctrl+click and Shift+click select several), as one step for Undo; they leave the table, and come back if you undo. Open Folder (or a double-click, or Enter) shows the file in Explorer, and Copy Path copies its full path.
Ignoring. Right-click a script, or select it and click Ignore ▾, to leave it out of the list from now on: Ignore This File, or Ignore Folder for any folder it is in, up to the one scanned. With several scripts selected, the menu ignores those files, or the folders they are in. A folder takes everything under it, wherever you scan from.
Ignored… (with the count) lists what you ignore, by kind and full path: Un-ignore (or Delete) brings a file or folder back, and Ignore a Folder… adds one before you scan it. 🔍 Scan leaves ignored scripts out too.
The list is kept in COMPUTER_settings.json with paths stored like the scripts’ own (%OneDrive% …), and every change to it is one step for Undo and shows in History.
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, parameter aliases, 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, collapsed sections, dialog layouts, keyboard shortcuts for Scriptary’s own actions, and what has happened to each schedule. |
COMPUTER_settings.ini |
The window’s own settings: its size, place and whether it is maximized, the dividers, the list’s sort and selected script, and the folder a script was last added from. A value that can’t be read is ignored, so the file can be edited by hand. Older versions kept these in the .json file; they move here the first time Scriptary starts. |
COMPUTER_history.json |
The change history used by Undo and History. |
COMPUTER_console.json |
The output tabs kept for the next start-up, with their output. See Output tabs between sessions. |
COMPUTER_detached\ |
Scripts launched detached: each launch’s details and how it ended, until Scriptary has recorded it, and the logs of the newest 50 launches. |
*.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 ▾ | Tags, Archived Scripts, Script List, Find Unregistered Scripts, Parameter Names, Parameters Without Help, Unused Saved Values, Saved Paths, Run Report, Chains, Schedules, Keyboard Shortcuts, and Restart Scriptary and Restart as Administrator or without Administrator Rights (only when they are offered) |
| Top strip | the Chains ▾ and Manage ▾ 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, Find |
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, Copy output and Find 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 |
| Ctrl+F | Find in the tab’s output | Output tab (its output or STDIN field) |
| ↑ / ↓ | Move through the script list (held, the parameters follow when you let go) | 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+A | Select all of the field’s text | Text fields |
| Right-click | Cut, Copy, Paste and Select all, each available only when it can act | 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, Shift+Enter | Next match, previous match | An output tab’s Find field |
| Esc | Close Find | An output tab’s Find field or output |
| Enter | OK / Save | Name, schedule and shortcut dialogs |
| Enter | Go to the selected script | Parameters Without Help, Saved Paths, Run Report, Script List |
| Enter | Scan the folder typed; open the selected script’s folder | Find Unregistered Scripts |
| 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 window. Use python.exe, not pythonw.exe, so that output appears in your terminal. Every option is written --name VALUE (or --name=VALUE), in any order; python scriptary.pyw --help lists them all.
python scriptary.pyw --command add --script-file-path SCRIPT Register a script
python scriptary.pyw --command list List scripts with their IDs (archived scripts are left out)
python scriptary.pyw --command run --script-name NAME Run a script with its saved parameters
python scriptary.pyw --command remove --script-name NAME Remove a script from the library
python scriptary.pyw --selftest TRUE Check Scriptary's own functions (see Testing)
python scriptary.pyw --help List every option
| Option | What it does |
|---|---|
--command {add,remove,list,run} |
Do this in the terminal instead of opening the window. Left out, the window opens. |
--script-file-path SCRIPT |
The script to add, for --command add. |
--script-name NAME |
The script to remove or run: see Naming a script. |
--working-folder-path FOLDER |
Where the library, saved values and settings are kept (see Choosing where data is stored). Its old name, --config-dir, still works. |
--show-self-restart-option TRUE |
Offer Restart Scriptary, and Restart as Administrator or without Administrator Rights (see Restarting Scriptary). |
--selftest TRUE |
Check that Scriptary’s own functions work, on scripts it writes to a temporary folder, without touching the library; then say which optional parts are installed. Exits with 0 when every check passed. |
A mistake on the command line (an unknown option, an option without its value or given twice, --command run without --script-name, a bare word such as list) is reported as Error: … with “Use –help for usage.”, and Scriptary exits with 2. Started with pythonw.exe, which has no console, it shows the mistake in a message box instead.
<script> can be any of the following, checked in this order:
--command 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 --command run --script-name 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 --command run --script-name "backup to nas"
--command run doesIt behaves like the GUI’s ▶ Run button, but in your terminal:
cmd.exe.--command 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, the name matched more than one script, or a data file is damaged; 2 means a mistake on the command line.
(Before, a name that matched several scripts gave 2.)
--command add and --command remove are recorded in the change history, so they can be undone from the GUI.
The tests use pytest (python -m pip install pytest).
From the Scriptary folder:
python -m pytest Everything
python -m pytest -m "not gui" Everything except the tests that open windows
python run_tests.py The same, from Scriptary itself (see its --help)
python scriptary.pyw --selftest TRUE A quick check of Scriptary's own functions, without pytest
The 863 tests take about ten minutes; 365 of them don’t open windows and take about twenty seconds. One is skipped outside Windows. The tests never touch your own library: each one works in a temporary folder.tests\README.md explains the result lines, the tools for checking that the list draws the same, and the check for dead code.
The tests that open windows are run at 150% display scaling too (on Linux: an Xvfb display started with -dpi 144). Among them, test_fit.py checks that at the window’s smallest size (900 × 640 at 100%) no button is cut off and the script list still shows three rows.
Output has no colors 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.
--command run says a name matches several scripts. Use --command list to see the IDs, then run the script by its label or ID.
An old command line stopped working. Commands are options now: scriptary.pyw run backup is scriptary.pyw --command run --script-name backup, and add SCRIPT is --command add --script-file-path SCRIPT. Update scheduled tasks and shortcuts that start Scriptary this way.
“Settings not saved”. Scriptary couldn’t write COMPUTER_settings.ini, for example because the working folder is read-only or a sync client held the file. Scriptary goes on, but the window’s size, dividers and choices may not be kept for the next start. The message names the file and the reason, and is shown once until a save works again.
“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 launched detached never showed its window.
If it failed, a tab with its output opened when Scriptary noticed. If nothing opened, look at its log, the newest .log file in the COMPUTER_detached folder, or right-click it and choose Run in a Tab to see its output as it runs.
A script’s arguments look wrong. Right-click it and choose Refresh Arguments. For Python scripts that build their parsers dynamically, use Detect Arguments by Running Script….
--help) finds the arguments of ordinary argparse, PowerShell and batch scripts; a parser built at run time needs Detect Arguments by Running Script….

Leave a Reply