This document provides detailed specifications for all workflow node types.
| Category | Nodes | Description |
|---|---|---|
| Variables | variable, set |
Declare and update variables |
| Control | if, while, sleep |
Conditional branching, loops, pausing |
| LLM | command |
Execute prompts via Gemini API |
| Data | http, json, script |
HTTP requests, JSON parsing, JavaScript execution |
| Drive | drive-file, drive-read, drive-search, drive-list, drive-folder-list, drive-save, drive-delete |
Google Drive file operations |
| Prompts | prompt-value, prompt-file, prompt-selection, dialog, drive-file-picker |
User input dialogs |
| Composition | workflow |
Execute another workflow as a sub-workflow |
| External | mcp |
Call remote MCP servers |
| RAG | rag-sync |
Sync files to RAG stores |
| Commands | gemihub-command |
Execute GemiHub file operations |
Declare and initialize a variable.
- id: init
type: variable
name: counter
value: "0"| Property | Required | Template | Description |
|---|---|---|---|
name |
Yes | No | Variable name |
value |
No | Yes | Initial value (default: empty string) |
Numeric values are auto-detected: if the value parses as a number, it's stored as a number.
value is optional on variable nodes. Omitting it gives two useful behaviors:
- Input declaration — If the variable has already been set by the caller (parent workflow, skill invocation, or hotkey trigger), the existing value is preserved. This lets a workflow declare the inputs it expects without overwriting them.
- Empty accumulator — If no caller set the variable, it is initialized to
"". This is safe for accumulators that will be appended to later.
# Input declaration — uses the caller's value, or "" if not provided
- id: declare-input
type: variable
name: inputText
# Accumulator — starts as "" and is appended to downstream
- id: init-output
type: variable
name: outputMarkdown
# Explicit initial value — always resets to 0 regardless of caller state
- id: init-counter
type: variable
name: counter
value: 0Update a variable with an expression.
- id: increment
type: set
name: counter
value: "{{counter}} + 1"| Property | Required | Template | Description |
|---|---|---|---|
name |
Yes | No | Variable name to update |
value |
Yes | Yes | Expression to evaluate |
Supports arithmetic operators: +, -, *, /, %. Variables are resolved first, then the result is evaluated as arithmetic if it matches the pattern number operator number.
Note: Only a single binary operation is supported (e.g.,
{{counter}} + 1). Compound expressions like5 + 3 * 2are treated as a plain string because they don't match thenumber operator numberpattern.
Conditional branching.
- id: branch
type: if
condition: "{{count}} > 10"
trueNext: handleMany
falseNext: handleFew| Property | Required | Template | Description |
|---|---|---|---|
condition |
Yes | Yes | Expression with comparison operator |
Supported operators: ==, !=, <, >, <=, >=, contains
Edge routing: trueNext / falseNext (defined in YAML, not as properties)
The contains operator works with both strings and JSON arrays:
- String:
{{text}} contains error - Array:
{{dialogResult.selected}} contains Option A
Loop with condition.
- id: loop
type: while
condition: "{{counter}} < {{total}}"
trueNext: processItem
falseNext: done| Property | Required | Template | Description |
|---|---|---|---|
condition |
Yes | Yes | Loop condition (same format as if) |
Edge routing: trueNext (loop body) / falseNext (exit)
Maximum iterations per while node: 1000 (global limit).
Pause workflow execution.
- id: wait
type: sleep
duration: "2000"| Property | Required | Template | Description |
|---|---|---|---|
duration |
Yes | Yes | Sleep duration in milliseconds |
Execute an LLM prompt via Gemini API.
- id: ask
type: command
prompt: "Summarize: {{content}}"
model: gemini-2.5-flash
ragSetting: __websearch__
driveToolMode: all
mcpServers: "mcp_server_id_1,mcp_server_id_2"
attachments: "imageVar"
saveTo: summary
saveImageTo: generatedImage
systemPrompt: "You are a helpful assistant."| Property | Required | Template | Description |
|---|---|---|---|
prompt |
Yes | Yes | Prompt text to send to the LLM |
model |
No | Yes | Model name (default: user's selected model) |
ragSetting |
No | No | RAG setting name, __websearch__ for web search, or __none__ (default) |
driveToolMode |
No | No | none (default), all, noSearch — enables Drive tool calling |
mcpServers |
No | No | Comma-separated MCP server IDs to enable |
attachments |
No | Yes | Comma-separated variable names containing FileExplorerData |
saveTo |
No | No | Variable to store text response |
saveImageTo |
No | No | Variable to store generated image (FileExplorerData JSON) |
systemPrompt |
No | Yes | System prompt for the LLM |
enableThinking |
No | No | "true" (default) to enable thinking/reasoning, "false" to disable |
command node uses the same tool constraints as chat:
- Gemma models force function tools (Drive/MCP) off
- Web Search mode forces function tools (Drive/MCP) off
Make HTTP requests.
- id: fetch
type: http
url: "https://api.example.com/data"
method: POST
contentType: json
headers: '{"Authorization": "Bearer {{token}}"}'
body: '{"query": "{{searchTerm}}"}'
saveTo: response
saveStatus: statusCode
throwOnError: "true"| Property | Required | Template | Description |
|---|---|---|---|
url |
Yes | Yes | Request URL |
method |
No | Yes | GET (default), POST, PUT, PATCH, DELETE |
contentType |
No | Yes | json (default), form-data, text, binary |
headers |
No | Yes | JSON object or Key: Value format (one per line) |
body |
No | Yes | Request body (for POST/PUT/PATCH) |
responseType |
No | Yes | auto (default), text, binary — override Content-Type auto-detection |
saveTo |
No | No | Variable for response body |
saveStatus |
No | No | Variable for HTTP status code |
throwOnError |
No | Yes | Throw on 4xx/5xx responses. Default: "true" — HTTP errors abort the workflow. Set "false" only when the workflow explicitly handles errors downstream. |
throwOnError — default is "true". A 4xx/5xx response aborts the workflow so the failure surfaces to the chat AI, the user, and the "Open workflow" recovery UI (for skill workflows). Only set "false" when the workflow genuinely reads saveStatus and takes a different downstream path on failure — not merely to prevent a crash.
# ✅ Default: HTTP errors abort the workflow
- id: fetch
type: http
url: "{{url}}"
saveTo: body
saveStatus: status
# ✅ Acceptable: explicit error-handling branch downstream
- id: fetch
type: http
url: "{{url}}"
throwOnError: "false"
saveTo: body
saveStatus: status
- id: check-status
type: if
condition: "{{status}} >= 400"
trueNext: handle-error # real branch that does something useful
# ❌ Anti-pattern: swallows every HTTP failure with no handler
- id: fetch
type: http
url: "{{url}}"
throwOnError: "false" # workflow "succeeds" even on 503
saveTo: bodyCross-origin requests (CORS): Requests run as browser fetch(). Same-origin and CORS-enabled cross-origin endpoints work directly. For other cross-origin URLs (news sites, OGP scraping, legacy APIs without CORS headers), both plans transparently route through a server proxy (/api/workflow/http-fetch) so the request succeeds. Free accounts are rate-limited to 2 req/min; Premium gets 60 req/min.
Proxy limits: The server proxy enforces:
- Per-user rate limit — 60 req/min on Premium, 2 req/min on the free plan. 429 with
Retry-After: 60when exceeded. - 20 MB response size cap — over-limit bodies return 413 (via
Content-Lengthcheck and read-time enforcement). - 30 s upstream timeout — stuck upstreams return 502.
- SSRF guard — hostnames resolving to private / loopback / metadata IP ranges are rejected with 400. DNS resolve failures are reported as 502 (not SSRF) so retry logic behaves correctly.
Response type detection: By default (auto), binary vs text is auto-detected from the Content-Type header. Use responseType: text to force text processing (e.g., when a server returns application/octet-stream for JSON), or responseType: binary to force binary handling.
Binary responses are automatically detected and stored as FileExplorerData JSON (Base64 encoded).
binary contentType: Sends FileExplorerData as raw binary with its original mimeType. Use with drive-file-picker or image generation results.
form-data example:
- id: upload
type: http
url: "https://example.com/upload"
method: POST
contentType: form-data
body: '{"file": "{{fileData}}"}'
saveTo: responseFor form-data:
- FileExplorerData (from
drive-file-picker/drive-save) is auto-detected and sent as binary - Use
fieldName:filenamesyntax for text file fields (e.g.,"file:report.html": "{{htmlContent}}")
Parse a JSON string into an object for property access.
- id: parseResponse
type: json
source: response
saveTo: data| Property | Required | Template | Description |
|---|---|---|---|
source |
Yes | No | Bare variable name holding the JSON string — no {{...}}, no surrounding quotes |
saveTo |
Yes | No | Variable for parsed result |
After parsing, access properties using dot notation: {{data.items[0].name}}
JSON in markdown code blocks: Automatically extracted from ```json ... ``` fences.
source is a bare variable name. Pass just the name — don't interpolate, don't wrap it, don't put it inside brackets:
# ✅ Correct
- id: parse-body
type: json
source: apiResponseBody
saveTo: parsed
# ❌ Wrong
- id: parse-body
type: json
source: "{{apiResponseBody}}" # no interpolation here
# or: source: "[{{apiResponseBody}}]" # wrapping corrupts valid JSON
saveTo: parsedExecute JavaScript code in a sandboxed iframe. The sandbox has no access to DOM, network, or storage — only pure computation. Useful for string manipulation, data transformation, calculations, encoding/decoding, and other operations that set node arithmetic cannot handle.
- id: transform
type: script
code: |
var items = '{{rawList}}'.split(',').map(function(s){ return s.trim(); });
items.sort();
return items.join('\n');
saveTo: sortedList
timeout: "5000"| Property | Required | Template | Description |
|---|---|---|---|
code |
Yes | Yes | JavaScript code to execute. Use return to return a value. |
saveTo |
No | No | Variable to store the result |
timeout |
No | No | Timeout in milliseconds (default: 10000) |
Return values:
undefined/null→ empty string- Non-string values → JSON-serialized (e.g., arrays, objects, numbers)
- Strings → stored as-is
Async support: Promises are automatically awaited.
Security: Runs in an iframe with sandbox="allow-scripts" (opaque origin). No access to parent DOM, cookies, localStorage, or network.
Example — Base64 encode:
- id: encode
type: script
code: "return btoa('{{plainText}}')"
saveTo: encodedExample — extract unique words:
- id: unique-words
type: script
code: |
var words = '{{text:json}}'.split(/\s+/);
var unique = [...new Set(words)];
return unique.sort().join(', ');
saveTo: uniqueWordsNote: The
commandnode also has access to anexecute_javascripttool via function calling, allowing the AI to write and run JavaScript code dynamically during a chat or workflow command execution.
Write content to a Google Drive file.
- id: save
type: drive-file
path: "output/{{filename}}.md"
content: "{{result}}"
mode: overwrite
confirm: "true"
history: "true"
open: "true"| Property | Required | Template | Description |
|---|---|---|---|
path |
Yes | Yes | File path (.md extension auto-appended if missing) |
content |
No | Yes | Content to write (default: empty string) |
mode |
No | No | overwrite (default), append, create (skip if exists) |
confirm |
No | No | "true" (default) to show diff review dialog when updating existing files; "false" to write without confirmation |
history |
No | No | "true" to save edit history |
open |
No | No | "true" to open the file in the editor after workflow completes |
Read content from a Google Drive file.
- id: read
type: drive-read
path: "notes/config.md"
saveTo: content| Property | Required | Template | Description |
|---|---|---|---|
path |
Yes | Yes | File path or Drive file ID |
saveTo |
Yes | No | Variable to store file content |
Smart path resolution:
- If path looks like a Drive file ID (no extension, >20 chars): reads directly
- Otherwise: searches by file name, tries with
.mdextension as fallback
Search for files on Google Drive.
- id: search
type: drive-search
query: "{{searchTerm}}"
searchContent: "true"
limit: "10"
saveTo: results| Property | Required | Template | Description |
|---|---|---|---|
query |
Yes | Yes | Search query string |
searchContent |
No | No | "true" to search file contents (default: name only) |
limit |
No | Yes | Maximum results (default: 10) |
saveTo |
Yes | No | Variable for results |
Output format:
[
{"id": "abc123", "name": "notes/todo.md", "modifiedTime": "2026-01-01T00:00:00Z"}
]List files with filtering.
- id: list
type: drive-list
folder: "Projects"
limit: "20"
sortBy: modified
sortOrder: desc
modifiedWithin: "7d"
saveTo: fileList| Property | Required | Template | Description |
|---|---|---|---|
folder |
No | Yes | Virtual folder prefix (e.g., "Projects") |
limit |
No | Yes | Maximum results (default: 50) |
sortBy |
No | Yes | modified (default), created, name |
sortOrder |
No | Yes | desc (default), asc |
modifiedWithin |
No | Yes | Time filter (e.g., "7d", "24h", "30m") |
createdWithin |
No | Yes | Time filter (e.g., "30d") |
saveTo |
Yes | No | Variable for results |
Output format:
{
"notes": [
{"id": "abc123", "name": "Projects/todo.md", "modifiedTime": "...", "createdTime": "..."}
],
"count": 5,
"totalCount": 12,
"hasMore": true
}Uses sync metadata for fast listing (no per-file API calls). "Folders" are virtual — derived from path prefixes in file names.
List virtual folders.
- id: listFolders
type: drive-folder-list
folder: "Projects"
saveTo: folderList| Property | Required | Template | Description |
|---|---|---|---|
folder |
No | Yes | Parent virtual folder path |
saveTo |
Yes | No | Variable for results |
Output format:
{
"folders": [{"name": "Active"}, {"name": "Archive"}],
"count": 2
}Returns only immediate subfolders (one level deep), sorted alphabetically.
Save FileExplorerData as a file on Google Drive.
- id: saveImage
type: drive-save
source: imageData
path: "images/output"
savePathTo: savedPath| Property | Required | Template | Description |
|---|---|---|---|
source |
Yes | Yes | Variable name or template containing FileExplorerData JSON |
path |
Yes | Yes | Target file path (extension auto-added from source data) |
savePathTo |
No | No | Variable to store final file name |
Note:
drive-savealways creates a new file, even if a file with the same path already exists. This differs fromdrive-file, which supportsoverwriteandappendmodes. Running the same workflow repeatedly may create duplicate files.
Soft-delete a file by moving it to the trash/ subfolder.
- id: cleanup
type: drive-delete
path: "notes/old-file.md"| Property | Required | Template | Description |
|---|---|---|---|
path |
Yes | Yes | File path to delete (.md extension auto-appended if missing) |
The file is moved to trash/ (not permanently deleted) and removed from sync metadata. Supports the same path resolution as drive-file (companion _fileId variables, exact name fallback).
Show a text input dialog.
- id: input
type: prompt-value
title: "Enter a value"
default: "{{defaultText}}"
multiline: "true"
saveTo: userInput| Property | Required | Template | Description |
|---|---|---|---|
title |
No | Yes | Prompt label (default: "Input") |
default |
No | Yes | Default value |
multiline |
No | No | "true" for multi-line textarea |
saveTo |
Yes | No | Variable to store user input |
Throws error if user cancels.
Show a file picker and read the selected file's content.
- id: pickFile
type: prompt-file
title: "Select a file"
saveTo: fileContent
saveFileTo: fileInfo| Property | Required | Template | Description |
|---|---|---|---|
title |
No | Yes | Picker dialog title (default: "Select a file") |
saveTo |
No | No | Variable to store file content (text) |
saveFileTo |
No | No | Variable to store file info JSON ({path, basename, name, extension}) |
At least one of saveTo or saveFileTo is required. Unlike drive-file-picker, this node reads the file content automatically.
Throws error if user cancels.
Show a multiline text input dialog.
- id: getText
type: prompt-selection
title: "Enter your text"
saveTo: selection| Property | Required | Template | Description |
|---|---|---|---|
title |
No | Yes | Prompt label (default: "Enter text") |
saveTo |
Yes | No | Variable to store user input |
Always shows a multiline textarea. Throws error if user cancels.
Display a dialog with options, buttons, and/or text input.
- id: ask
type: dialog
title: Select Options
message: "Choose items to process"
markdown: "true"
options: "Option A, Option B, Option C"
multiSelect: "true"
inputTitle: "Additional notes"
multiline: "true"
defaults: '{"input": "default text", "selected": ["Option A"]}'
button1: Confirm
button2: Cancel
saveTo: dialogResult| Property | Required | Template | Description |
|---|---|---|---|
title |
No | Yes | Dialog title (default: "Dialog") |
message |
No | Yes | Message content |
markdown |
No | No | "true" renders message as Markdown |
options |
No | Yes | Comma-separated list of choices |
multiSelect |
No | No | "true" for checkboxes, "false" for radio |
inputTitle |
No | Yes | Label for text input field (shows input when set) |
multiline |
No | No | "true" for multi-line textarea |
defaults |
No | Yes | JSON with input and selected initial values |
button1 |
No | Yes | Primary button label (default: "OK") |
button2 |
No | Yes | Secondary button label |
saveTo |
No | No | Variable for result |
Result format (saveTo variable):
{
"button": "Confirm",
"selected": ["Option A", "Option B"],
"input": "some text"
}Important: When checking selected value in an
ifcondition:
- Single option:
{{dialogResult.selected[0]}} == Option A- Array contains (multiSelect):
{{dialogResult.selected}} contains Option A
Show a file picker dialog to select a Drive file. When saveTo is used, the file content is automatically loaded — binary files (PDF, images, etc.) are Base64-encoded, text files are read as-is.
- id: selectFile
type: drive-file-picker
title: "Select a file"
mode: select
extensions: "pdf,doc,md"
saveTo: fileData
savePathTo: filePath| Property | Required | Template | Description |
|---|---|---|---|
title |
No | Yes | Picker dialog title (default: "Select a file") |
mode |
No | No | select (default) to pick existing file, create to enter a new path |
default |
No | Yes | Default file path (used as initial value in create mode) |
extensions |
No | No | Comma-separated allowed extensions |
path |
No | Yes | Direct file path (bypasses picker when set) |
saveTo |
No | No | Variable for FileExplorerData JSON (includes file content) |
savePathTo |
No | No | Variable for file name/path |
At least one of saveTo or savePathTo is required.
FileExplorerData format:
{
"id": "abc123",
"path": "notes/report.pdf",
"basename": "report.pdf",
"name": "report",
"extension": "pdf",
"mimeType": "application/pdf",
"contentType": "binary",
"data": "JVBERi0xLjQg..."
}contentType:"binary"for binary files (PDF, images, etc.),"text"for text filesdata: Base64-encoded content for binary files, plain text for text files- In
createmode,datais empty (file does not exist yet)
Example — image analysis:
- id: select-image
type: drive-file-picker
title: "Select an image to analyze"
extensions: "png,jpg,jpeg,gif,webp"
saveTo: imageData
- id: analyze
type: command
prompt: "Describe this image in detail"
attachments: imageData
saveTo: analysisExample — load file without dialog:
- id: load-pdf
type: drive-file-picker
path: "{{pdfPath}}"
saveTo: pdfDataExecute another workflow as a sub-workflow.
- id: runSub
type: workflow
path: "workflows/summarize.yaml"
name: "Summarizer"
input: '{"text": "{{content}}"}'
output: '{"result": "summary"}'
prefix: "sub_"| Property | Required | Template | Description |
|---|---|---|---|
path |
Yes | Yes | Path to workflow file |
name |
No | Yes | Workflow name (for multi-workflow files) |
input |
No | Yes | JSON or key=value mapping for sub-workflow input |
output |
No | Yes | JSON or key=value mapping for output variables |
prefix |
No | No | Prefix for all output variables (when output not specified) |
Input mapping: '{"subVar": "{{parentValue}}"}' or subVar={{parentValue}},x=hello
Output mapping: '{"parentVar": "subResultVar"}' or parentVar=subResultVar
If neither output nor prefix is specified, all sub-workflow variables are copied directly.
Call a remote MCP (Model Context Protocol) server tool via HTTP.
- id: search
type: mcp
url: "https://mcp.example.com/v1"
tool: "web_search"
args: '{"query": "{{searchTerm:json}}"}'
headers: '{"Authorization": "Bearer {{apiKey}}"}'
saveTo: searchResults
saveUiTo: uiData| Property | Required | Template | Description |
|---|---|---|---|
url |
Yes | Yes | MCP server endpoint URL |
tool |
Yes | Yes | Tool name to call |
args |
No | Yes | JSON object with tool arguments |
headers |
No | Yes | JSON object with HTTP headers |
saveTo |
No | No | Variable for result |
saveUiTo |
No | No | Variable for UI resource data (when server returns _meta.ui.resourceUri) |
Uses JSON-RPC 2.0 protocol (tools/call method). Text content parts from the response are joined with newlines.
Sync a Drive file to a Gemini RAG store (File Search).
- id: sync
type: rag-sync
path: "notes/knowledge-base.md"
ragSetting: "myRagStore"
saveTo: syncResult| Property | Required | Template | Description |
|---|---|---|---|
path |
Yes | Yes | File path on Drive |
ragSetting |
Yes | Yes | RAG setting name (from Settings > RAG) |
saveTo |
No | No | Variable for sync result |
Uploads the specified Drive file to the RAG store. Creates the store if it doesn't already exist. The result contains {path, ragSetting, fileId, storeName, mode, syncedAt}.
Use this to prepare files for RAG-powered command nodes (set ragSetting on the command node to the same setting name).
Execute GemiHub file operations (encrypt, publish, rename, etc.) as workflow nodes.
- id: pub
type: gemihub-command
command: publish
path: "notes/readme.md"
saveTo: url| Property | Required | Template | Description |
|---|---|---|---|
command |
Yes | Yes | Command name (see table below) |
path |
Yes | Yes | File path, Drive file ID, or {{variable}} |
text |
No | Yes | Additional text argument (usage depends on command) |
saveTo |
No | No | Variable to store the result |
Available commands:
| Command | text usage |
saveTo result |
|---|---|---|
encrypt |
— | New file name (with .encrypted suffix) |
publish |
— | Public URL |
unpublish |
— | "ok" |
duplicate |
Custom name (optional; default: "name (copy).ext") |
New file name |
convert-to-pdf |
— | PDF file name (saved to temporaries/) |
convert-to-html |
— | HTML file name (saved to temporaries/) |
rename |
New name (required) | New file name |
Path resolution follows the same pattern as drive-read:
- Direct Drive file ID (20+ alphanumeric chars)
- Companion
_fileIdvariable fromdrive-file-picker - Search by file name →
findFileByExactNamefallback
Examples:
# Encrypt a file
- id: enc
type: gemihub-command
command: encrypt
path: "notes/secret.md"
saveTo: encryptedName
# Duplicate with custom name
- id: dup
type: gemihub-command
command: duplicate
path: "templates/report.md"
text: "reports/2026-report.md"
saveTo: newFile
# Rename a file picked by user
- id: pick
type: drive-file-picker
title: "Select file to rename"
savePathTo: filePath
- id: ren
type: gemihub-command
command: rename
path: "{{filePath}}"
text: "{{filePath}}-archived.md"
saveTo: renamedName
# Convert markdown to PDF
- id: pdf
type: gemihub-command
command: convert-to-pdf
path: "notes/report.md"
saveTo: pdfName
# Convert markdown to HTML
- id: html
type: gemihub-command
command: convert-to-html
path: "notes/report.md"
saveTo: htmlNameUse {{variable}} syntax to reference variables:
# Basic
path: "{{folder}}/{{filename}}.md"
# Object/Array access
url: "https://api.example.com?id={{data.id}}"
content: "{{items[0].name}}"
# Dynamic index (for loops)
path: "{{parsed.notes[counter].path}}"Use {{variable:json}} to escape the value for embedding inside a string literal. It properly escapes newlines, quotes, and other special characters.
Important: :json only escapes the content — it does not add surrounding quotes. You must provide the quotes yourself when embedding inside a string.
# Without :json - breaks if content has newlines/quotes
args: '{"text": "{{content}}"}' # ERROR if content has special chars
# With :json - safe for any content (the "..." around it is your string literal)
args: '{"text": "{{content:json}}"}' # OK - properly escapedIn script nodes (JavaScript):
:json substitutes plain text before the code runs, so you must wrap it in quotes when the value should be a JS string:
# ✅ Correct — string literal with escaped content
code: |
var text = "{{userInput:json}}";
var data = JSON.parse("{{jsonStr:json}}");
# ❌ Wrong — missing outer quotes, produces invalid JS
code: |
var text = {{userInput:json}}; # syntax error
JSON.parse({{jsonStr:json}}); # needs a string argumentIf the variable already holds a parsed object/array (e.g. from a previous json node), use {{var:json}} without quotes so it becomes a JS object/array literal:
code: |
var arr = {{parsedArray:json}}; # becomes: var arr = [{"url":"..."}]This is essential when passing file content or user input to mcp, http, or script nodes with JSON bodies.
Use next: end to explicitly terminate the workflow:
- id: save
type: drive-file
path: "output.md"
content: "{{result}}"
next: end # Workflow ends here
- id: branch
type: if
condition: "{{cancel}}"
trueNext: end # End workflow on true branch
falseNext: continuename: Summarize File
nodes:
- id: select
type: drive-file-picker
title: "Select a file to summarize"
extensions: "md,txt"
savePathTo: filePath
- id: read
type: drive-read
path: "{{filePath}}"
saveTo: content
- id: summarize
type: command
prompt: "Summarize this text:\n\n{{content}}"
saveTo: summary
- id: save
type: drive-file
path: "summaries/{{filePath}}"
content: "# Summary\n\n{{summary}}"name: Weather Report
nodes:
- id: city
type: dialog
title: City name
inputTitle: City
saveTo: cityInput
- id: geocode
type: http
url: "https://geocoding-api.open-meteo.com/v1/search?name={{cityInput.input}}&count=1"
method: GET
saveTo: geoResponse
- id: parseGeo
type: json
source: geoResponse
saveTo: geo
- id: weather
type: http
url: "https://api.open-meteo.com/v1/forecast?latitude={{geo.results[0].latitude}}&longitude={{geo.results[0].longitude}}¤t=temperature_2m"
method: GET
saveTo: weatherData
- id: report
type: command
prompt: "Create a weather report:\n{{weatherData}}"
saveTo: summary
- id: save
type: drive-file
path: "weather/{{cityInput.input}}.md"
content: "# Weather: {{cityInput.input}}\n\n{{summary}}"name: Tag Analyzer
nodes:
- id: init
type: variable
name: counter
value: "0"
- id: initReport
type: variable
name: report
value: "# Tag Suggestions\n\n"
- id: list
type: drive-list
folder: "Clippings"
limit: "5"
saveTo: notes
- id: parse
type: json
source: notes
saveTo: parsed
- id: loop
type: while
condition: "{{counter}} < {{parsed.count}}"
trueNext: read
falseNext: finish
- id: read
type: drive-read
path: "{{parsed.notes[counter].name}}"
saveTo: content
- id: analyze
type: command
prompt: "Suggest 3 tags for:\n\n{{content}}"
saveTo: tags
- id: append
type: set
name: report
value: "{{report}}## {{parsed.notes[counter].name}}\n{{tags}}\n\n"
- id: increment
type: set
name: counter
value: "{{counter}} + 1"
next: loop
- id: finish
type: drive-file
path: "reports/tag-suggestions.md"
content: "{{report}}"File: workflows/translate.yaml
name: Translator
nodes:
- id: translate
type: command
prompt: "Translate to {{targetLang}}:\n\n{{text}}"
saveTo: translatedFile: workflows/main.yaml
name: Multi-Language Export
nodes:
- id: input
type: dialog
title: Enter text to translate
inputTitle: Text
multiline: "true"
saveTo: userInput
- id: toJapanese
type: workflow
path: "workflows/translate.yaml"
name: "Translator"
input: '{"text": "{{userInput.input}}", "targetLang": "Japanese"}'
output: '{"japaneseText": "translated"}'
- id: toSpanish
type: workflow
path: "workflows/translate.yaml"
name: "Translator"
input: '{"text": "{{userInput.input}}", "targetLang": "Spanish"}'
output: '{"spanishText": "translated"}'
- id: save
type: drive-file
path: "translations/output.md"
content: |
# Original
{{userInput.input}}
## Japanese
{{japaneseText}}
## Spanish
{{spanishText}}name: RAG Search
nodes:
- id: query
type: mcp
url: "http://localhost:8080"
tool: "query"
args: '{"store_name": "mystore", "question": "How does auth work?", "show_citations": true}'
headers: '{"X-API-Key": "mysecretkey"}'
saveTo: result
- id: show
type: dialog
title: "Search Result"
message: "{{result}}"
markdown: "true"
button1: "OK"