Scripts and data files
A palette from a shell script or a data file, no TypeScript: one TOML table each.
palv0.1.0Developerbundled
Ships inside pal. Installing puts an editable copy ahead of the bundled one.




What it does
Scripts and data files
The zero-code tier. A palette can be a data file (json, jsonl or toml) or
a shell script that prints JSON lines, described by a small TOML table. No
TypeScript. The extension reads those tables from a pal v1 style config
file and turns each [palette.<name>] into a palette named after its
table, with the config id scripts-<name>. The full format is in
docs/scripts.md; this is the short version.
A data-file palette
[palette.links]
auto_list = true
data = "links.json" # relative to the config file's directory
icon_utf = "🔗"
actions = [
{ id = "open", title = "Open", action = "open", key = "url", primary = true },
{ id = "copy", title = "Copy link", action = "copy", key = "url", shortcut = "cmd+c" },
]
links.json is a JSON array (or one object per line, or a TOML file
whose first top-level array is the rows). Every row is an item: name is
the title, id defaults to name; subtitle, keywords, section,
url (a favicon when there is no icon), accessories, detail and
icon_utf are what they say. The table's actions apply to every row.
Without actions, auto_pick = true with default_action (copy,
open, cmd, type) and action_key gives one built-in action.
A script palette
[palette.hosts]
base = "plugins/hosts" # the directory holding run.sh
requires = ["awk"] # skipped when the binary is missing
ttl = 3600 # reuse a listing for an hour
run.sh list prints one JSON object per line (the row fields above, plus
preview, a shell command whose stdout becomes the detail pane's
markdown, run lazily). run.sh pick gets the picked row as JSON on stdin
and every field as PAL_<KEY> in the environment (PAL_ID, PAL_NAME,
PAL_ACTION, PAL_FILTER), and prints a result envelope: clipboard,
open, toast, hud, show (a read-only level), palette (drill into
another script palette with env), reload. No envelope hides the panel.
Table keys: input (list on every keystroke, the query on stdin and in
PAL_QUERY), input_prompt, live (list on every show), ttl, view = "grid", display = { detail = true, columns = 8 }, filter (a scope
dropdown, the id in PAL_FILTER), requires, os, command (instead of
run.sh). A plugin.toml in base may carry the same keys. base may
also be github:<user>/<repo>/<path> from v1's plugin cache.
Keyboard
What a row does is the table's: the first action (or the primary one)
runs on enter, the second on cmd+enter, every action from cmd+k with
the shortcut it declares. With no actions at all a script palette's row
is Select, which runs run.sh pick.
| keys | action |
|---|---|
enter |
The primary action: open, copy, cmd, type, or pick into the script |
cmd+enter |
The second action |
cmd+k |
Every action of the row, with its shortcut, style and confirm |
cmd+i |
The detail pane: the row's detail, or its preview command's output |
tab |
The next filter scope |
cmd+r |
Run the script again past any ttl |
Setup
Point config at the file that holds the tables. The default is pal's
own config file; pal's parser flags a palette table as an unknown key
(the palettes still work), so a file of their own keeps the warning away:
[extensions.scripts]
config = "~/.config/pal/scripts.toml"
Relative paths inside that file (data, base, [general] env_file)
are resolved against its directory; ~ is expanded. Scripts get the
app's PATH plus ~/.local/bin, ~/.cargo/bin, /opt/homebrew/bin and
/usr/local/bin. A type action pastes into the app in front, which
needs Accessibility on macOS (wtype or ydotool on Linux).
Settings, [extensions.scripts]:
| key | type | default | what |
|---|---|---|---|
config |
path | ~/.config/pal/config.toml |
The file whose [palette.<name>] tables become palettes. |
skip |
list | ["combine", "pals", "apps", "bookmarks", "calc", "emoji", "clipboard"] |
Table names not to load, because a bundled extension covers them. |
v1_repo |
path | ~/proj/pal-v1 |
The v1 checkout: where github:zcag/pal/... bases resolve when v1's plugin cache has no copy, and where a base under a v1 checkout missing on this box (~/proj/pal/plugins/... or ~/proj/pal-v1/plugins/...) is looked up. ~/proj/pal is tried when this path has no plugins/palettes. |
timeout |
seconds, 1 to 300 | 30 |
A list or pick still running after this is killed. |
preview_max |
0 to 32 | 4 |
How many preview commands run at the same time. 0 turns previews off. |
ttl |
seconds, 0 to 604800 | 3600 |
Listing lifetime for non-live tables that declare no ttl; a table's own ttl wins. 0 runs every script on every start. |
config, skip, v1_repo and ttl are read when the extension loads;
after changing them, Settings > Restart extension host. timeout and
preview_max apply to the next run.
What it does not do
- v1's
builtin/...bases: no equivalent, one inert row says so. - Raycast icon names (
icon_rc): dropped; useicon_utf,iconoricon_xdg. - Metadata separators in
detail: no equivalent, left out. - Run a
listorpickpasttimeout: it is killed with its process group and counts as failed. - Watch the config: a new table shows after Restart extension host.
Platforms
macOS and Linux. A table with os = "macos" or "linux" is skipped
elsewhere; requires gates on binaries on PATH the same way on both.
Palettes 0
The manifest declares no palettes; the code decides at load.
Actions
- OpenAn `open` action on the row's url.↵
- Copy linkA `copy` action on a row field.⌘C
- SelectThe default of a script palette without actions: run.sh pick with the row in the environment.↵
Settings
Extension, [extensions.scripts]
configA pal v1 config.toml; every [palette.<name>] in it becomes a palette here.
skipv1 palette names not to load, because a native extension covers them.
v1_repoThe v1 checkout: where github:zcag/pal/... bases resolve when v1's plugin cache (~/.local/share/pal) has no copy, and where a base under a v1 checkout missing on this box is looked up. ~/proj/pal is tried when this path has no plugins.
timeoutA list or pick script still running after this is killed.
preview_maxAn item's preview command runs when the detail pane rests on it; at most this many run at the same time. 0 turns previews off.
ttlA palette that declares no ttl keeps its last listing across restarts and shows for this long before its script runs again; a palette's own ttl wins, and a live palette is exempt (it relists on every show unless it sets its own). Default an hour: scripts are the slow tier, and the root answers from the kept listing meanwhile. 0 runs every script on every start.
Defaults shown. Change them in pal's settings window or in the config file.