Steps
Arrange a linear pipeline of conditions, transforms, scripts, and one final output. Configure each step in a focused inspector and test the before and after values.
Build a workflow with visual steps or code, choose which clipboard types it supports, and run it directly beside Pasteon’s built-in actions.
A Workflow is the saved recipe. Its Action appears in Pasteon only when the selected clipboard item matches the inputs you choose.
Arrange a linear pipeline of conditions, transforms, scripts, and one final output. Configure each step in a focused inspector and test the before and after values.
Run inline code or an external script with your interpreter, arguments, working directory, and timeouts. Use Simple mode for one result or Script Filter for runtime choices.
This example trims copied text, normalizes its naming style, and returns the result to the app you are working in.
Open Settings → Workflows, add a Workflow, give it a name and icon, then select the clipboard types where its Action should appear.
Add Trim Text, Change Case, or other steps. Drag to reorder them. The Output stays fixed at the end so the pipeline remains predictable.
Run the test without copying, pasting, or opening anything. Inspect each step’s before and after value, duration, and validation state.
The Workflow appears directly after built-in Primary Actions. Click or press Enter to paste the result; hold Command to copy it instead.
Steps run from top to bottom. Conditions decide when an Action applies, transforms update the current value, and one output defines what Pasteon does with it.
Pasteon sends versioned JSON to stdin and reads protocol JSON from stdout. Logs belong on stderr, while timeouts, cancellation, and output limits keep runs controlled.
Use Simple mode when one Action should produce one text, file, or URL result.
{
"version": 1,
"result": {
"type": "text",
"value": "Ready to paste"
}
}The filter phase returns lightweight candidate metadata. Pasteon runs execute only after the user chooses one candidate.
{
"version": 1,
"actions": [
{
"id": "swift",
"title": "Generate Swift Model",
"argument": { "language": "swift" }
}
]
}The script receives phase “filter” and returns up to 20 candidate Actions.
Pasteon displays the titles, descriptions, icons, and JSON arguments without precomputing results.
The chosen actionId and argument return to the script, which computes only that result.
Use stdout only for protocol JSON. Write diagnostics to stderr. Inline and external scripts share the same input and output contract.
Use this reference when writing Code Workflows or generating .pasteon-workflow files. Field names and limits match the current Pasteon runner.
These values control where the Workflow appears and how Pasteon launches its script.
| Field | Type | Required | What it does |
|---|---|---|---|
id | UUID | Yes | Stable Workflow identifier used for updates, Filter sessions, import conflict detection, and workflowID input. |
defaultIntroducedVersion | Integer | null | Bundled only | Catalog version that introduced a bundled default. It lets upgrades install only newly added defaults without restoring ones a user deleted. |
name | String | Yes | The Workflow and Action name shown in Settings and the Pasteon action list. |
nameLocalizationKey | String | null | Bundled only | Optional String Catalog key used to localize the name of a bundled Workflow. User edits clear this key. |
summary | String | No | A short explanation displayed beside the Action. It does not affect execution. |
summaryLocalizationKey | String | null | Bundled only | Optional localization key for the bundled Workflow summary. |
symbolName | SF Symbol name | Yes | The icon used by the Workflow Action. Invalid candidate icons fall back to this symbol. |
isEnabled | Boolean | Yes | Disabled Workflows remain saved but do not generate Actions. |
requiresTrustConfirmation | Boolean | null | Imported | Marks imported code as untrusted. Pasteon sets this to true and disables the Workflow until the user confirms it. |
sortOrder | Number | Yes | Controls the order of Custom Workflow Actions after built-in Primary Actions. |
mode | simple | scriptFilter | Yes | Simple executes immediately. Script Filter runs filter first, then execute after a candidate is chosen. |
supportedTypes | PasteType[] | Yes | Clipboard types where the Action may appear: text, markdown, html, json, url, color, date, timestamp, fileURL, imageURL, videoURL, image, or appObject. |
editorMode | steps | code | No | Selects the visual linear editor or script editor. Older Workflow files without this field use Code. |
script.source | inline | external | Code | Inline stores code inside the Workflow. External references a script on disk. |
script.code | String | Inline | The inline script body. Pasteon writes it to a temporary file for each run. |
script.codeResource | Resource name | null | Bundled only | Bundle resource containing code for a default Workflow. Exported user Workflows carry resolved inline code instead. |
script.scriptPath | File path | External | Path to the external script. Tilde paths are expanded. Missing files keep the configuration but prevent an Action from appearing. |
script.interpreterPath | Executable path | Inline | Executable used to run the script, such as /bin/zsh or the result of which node. External executable scripts may leave it empty. |
script.arguments | String[] | No | Arguments passed as an array before the generated or external script path. Pasteon does not join them into a shell command. |
script.workingDirectory | Directory path | No | Current directory for the process. When empty, external scripts use their folder and inline scripts use the temporary input folder. |
script.filterTimeout | Seconds | Filter | Maximum Filter duration. Values are clamped to 1–120 seconds; the default is 5. |
script.executeTimeout | Seconds | Yes | Maximum Execute duration. Values are clamped to 1–120 seconds; the default is 15. |
steps | WorkflowStep[] | null | Steps | Ordered linear step definitions. Steps mode requires Simple mode and exactly one final output. OCR enables image input; PNG File and Open in Finder apply stricter input-type rules. |
variables | WorkflowVariableDefinition[] | null | No | Reusable Text or Secret values available to Steps templates and Code Workflow stdin. Names must be unique within the Workflow. |
Pasteon builds this object only after the user runs a Workflow. Binary clipboard representations are materialized as temporary files instead of being embedded in JSON.
| Field | Type | Required | What it does |
|---|---|---|---|
version | Integer | Yes | Workflow protocol version. The current and only supported value is 1. |
workflowID | UUID String | Yes | Stable identifier of the Workflow being run. |
phase | filter | execute | Yes | Tells a shared script which stage to run. Simple Workflows receive execute only. |
paste.id | UUID String | Yes | Identifier of the selected Pasteon history item. |
paste.type | PasteType | Yes | The derived clipboard content type used for Workflow visibility and script logic. |
paste.text | String | null | No | Text form of the selected content when available. Files and binary images may not have text. |
paste.sourceAppBundleIdentifier | String | null | No | Bundle identifier of the app where the clipboard item was originally copied. |
paste.representations | Representation[] | Yes | All available pasteboard representations. Text may be inline; binary data is exposed by file path. |
targetApp.bundleIdentifier | String | null | No | Bundle identifier of the frontmost app that will receive the result. |
targetApp.name | String | null | No | Localized display name of the frontmost target app. |
directories.input | Directory path | Yes | Temporary run directory containing the inline script and materialized binary inputs. Removed after the run. |
directories.output | Directory path | Yes | Directory where the script should create returned files. Unused output directories are cleaned after 24 hours. |
variables | Record<String, String> | Yes | Resolved variables keyed by name. Text and Secret values are available during both Filter and Execute. |
actionID | String | null | Execute after Filter | ID of the candidate chosen from Filter output. Null during filter and for Simple Workflows. |
argument | JSON value | null | Execute after Filter | The selected candidate’s argument, returned unchanged so execute can compute only that choice. |
{
"version": 1,
"workflowID": "5F604A89-7AC2-45D9-B48C-BB540B60CA67",
"phase": "execute",
"paste": {
"id": "D0A4E45A-61F6-4DAF-BC1E-4E17A23AA5C0",
"type": "json",
"text": "{\"name\":\"Pasteon\"}",
"sourceAppBundleIdentifier": "com.apple.Safari",
"representations": [
{
"type": "public.utf8-plain-text",
"value": "{\"name\":\"Pasteon\"}",
"path": null,
"fileName": null,
"fileSize": 18,
"temporary": false
}
]
},
"targetApp": {
"bundleIdentifier": "com.apple.dt.Xcode",
"name": "Xcode"
},
"directories": {
"input": "/tmp/Pasteon/WorkflowInputs/RUN_ID",
"output": "~/Library/Application Support/Pasteon/WorkflowOutputs/RUN_ID"
},
"variables": {
"API_BASE_URL": "https://api.example.com",
"API_TOKEN": "••••••••"
},
"actionID": "swift",
"argument": { "language": "swift" }
}Each example reads the complete stdin payload, accesses paste.text and a PREFIX Workflow variable, then writes one valid Simple Workflow result to stdout.
Use file descriptor 0 with the Node.js standard library.
/opt/homebrew/bin/nodeconst fs = require("node:fs");
const payload = JSON.parse(fs.readFileSync(0, "utf8"));
const text = payload.paste?.text ?? "";
const prefix = payload.variables?.PREFIX ?? "";
process.stdout.write(JSON.stringify({
version: 1,
result: { type: "text", value: prefix + text }
}));Use json.load with sys.stdin and json.dump with sys.stdout.
/opt/homebrew/bin/python3import json
import sys
payload = json.load(sys.stdin)
text = payload.get("paste", {}).get("text") or ""
prefix = payload.get("variables", {}).get("PREFIX", "")
json.dump({
"version": 1,
"result": {"type": "text", "value": prefix + text}
}, sys.stdout)Read $stdin, parse with JSON, and write only protocol JSON.
/opt/homebrew/bin/rubyrequire "json"
payload = JSON.parse($stdin.read)
text = payload.dig("paste", "text") || ""
prefix = payload.dig("variables", "PREFIX") || ""
$stdout.write(JSON.generate({
version: 1,
result: { type: "text", value: prefix + text }
}))Read the STDIN stream and use PHP’s built-in JSON functions.
/opt/homebrew/bin/php<?php
$payload = json_decode(stream_get_contents(STDIN), true);
$text = $payload["paste"]["text"] ?? "";
$prefix = $payload["variables"]["PREFIX"] ?? "";
echo json_encode([
"version" => 1,
"result" => ["type" => "text", "value" => $prefix . $text]
]);Read FileHandle.standardInput and decode with Foundation.
/usr/bin/swiftimport Foundation
let data = FileHandle.standardInput.readDataToEndOfFile()
let payload = try JSONSerialization.jsonObject(with: data) as? [String: Any]
let paste = payload?["paste"] as? [String: Any]
let variables = payload?["variables"] as? [String: String]
let text = paste?["text"] as? String ?? ""
let prefix = variables?["PREFIX"] ?? ""
let response: [String: Any] = [
"version": 1,
"result": ["type": "text", "value": prefix + text]
]
let output = try JSONSerialization.data(withJSONObject: response)
FileHandle.standardOutput.write(output)Zsh reads the raw payload; jq performs JSON parsing and encoding.
/bin/zsh#!/bin/zsh
set -euo pipefail
payload="$(cat)"
text="$(printf '%s' "$payload" | jq -r '.paste.text // ""')"
prefix="$(printf '%s' "$payload" | jq -r '.variables.PREFIX // ""')"
jq -n --arg value "$prefix$text" '{
version: 1,
result: {type: "text", value: $value}
}'Pasteon does not bundle language runtimes or jq. Set interpreterPath to an executable that exists on the current Mac. Homebrew paths differ between Apple silicon and Intel Macs; use “which node”, “which python3”, or the equivalent to find the correct path.
Every step has identity, behavior, enabled state, and one shared configuration object. Only fields used by the selected kind affect execution.
| Field | Type | Required | What it does |
|---|---|---|---|
steps[].id | UUID | Yes | Stable identity used by selection, drag ordering, validation, and per-step test results. |
steps[].kind | WorkflowStepKind | Yes | Selects the condition, transform, script, or output operation. |
steps[].isEnabled | Boolean | Yes | Disabled non-output steps are skipped. The final Output cannot be disabled. |
configuration.pattern | String | Match / Replace | Text, app identifier fragment, or regular expression to test or replace. |
configuration.replacement | String | Replace | Replacement text. In Regex mode it follows NSRegularExpression replacement template rules. |
configuration.matchMode | contains | equals | startsWith | endsWith | regularExpression | Match / Replace | Controls how pattern is compared. Replace uses plain replacement unless regularExpression is selected. |
configuration.isCaseSensitive | Boolean | Match / Replace | When false, text comparison and Regex replacement are case-insensitive. |
configuration.trimMode | whitespaceAndNewlines | whitespace | newlines | Trim | Selects which characters are removed from both ends. |
configuration.caseStyle | camel | pascal | snake | screamingSnake | kebab | train | dot | Change Case | Target naming convention for the current text. |
configuration.template | String | Template | Text template containing supported placeholders such as {{input}} and {{date}}. |
configuration.fileName | String | Output File | Output file name, with template variables allowed. Directory components are discarded for safety. |
configuration.script | ScriptConfiguration | Run Script | Script settings for this step. A Run Script step must return a text result for the next visual step. |
textConditionShow and run only when the current text matches pattern.
sourceAppConditionMatch the bundle identifier of the app that created the clip.
targetAppConditionMatch the bundle identifier of the frontmost destination app.
trimTextRemove selected whitespace characters from both ends.
replaceTextPerform plain or regular-expression replacement.
changeCaseConvert the current text to the configured naming style.
urlEncode / urlDecodePercent-encode or decode the current text.
jsonPretty / jsonMinifyParse JSON, sort keys, then pretty-print or compact it.
templateReplace supported placeholders in a text template.
runScriptRun a Simple Code Workflow step that must return text.
recognizeTextUse macOS Vision OCR on Clipboard Image or ImageURL input and pass the recognized text to the following steps.
outputText / outputFile / outputOpenURLReturn text, create a text file, or open a supported URL. Exactly one output is kept at the end of a valid Steps Workflow.
outputPNGFileConvert Clipboard Image or ImageURL input to a PNG file. Other input types make the Workflow invalid.
outputRevealInFinderReveal a local FileURL, ImageURL, or VideoURL in Finder. Workflow testing reports the path without opening Finder.
Each representation describes one pasteboard flavor. Use value for text and path for files or materialized binary data.
| Field | Type | Required | What it does |
|---|---|---|---|
type | UTI String | Yes | Pasteboard type identifier, such as public.utf8-plain-text, public.file-url, public.png, or public.html. |
value | String | null | No | Inline UTF-8 value for text-like representations or the original file URL string. |
path | File path | null | No | Original local file path or temporary path created for binary representation data. |
fileName | String | null | No | Original or generated safe file name associated with the representation. |
fileSize | Int64 | Yes | Representation size in bytes, using stored metadata when available. |
temporary | Boolean | Yes | True when Pasteon wrote binary data into directories.input for this run. Do not retain that path. |
Filter output describes choices only. It must not contain final generated content or perform work for every candidate.
| Field | Type | Required | What it does |
|---|---|---|---|
version | Integer | Yes | Must equal the supported protocol version: 1. |
actions | Action[] | Yes | Non-empty candidate list. Pasteon validates and displays at most the first 20 items. |
actions[].id | String | Yes | Candidate identifier returned as actionID during execute. After trimming, length must be 1–120 characters. |
actions[].title | String | Yes | Visible candidate title. After trimming, length must be 1–120 characters. |
actions[].subtitle | String | null | No | Secondary explanation shown beside the candidate. Pasteon keeps the first 240 characters. |
actions[].icon | SF Symbol | null | No | SF Symbol name for the candidate. Invalid symbols fall back to the parent Workflow icon. |
actions[].argument | JSON value | null | No | Opaque JSON value sent back unchanged during execute. It may be an object, array, string, number, boolean, or null. |
Execute returns exactly one result object. Include only the field required by its type.
| Field | Type | Required | What it does |
|---|---|---|---|
version | Integer | Yes | Must equal the supported protocol version: 1. |
result | Object | Yes | The one final result Pasteon should apply. |
result.type | text | files | openURL | revealFile | Yes | Selects validation and the normal versus Command-mode behavior. |
result.value | String | text | Non-empty text to paste normally or copy when Command mode is active. |
result.paths | String[] | files | revealFile | For files, a non-empty list whose relative paths resolve inside directories.output and must exist. For revealFile, the first path is the local item to reveal. |
result.url | String | openURL | Valid http, https, or mailto URL. Normal mode opens it; Command mode copies it. |
revealFile behavior | Local file action | revealFile | Normal Action execution reveals the first path in Finder and hides Pasteon. Command mode does not change this result into copy-only behavior. |
{
"version": 1,
"result": {
"type": "files",
"paths": ["GeneratedModel.swift"]
}
}The runner launches processes without shell-string concatenation, streams both output channels, and terminates work when the user leaves the session.
stdout must contain one protocol JSON document and no log lines. Exceeding the limit terminates the process.
Write logs and diagnostics to stderr. It is captured for testing and errors.
Filter and Execute have separate configurable timeouts. Pasteon terminates an overdue process.
A non-zero process exit is treated as failure, with captured stderr included in the error.
Switching Paste items, returning from Filter results, editing or deleting the Workflow, or closing the window cancels the run.
Arguments are passed as an array. Pasteon does not expand pipes, wildcards, variables, or other shell syntax.
Workflow output directories older than 24 hours are removed during application cleanup.
Scripts execute locally with the current macOS user’s access. Review imported code before enabling it.
Define values once in Settings and reuse them in visual Steps or Code Workflows. Text values are stored with the Workflow. Secret values are stored in the macOS Keychain and removed from exported files.
| Field | Type | Required | What it does |
|---|---|---|---|
variables[].id | UUID | Yes | Stable identity used to associate a Secret with its Keychain value. Copying a Workflow creates new variable IDs. |
variables[].name | String | Yes | Case-sensitive lookup name. It must match [A-Za-z_][A-Za-z0-9_]* and be unique within the Workflow. |
variables[].kind | text | secret | Yes | Text stores its value in the Workflow. Secret stores its value in the macOS Keychain. |
variables[].value | String | Text only | Text value saved and exported with the Workflow. Secret definitions always export this field as an empty string. |
{
"variables": [
{
"id": "C3EEAF0E-0AD8-4A26-924C-CB867088D955",
"name": "API_BASE_URL",
"kind": "text",
"value": "https://api.example.com"
},
{
"id": "7E05B2EE-E745-4558-A267-E63B7D1E2235",
"name": "API_TOKEN",
"kind": "secret",
"value": ""
}
]
}Template and file-name steps replace these built-in placeholders and any {{variables.NAME}} value at runtime.
{{input}}Current text from the previous step.{{sourceApp}}Source app bundle identifier, or an empty string.{{targetApp}}Frontmost target app bundle identifier, or an empty string.{{clipboardType}}Current PasteType raw value.{{date}}Current date and time in ISO 8601 format.{{variables.NAME}}Value of the user-defined Text or Secret variable with the matching case-sensitive name.Code Workflows can read these in addition to the stdin JSON object.
PASTEON_WORKFLOW_IDUUID of the current Workflow.PASTEON_WORKFLOW_PHASEfilter or execute.PASTEON_INPUT_DIRPath matching directories.input.PASTEON_OUTPUT_DIRPath matching directories.output.Exports are readable versioned JSON. A file may contain one Workflow or the full Workflow list.
| Field | Type | Required | What it does |
|---|---|---|---|
version | Integer | Yes | Envelope protocol version. Import currently accepts version 1. |
installedDefaultsVersion | Integer | null | No | Internal default-catalog state. User exports write null and imports do not use it to enable defaults. |
workflows | WorkflowDefinition[] | Yes | One or more complete Workflow definitions. A bare single WorkflowDefinition is also accepted for compatibility. |
This one script handles both phases. Filter returns two lightweight choices; Execute computes only the selected result.
Interpreter: /opt/homebrew/bin/nodeasync function main() {
let input = "";
process.stdin.setEncoding("utf8");
for await (const chunk of process.stdin) input += chunk;
const payload = JSON.parse(input);
const text = payload.paste?.text ?? "";
let response;
if (payload.phase === "filter") {
response = {
version: 1,
actions: [
{
id: "uppercase",
title: "Convert to Uppercase",
subtitle: "Uppercase the copied text",
icon: "textformat",
argument: null
},
{
id: "wrap",
title: "Wrap in Brackets",
subtitle: "Add [ and ]",
icon: "curlybraces",
argument: { prefix: "[", suffix: "]" }
}
]
};
} else {
const argument = payload.argument ?? {};
const value =
payload.actionID === "uppercase"
? text.toUpperCase()
: (argument.prefix ?? "") + text + (argument.suffix ?? "");
response = {
version: 1,
result: { type: "text", value }
};
}
process.stdout.write(JSON.stringify(response));
}
main().catch((error) => {
process.stderr.write(`${error.stack ?? error.message}\n`);
process.exit(1);
});Use the path returned by “which node” on your Mac. Avoid console.log because it writes to stdout; use console.error for diagnostics.
Normal execution performs the result immediately. Command-click or Command + Enter switches text, files, and URLs to copy-only mode. Finder reveal always locates the file.
textReturn generated text, cleaned content, templates, code, or any other string.
filesCreate files in the provided output directory and return their paths to Pasteon.
openURLOpen supported web or mail links normally, or copy the URL in Command mode.
revealFileLocate the returned local file in Finder. Workflow tests show the path without opening Finder.
Pasteon ships these enabled by default. You can inspect, edit, disable, duplicate, export, or delete them like any other Workflow.
Script Filter.json.txt.mdopenURLScript FilterSimpleScript FilterOCR → TextImage → .pngrevealFileWorkflow files stay readable and portable. Imported Workflows remain disabled until you review and trust their code.
No. Steps mode covers common conditions, text transforms, templates, scripts, and outputs in a visual linear editor. Code mode is available when you need custom behavior.
Simple runs once and returns one result. Script Filter first returns lightweight choices, then runs the selected choice in a separate execute phase.
An enabled Workflow appears after built-in Primary Actions when the selected clipboard item matches its input types and visual conditions.
Scripts run locally on your Mac with the interpreter and working directory you configure. Imported Workflows are disabled until you review and enable them.
Yes. You can create, test, import, export, and run Custom Workflows with Pasteon Pro.
Download Pasteon for Mac, start with a visual Workflow, and move into scripts only when your process needs them.