Cleat 0.1.0

Extensions

A Cleat extension is an executable that prints JSON lines to stdout. No SDK, no build step, any language. The full protocol: manifest, list and action mode.

Cleat extensionsUpdated

A command is an executable file in ~/.config/cleat/commands. Cleat runs it, reads what it prints, and shows a list. That is the whole API. Bash, Python, Ruby, Swift, whatever has a shebang.

Manifest

Put a comment near the top of the file, within the first 40 lines, that contains cleat: followed by a JSON object:

#!/usr/bin/env bash
# cleat: {"name":"GitHub Repos","keyword":"gh","icon":"arrow.triangle.branch"}

Any comment syntax works: #, //, /* */, a Python docstring. Only the text after cleat: is parsed.

Field Required Meaning
name no Shown in the palette. Defaults to the file name.
keyword no Typing keyword with a space jumps straight into the command.
icon no An SF Symbol name, or an absolute path to a file or app whose icon to use.
mode no list (default) or action.
subtitle no Shown under the name in the root palette, and as the placeholder inside the command.

List mode

Cleat runs the script with the current query as the first argument, and runs it again on every keystroke, debounced, with the previous run cancelled. Print one JSON object per line:

{"title":"cleat","subtitle":"gorgekara/cleat","arg":"https://github.com/gorgekara/cleat","icon":"star"}
Field Required Meaning
title yes The row’s text.
subtitle no Smaller text under the title.
arg no Passed back on selection. Defaults to the title. url is accepted as an alias.
icon no SF Symbol name or absolute path. Defaults to the command’s icon.

A single JSON array of the same objects is also accepted. Lines that are not JSON objects are ignored, so stray debug output does not break the list.

When the user presses Return on a row, Cleat hides the palette and runs the script again:

./your-command --run "<arg>"

Action mode

"mode":"action" commands show up as a single row in the root palette. Return hides the palette and runs ./your-command --run.

Environment

Variable Value
CLEAT_QUERY The query, same as the first argument
CLEAT_VERSION Cleat’s version
CLEAT_COMMANDS_DIR The commands folder
PATH Your PATH plus /opt/homebrew/bin, /usr/local/bin, ~/.local/bin, ~/bin

The working directory is your home folder.

Limits and errors

  • Listing is killed after 2 seconds, --run after 15.
  • A non-zero exit shows the first line of stderr in the palette.
  • The file must be executable: chmod +x ~/.config/cleat/commands/your-command.
  • Cleat re-reads the folder whenever it opens, so there is nothing to reload. Reload Commands exists for the rare case.

The smallest possible command

#!/usr/bin/env bash
# cleat: {"name":"Say hi","mode":"action"}
say hi

A list command in Python

#!/usr/bin/env python3
# cleat: {"name":"Projects","keyword":"p","icon":"folder"}
import json, os, sys
root = os.path.expanduser("~/Development")
query = (sys.argv[1] if len(sys.argv) > 1 else "").lower()
if "--run" in sys.argv:
    os.system(f'open "{sys.argv[-1]}"')
    sys.exit()
for name in sorted(os.listdir(root)):
    if query in name.lower():
        print(json.dumps({"title": name, "subtitle": root, "arg": os.path.join(root, name)}))