How to create a workflow
Everything happens in AppPad’s settings. No extra tools needed.
- 1
Open “Settings” › “Workflows” and choose “New Workflow”, or start from “New Shell Workflow” or “New AppleScript Workflow”.
- 2
Fill in “Name”, “Description” and “Keywords”. Typing a keyword exactly puts the workflow first in the panel.
- 3
Under “Argument”, choose whether it takes text after the keyword and how that text is read: text, duration, time, number, percentage or reminder.
- 4
Under “Steps”, use “Add Step”. The first step gets the argument, every later step the previous output: stdin and $APPPAD_INPUT in shell scripts, argv in AppleScript and JavaScript (on run argv, function run(argv)), {{input}} in HTTP fields, the shortcut input and Open URL.
- 5
Under “Declared Permissions”, declare the files, network access, apps, hosts and secrets it needs; “Detect from Steps” fills them in from your steps. Put tokens in “Settings” › “Workflows” › “Secrets” and use them as {{secret:NAME}}. AppPad asks you before granting anything.
- 6
Press ⌘Space, type the keyword and press ↩.
Examples
Each example is a complete workflow. Open it in AppPad to try it, or read its JSON to see how it is built. AppPad asks before installing.
Base64 Encode
Encode the text you type as Base64 and copy the result.
Type b64 hello world
Needs
- This workflow needs no permissions.
Show JSON
{
"formatVersion": "1.0",
"id": "com.youmindhub.example.base64",
"version": "1.0",
"name": "Base64 Encode",
"description": "Encode the text you type as Base64 and copy the result.",
"localizations": {
"de": {
"name": "Base64-Kodierung",
"description": "Kodiert den getippten Text als Base64 und kopiert das Ergebnis."
},
"es": {
"name": "Codificar en Base64",
"description": "Codifica en Base64 el texto que escribes y copia el resultado."
},
"fr": {
"name": "Encoder en Base64",
"description": "Encode en Base64 le texte saisi et copie le résultat."
},
"it": {
"name": "Codifica Base64",
"description": "Codifica in Base64 il testo digitato e copia il risultato."
},
"ja": {
"name": "Base64 エンコード",
"description": "入力したテキストを Base64 にエンコードし、結果をコピーします。"
},
"ko": {
"name": "Base64 인코딩",
"description": "입력한 텍스트를 Base64로 인코딩하고 결과를 복사합니다."
},
"nl": {
"name": "Base64-codering",
"description": "Codeert de getypte tekst als Base64 en kopieert het resultaat."
},
"zh-Hans": {
"name": "Base64 编码",
"description": "把输入的文字编码为 Base64 并复制结果。"
},
"zh-Hant": {
"name": "Base64 編碼",
"description": "把輸入的文字編碼為 Base64 並拷貝結果。"
}
},
"group": "Examples",
"keywords": [
"b64",
"base64"
],
"argument": "required",
"argumentType": "text",
"argumentHint": "text",
"symbol": "textformat",
"successNotice": "output",
"successMessage": "",
"failureNotice": "error",
"failureMessage": "",
"copyOutput": true,
"steps": [
{
"kind": "shell",
"script": "printf '%s' \"$APPPAD_INPUT\" | base64",
"timeout": 10
}
],
"permissions": {}
}Weather
Show the current weather for a city from wttr.in. Without a city it uses your location.
Type weather Tokyo
Needs
- Access the network from scripts
Show JSON
{
"formatVersion": "1.0",
"id": "com.youmindhub.example.weather",
"version": "1.0",
"name": "Weather",
"description": "Show the current weather for a city from wttr.in. Without a city it uses your location.",
"localizations": {
"de": {
"name": "Wetter",
"description": "Zeigt das aktuelle Wetter für eine Stadt von wttr.in. Ohne Stadt wird dein Standort verwendet."
},
"es": {
"name": "Tiempo",
"description": "Muestra el tiempo actual de una ciudad desde wttr.in. Sin ciudad, usa tu ubicación."
},
"fr": {
"name": "Météo",
"description": "Affiche la météo actuelle d’une ville depuis wttr.in. Sans ville, votre position est utilisée."
},
"it": {
"name": "Meteo",
"description": "Mostra il meteo attuale di una città da wttr.in. Senza città usa la tua posizione."
},
"ja": {
"name": "天気",
"description": "wttr.in から都市の現在の天気を表示します。都市を省略すると現在地を使います。"
},
"ko": {
"name": "날씨",
"description": "wttr.in에서 도시의 현재 날씨를 보여 줍니다. 도시를 생략하면 현재 위치를 사용합니다."
},
"nl": {
"name": "Weer",
"description": "Toont het huidige weer voor een stad via wttr.in. Zonder stad wordt je locatie gebruikt."
},
"zh-Hans": {
"name": "天气",
"description": "从 wttr.in 显示城市的当前天气;不填城市则使用你的所在位置。"
},
"zh-Hant": {
"name": "天氣",
"description": "從 wttr.in 顯示城市的目前天氣;不填城市則使用你的所在位置。"
}
},
"group": "Examples",
"keywords": [
"weather",
"wttr"
],
"argument": "optional",
"argumentType": "text",
"argumentHint": "city",
"symbol": "cloud.sun",
"successNotice": "output",
"successMessage": "",
"failureNotice": "error",
"failureMessage": "",
"copyOutput": false,
"steps": [
{
"kind": "shell",
"script": "curl -fsS \"https://wttr.in/${APPPAD_INPUT// /+}?format=3\"",
"timeout": 20
}
],
"permissions": {
"network": true
}
}Quick Note
Append a timestamped line to ~/AppPad/Notes.txt.
Type note call the bank
Needs
- Read and change files in ~/AppPad
Show JSON
{
"formatVersion": "1.0",
"id": "com.youmindhub.example.note",
"version": "1.0",
"name": "Quick Note",
"description": "Append a timestamped line to ~/AppPad/Notes.txt.",
"localizations": {
"de": {
"name": "Schnelle Notiz",
"description": "Hängt eine Zeile mit Zeitstempel an ~/AppPad/Notes.txt an."
},
"es": {
"name": "Nota rápida",
"description": "Añade una línea con fecha y hora a ~/AppPad/Notes.txt."
},
"fr": {
"name": "Note rapide",
"description": "Ajoute une ligne horodatée à ~/AppPad/Notes.txt."
},
"it": {
"name": "Nota veloce",
"description": "Aggiunge una riga con data e ora a ~/AppPad/Notes.txt."
},
"ja": {
"name": "クイックメモ",
"description": "日時付きの 1 行を ~/AppPad/Notes.txt に追記します。"
},
"ko": {
"name": "빠른 메모",
"description": "~/AppPad/Notes.txt에 시각이 붙은 한 줄을 추가합니다."
},
"nl": {
"name": "Snelle notitie",
"description": "Voegt een regel met tijdstempel toe aan ~/AppPad/Notes.txt."
},
"zh-Hans": {
"name": "快速笔记",
"description": "把带时间的一行追加到 ~/AppPad/Notes.txt。"
},
"zh-Hant": {
"name": "快速筆記",
"description": "把帶時間的一行附加到 ~/AppPad/Notes.txt。"
}
},
"group": "Examples",
"keywords": [
"note",
"jot"
],
"argument": "required",
"argumentType": "text",
"argumentHint": "note",
"symbol": "note.text",
"successNotice": "custom",
"successMessage": "✓ {{output}}",
"failureNotice": "error",
"failureMessage": "",
"copyOutput": false,
"steps": [
{
"kind": "shell",
"script": "mkdir -p ~/AppPad\nprintf '%s %s\\n' \"$(date '+%F %R')\" \"$APPPAD_INPUT\" >> ~/AppPad/Notes.txt\necho \"~/AppPad/Notes.txt\"",
"timeout": 10
}
],
"permissions": {
"fileWrite": [
"~/AppPad"
]
}
}Copy Finder Path
Copy the paths of the files selected in Finder, or of the open folder.
Type path
Needs
- Use system services (open apps, clipboard, notifications)
- Control Finder
The first run asks you to let AppPad control Finder.
Show JSON
{
"formatVersion": "1.0",
"id": "com.youmindhub.example.finderpath",
"version": "1.0",
"name": "Copy Finder Path",
"description": "Copy the paths of the files selected in Finder, or of the open folder.",
"localizations": {
"de": {
"name": "Finder-Pfad kopieren",
"description": "Kopiert die Pfade der im Finder ausgewählten Dateien oder des geöffneten Ordners."
},
"es": {
"name": "Copiar ruta del Finder",
"description": "Copia las rutas de los archivos seleccionados en el Finder o de la carpeta abierta."
},
"fr": {
"name": "Copier le chemin Finder",
"description": "Copie les chemins des fichiers sélectionnés dans le Finder, ou du dossier ouvert."
},
"it": {
"name": "Copia percorso Finder",
"description": "Copia i percorsi dei file selezionati nel Finder o della cartella aperta."
},
"ja": {
"name": "Finder のパスをコピー",
"description": "Finder で選択したファイル、または開いているフォルダのパスをコピーします。"
},
"ko": {
"name": "Finder 경로 복사",
"description": "Finder에서 선택한 파일 또는 열린 폴더의 경로를 복사합니다."
},
"nl": {
"name": "Finder-pad kopiëren",
"description": "Kopieert de paden van de in de Finder geselecteerde bestanden of van de geopende map."
},
"zh-Hans": {
"name": "复制访达路径",
"description": "复制在访达中选中的文件路径,或当前打开的文件夹路径。"
},
"zh-Hant": {
"name": "拷貝 Finder 路徑",
"description": "拷貝在 Finder 中選取的檔案路徑,或目前打開的檔案夾路徑。"
}
},
"group": "Examples",
"keywords": [
"path",
"finderpath"
],
"symbol": "folder",
"successNotice": "output",
"successMessage": "",
"failureNotice": "error",
"failureMessage": "",
"copyOutput": true,
"steps": [
{
"kind": "appleScript",
"language": "appleScript",
"script": "on run argv\n\ttell application \"Finder\"\n\t\tset picked to selection as alias list\n\t\tif picked is {} then return POSIX path of (insertion location as alias)\n\tend tell\n\tset paths to {}\n\trepeat with f in picked\n\t\tset end of paths to POSIX path of f\n\tend repeat\n\tset AppleScript's text item delimiters to linefeed\n\treturn paths as text\nend run",
"timeout": 20
}
],
"permissions": {
"appleEvents": [
"com.apple.finder"
]
}
}Title Case
Capitalize the first letter of every word and copy the result.
Type title the quick brown fox
Needs
- Use system services (open apps, clipboard, notifications)
Show JSON
{
"formatVersion": "1.0",
"id": "com.youmindhub.example.titlecase",
"version": "1.0",
"name": "Title Case",
"description": "Capitalize the first letter of every word and copy the result.",
"localizations": {
"de": {
"name": "Wortanfänge groß",
"description": "Schreibt jeden Wortanfang groß und kopiert das Ergebnis."
},
"es": {
"name": "Mayúsculas iniciales",
"description": "Pone en mayúscula la primera letra de cada palabra y copia el resultado."
},
"fr": {
"name": "Majuscules initiales",
"description": "Met une majuscule à chaque mot et copie le résultat."
},
"it": {
"name": "Iniziali maiuscole",
"description": "Mette in maiuscolo la prima lettera di ogni parola e copia il risultato."
},
"ja": {
"name": "単語の先頭を大文字に",
"description": "各単語の先頭を大文字にして結果をコピーします。"
},
"ko": {
"name": "단어 첫 글자 대문자",
"description": "각 단어의 첫 글자를 대문자로 바꾸고 결과를 복사합니다."
},
"nl": {
"name": "Hoofdletters per woord",
"description": "Zet de eerste letter van elk woord in hoofdletters en kopieert het resultaat."
},
"zh-Hans": {
"name": "单词首字母大写",
"description": "把每个单词的首字母改成大写并复制结果。"
},
"zh-Hant": {
"name": "單字首字母大寫",
"description": "把每個單字的首字母改成大寫並拷貝結果。"
}
},
"group": "Examples",
"keywords": [
"title",
"titlecase"
],
"argument": "required",
"argumentType": "text",
"argumentHint": "text",
"symbol": "textformat.size",
"successNotice": "output",
"successMessage": "",
"failureNotice": "error",
"failureMessage": "",
"copyOutput": true,
"steps": [
{
"kind": "appleScript",
"language": "javaScript",
"script": "function run(argv) {\n const text = argv.join(\" \")\n return text.toLowerCase().replace(/(^|[\\s-])(\\S)/g, (m, p, c) => p + c.toUpperCase())\n}",
"timeout": 10
}
],
"permissions": {}
}Speak Text
Send the text to a shortcut that reads it aloud.
Type speak good morning
Needs
- Run the shortcut “AppPad Speak”
First create a shortcut named “AppPad Speak” in the Shortcuts app with one action: Speak Text, set to Shortcut Input.
Show JSON
{
"formatVersion": "1.0",
"id": "com.youmindhub.example.speak",
"version": "1.0",
"name": "Speak Text",
"description": "Send the text to a shortcut that reads it aloud.",
"localizations": {
"de": {
"name": "Text sprechen",
"description": "Sendet den Text an einen Kurzbefehl, der ihn vorliest."
},
"es": {
"name": "Leer texto en voz alta",
"description": "Envía el texto a un atajo que lo lee en voz alta."
},
"fr": {
"name": "Lire le texte",
"description": "Envoie le texte à un raccourci qui le lit à voix haute."
},
"it": {
"name": "Leggi testo",
"description": "Invia il testo a un comando rapido che lo legge ad alta voce."
},
"ja": {
"name": "テキストを読み上げ",
"description": "テキストを読み上げるショートカットに送ります。"
},
"ko": {
"name": "텍스트 읽기",
"description": "텍스트를 소리 내어 읽는 단축어로 보냅니다."
},
"nl": {
"name": "Tekst uitspreken",
"description": "Stuurt de tekst naar een opdracht die hem voorleest."
},
"zh-Hans": {
"name": "朗读文字",
"description": "把文字交给一个快捷指令朗读出来。"
},
"zh-Hant": {
"name": "朗讀文字",
"description": "把文字交給一個捷徑朗讀出來。"
}
},
"group": "Examples",
"keywords": [
"speak",
"say"
],
"argument": "required",
"argumentType": "text",
"argumentHint": "text",
"symbol": "waveform",
"successNotice": "none",
"successMessage": "",
"failureNotice": "error",
"failureMessage": "",
"copyOutput": false,
"steps": [
{
"kind": "shortcut",
"shortcutName": "AppPad Speak",
"timeout": 60
}
],
"permissions": {}
}Shorten URL
Shorten a link with is.gd and copy the short URL.
Type short https://example.com/a/long/link
Needs
- Send HTTP requests to is.gd
Show JSON
{
"formatVersion": "1.0",
"id": "com.youmindhub.example.shorten",
"version": "1.0",
"name": "Shorten URL",
"description": "Shorten a link with is.gd and copy the short URL.",
"localizations": {
"de": {
"name": "URL kürzen",
"description": "Kürzt einen Link mit is.gd und kopiert die kurze URL."
},
"es": {
"name": "Acortar URL",
"description": "Acorta un enlace con is.gd y copia la URL corta."
},
"fr": {
"name": "Raccourcir une URL",
"description": "Raccourcit un lien avec is.gd et copie l’URL courte."
},
"it": {
"name": "Accorcia URL",
"description": "Accorcia un link con is.gd e copia l’URL breve."
},
"ja": {
"name": "URL を短縮",
"description": "is.gd でリンクを短縮し、短い URL をコピーします。"
},
"ko": {
"name": "URL 줄이기",
"description": "is.gd로 링크를 줄이고 짧은 URL을 복사합니다."
},
"nl": {
"name": "URL inkorten",
"description": "Kort een link in met is.gd en kopieert de korte URL."
},
"zh-Hans": {
"name": "缩短网址",
"description": "用 is.gd 缩短链接并复制短网址。"
},
"zh-Hant": {
"name": "縮短網址",
"description": "用 is.gd 縮短連結並拷貝短網址。"
}
},
"group": "Examples",
"keywords": [
"short",
"isgd"
],
"argument": "required",
"argumentType": "text",
"argumentHint": "url",
"symbol": "link",
"successNotice": "output",
"successMessage": "",
"failureNotice": "error",
"failureMessage": "",
"copyOutput": true,
"steps": [
{
"kind": "http",
"http": {
"method": "GET",
"url": "https://is.gd/create.php?format=simple&url={{input}}",
"headers": "",
"body": ""
},
"timeout": 20
}
],
"permissions": {
"httpHosts": [
"is.gd"
]
}
}Send to Phone
Push the text to your phone with ntfy. Step 1 turns it into JSON, step 2 sends it with your secret topic.
Type phone dinner is ready
Needs
- Use system services (open apps, clipboard, notifications)
- Send HTTP requests to ntfy.sh
- Use the secret “NTFY_TOPIC” in HTTP requests
Install the ntfy app on your phone and subscribe to a long, hard-to-guess topic. Then add that topic in Settings › Workflows › Secrets as NTFY_TOPIC.
Show JSON
{
"formatVersion": "1.0",
"id": "com.youmindhub.example.phone",
"version": "1.0",
"name": "Send to Phone",
"description": "Push the text to your phone with ntfy. Step 1 turns it into JSON, step 2 sends it with your secret topic.",
"localizations": {
"de": {
"name": "An Handy senden",
"description": "Schickt den Text per ntfy aufs Handy. Schritt 1 macht JSON daraus, Schritt 2 sendet es mit deinem geheimen Thema."
},
"es": {
"name": "Enviar al móvil",
"description": "Envía el texto a tu móvil con ntfy. El paso 1 lo convierte en JSON y el paso 2 lo envía con tu tema secreto."
},
"fr": {
"name": "Envoyer au téléphone",
"description": "Envoie le texte sur votre téléphone avec ntfy. L’étape 1 le convertit en JSON, l’étape 2 l’envoie avec votre sujet secret."
},
"it": {
"name": "Invia al telefono",
"description": "Invia il testo al telefono con ntfy. Il passaggio 1 lo trasforma in JSON, il passaggio 2 lo invia con il tuo argomento segreto."
},
"ja": {
"name": "スマホに送信",
"description": "ntfy でテキストをスマホに送ります。ステップ 1 で JSON にし、ステップ 2 で秘密のトピックに送信します。"
},
"ko": {
"name": "휴대폰으로 보내기",
"description": "ntfy로 텍스트를 휴대폰에 보냅니다. 1단계에서 JSON으로 바꾸고, 2단계에서 비밀 토픽으로 보냅니다."
},
"nl": {
"name": "Naar telefoon sturen",
"description": "Stuurt de tekst via ntfy naar je telefoon. Stap 1 maakt er JSON van, stap 2 verstuurt het met je geheime onderwerp."
},
"zh-Hans": {
"name": "发送到手机",
"description": "用 ntfy 把文字推送到手机。第 1 步转成 JSON,第 2 步用你的秘密主题发送。"
},
"zh-Hant": {
"name": "傳送到手機",
"description": "用 ntfy 把文字推送到手機。第 1 步轉成 JSON,第 2 步用你的秘密主題傳送。"
}
},
"group": "Examples",
"keywords": [
"phone",
"ntfy"
],
"argument": "required",
"argumentType": "text",
"argumentHint": "text",
"symbol": "iphone",
"successNotice": "none",
"successMessage": "",
"failureNotice": "error",
"failureMessage": "",
"copyOutput": false,
"steps": [
{
"kind": "appleScript",
"language": "javaScript",
"script": "function run(argv) {\n return JSON.stringify(argv.join(\" \"))\n}",
"timeout": 10
},
{
"kind": "http",
"http": {
"method": "POST",
"url": "https://ntfy.sh/",
"headers": "Content-Type: application/json",
"body": "{\"topic\": \"{{secret:NTFY_TOPIC}}\", \"title\": \"AppPad\", \"message\": {{input}}}"
},
"timeout": 20
}
],
"permissions": {
"httpHosts": [
"ntfy.sh"
],
"secrets": [
"NTFY_TOPIC"
]
}
}Search YouTube
Open YouTube search results for the text you type.
Type yt lofi
Needs
- Open web pages and links
Show JSON
{
"formatVersion": "1.0",
"id": "com.youmindhub.example.youtube",
"version": "1.0",
"name": "Search YouTube",
"description": "Open YouTube search results for the text you type.",
"localizations": {
"de": {
"name": "Auf YouTube suchen",
"description": "Öffnet die YouTube-Suchergebnisse für den getippten Text."
},
"es": {
"name": "Buscar en YouTube",
"description": "Abre los resultados de búsqueda de YouTube para el texto que escribes."
},
"fr": {
"name": "Rechercher sur YouTube",
"description": "Ouvre les résultats de recherche YouTube pour le texte saisi."
},
"it": {
"name": "Cerca su YouTube",
"description": "Apre i risultati di ricerca di YouTube per il testo digitato."
},
"ja": {
"name": "YouTube で検索",
"description": "入力したテキストの YouTube 検索結果を開きます。"
},
"ko": {
"name": "YouTube 검색",
"description": "입력한 텍스트의 YouTube 검색 결과를 엽니다."
},
"nl": {
"name": "Zoeken op YouTube",
"description": "Opent de YouTube-zoekresultaten voor de getypte tekst."
},
"zh-Hans": {
"name": "搜索 YouTube",
"description": "打开输入文字的 YouTube 搜索结果。"
},
"zh-Hant": {
"name": "搜尋 YouTube",
"description": "打開輸入文字的 YouTube 搜尋結果。"
}
},
"group": "Examples",
"keywords": [
"yt",
"youtube"
],
"argument": "required",
"argumentType": "text",
"argumentHint": "keywords",
"symbol": "play.rectangle",
"successNotice": "none",
"successMessage": "",
"failureNotice": "error",
"failureMessage": "",
"copyOutput": false,
"steps": [
{
"kind": "builtin",
"builtin": "openURL",
"url": "https://www.youtube.com/results?search_query={{input}}",
"timeout": 10
}
],
"permissions": {}
}Share and import
“Export…” saves a workflow as a file you can share, and “Import…” adds one. Each workflow has a unique ID; importing one with the same ID and a higher version replaces the old copy.