# Script Task Templates When creating a script-mode task, always use one of these templates. The template handles all boilerplate (input parsing, validation, iteration, error handling, summary). You only write the task-specific logic. ## Inputs All task inputs defined in the TASK.md frontmatter are available to the script in two ways: 1. **Environment variables**: `INPUT_` (uppercase) — e.g. `file_path` → `$INPUT_FILE_PATH` 2. **Positional arguments**: if `args: [file_path]` is set in TASK.md, the value is passed as `$1` ## Templates ### 1. File Processor Use when the task operates on a file or directory of files. **When to use**: converting files, transcoding, extracting metadata, batch renaming, any per-file operation. **Structure**: Define `EXTENSIONS` and `process_file()`, then the template handles discovery, iteration, and summary. ```bash #!/usr/bin/env bash set -euo pipefail # ── Task: ── EXTENSIONS="ext1|ext2|ext3" process_file() { local input="$1" # ... do work on $input ... # return 0 on success, 1 on failure } # ── Template: File Processor ── TARGET="${1:-${INPUT_FILE_PATH:-}}" if [[ -z "$TARGET" ]]; then echo "Error: No file or directory path provided" >&2 exit 1 fi if [[ ! -e "$TARGET" ]]; then echo "Error: Path does not exist: $TARGET" >&2 exit 1 fi converted=0 failed=0 if [[ -f "$TARGET" ]]; then if process_file "$TARGET"; then converted=$((converted + 1)) else failed=$((failed + 1)) fi elif [[ -d "$TARGET" ]]; then while IFS= read -r -d '' file; do if process_file "$file"; then converted=$((converted + 1)) else failed=$((failed + 1)) fi done < <(find "$TARGET" -type f -regextype posix-extended -iregex ".*\.($EXTENSIONS)" -print0 | sort -z) if [[ $converted -eq 0 && $failed -eq 0 ]]; then echo "No matching files found in: $TARGET" exit 0 fi else echo "Error: Not a file or directory: $TARGET" >&2 exit 1 fi echo "" echo "Summary: $converted processed, $failed failed" ``` **Slots to fill**: - `EXTENSIONS` — pipe-separated list of file extensions to match when processing a directory - `process_file()` — receives one argument: the full path to the file. Print progress to stdout, errors to stderr. Return 0 on success, 1 on failure. **Example** (convert audio to MP3): ```bash EXTENSIONS="flac|wav|ogg|wma|aac|m4a|opus" process_file() { local input="$1" local output="${input%.*}.mp3" if [[ -f "$output" ]]; then echo "Skipping (exists): $output" return 0 fi echo "Converting: $input" if ffmpeg -i "$input" -codec:a libmp3lame -b:a 320k -y "$output" 2>/dev/null; then echo " Done" else echo " Failed" >&2 return 1 fi } ``` ### 2. Standalone Use when the task doesn't operate on a specific file target — it uses inputs from environment variables or takes no input at all. **When to use**: fetching data from APIs, generating reports, system tasks, anything that isn't per-file processing. ```bash #!/usr/bin/env bash set -euo pipefail # ── Task: ── main() { # Access inputs via $INPUT_* environment variables # e.g. $INPUT_COUNTRY, $INPUT_LIMIT, $INPUT_OUTPUT_DIR # ... do work ... } # ── Template: Standalone ── main ``` **Slots to fill**: - `main()` — the entire task logic. Use `$INPUT_*` env vars for parameters. **Example** (download RSS feed): ```bash main() { local url="$INPUT_FEED_URL" local output="${INPUT_OUTPUT_DIR:-$HOME}/feed.xml" echo "Fetching: $url" if curl -sSL "$url" -o "$output"; then echo "Saved to: $output" else echo "Failed to fetch feed" >&2 exit 1 fi } ``` ## TASK.md Frontmatter Every script task needs a TASK.md with this structure: ```yaml --- name: Task Name description: What the task does version: 1 mode: script language: bash triggers: # optional — enables context menu on matching files - type: file extensions: - ext1 - ext2 - type: directory inputs: input_name: type: string # string, number, boolean description: What this input is args: [input_name] # optional — pass inputs as positional args --- # Task Name Brief description of what the task does. ``` ## Rules 1. **Always use `set -euo pipefail`** — fail fast on errors. 2. **Print progress to stdout** — the user sees this streamed in the UI. 3. **Print errors to stderr** — they appear in red in the UI. 4. **Return proper exit codes** — 0 = success, non-zero = failure. The UI shows "Task complete" or "Task failed" based on exit code. 5. **Don't assume tools are installed** — check with `command -v` before using optional dependencies. 6. **Use `$INPUT_*` env vars** — never hardcode paths or values that should come from inputs. 7. **The script runs inside a bwrap sandbox** for non-admin users — it has access to `/data/home/` (user's home), `/tmp`, and standard system tools. It cannot access other users' data. 8. **Keep scripts self-contained** — the entire script is stored in the database as a single text blob. No external file dependencies.