Actions
Actions specify what changes to make to your notes' YAML front matter.
Action Syntax
SCALAR operations (no FOR prefix):
SET field "value" # Set field value
DELETE field # Delete field
RENAME old TO new # Rename field
INCREMENT field 5 # Increment field
DECREMENT field 5 # Decrement fieldCOLLECTION operations (FOR prefix required):
FOR array APPEND "item" # Append to array
FOR array WHERE <condition> SET field "value" # Conditional update
FOR array SORT BY field # Sort array
FOR object MERGE {data} # Merge objectKey insight: Scalar operations work on single values (no FOR), collection operations work on arrays/objects (FOR required).
Examples:
SET status "active"
DELETE old_field
FOR tags APPEND "reviewed"
FOR tasks WHERE status = "pending" SET status "active"Core Action Operations
SET - Create or Update Fields
What it does: Sets a field value, creating it if missing or updating it if it exists.
Unique power: Guarantees a field has a specific value and type, regardless of its current state. Can normalize heterogeneous data (e.g., convert string → array).
Syntax:
SET <field> <value>Example that can't be done any other way:
Ensure tags is always an array with at least one value, even if it's currently a string or missing:
SET tags ["unprocessed"]Before (various states):
# Case 1: Field missing
title: My Note
# Case 2: Field is string
title: My Note
tags: old-string-value
# Case 3: Field is already array
title: My Note
tags: [existing, values]After (normalized):
# All cases result in same structure
title: My Note
tags: [unprocessed]Other examples:
SET status "active"
SET priority 5
SET metadata {author: "John", version: 2}FOR ... APPEND - Append to Lists (De-duplicated)
What it does: Adds an item to an array only if it's not already present.
Unique power: Build lists incrementally across multiple rules without creating duplicates. Perfect for workflows where multiple conditions might fire.
Syntax:
FOR <array> APPEND <value>Example that can't be done any other way:
Mark a note as reviewed without creating duplicate tags, even if the rule runs multiple times:
FOR tags APPEND "reviewed"Before:
---
title: Project Note
tags: [project, active]
---After (first run):
---
title: Project Note
tags: [project, active, reviewed]
---After (second run - no duplicate):
---
title: Project Note
tags: [project, active, reviewed] # ← Still only one "reviewed"
---Why you need APPEND: SET tags would overwrite existing tags. FOR tags INSERT AT -1 would create duplicates. Only APPEND provides idempotent list building.
FOR ... REMOVE - Delete from Lists (Conditional)
What it does: Removes items from an array that match a condition.
Unique power: Selectively delete items from lists based on their values while preserving other items.
Syntax:
FOR <array> WHERE <condition> REMOVEExample that can't be done any other way:
Remove "draft" tag while keeping all other tags intact:
FOR tags WHERE $ = "draft" REMOVEBefore:
---
title: Published Article
tags: [draft, project, active, important]
---After:
---
title: Published Article
tags: [project, active, important] # ← Only "draft" removed
---Note: The $ symbol represents the current item in the array.
FOR ... REMOVE_ALL - Delete All Occurrences
What it does: Removes all instances of a specific value from an array.
Unique power: Clean up arrays by removing every occurrence of a value, regardless of position.
Syntax:
FOR <array> REMOVE_ALL <value>Example:
FOR tags REMOVE_ALL "draft"Before:
tags: [draft, project, draft, active, draft]After:
tags: [project, active]FOR ... REMOVE_ANY - Delete Multiple Values
What it does: Removes all instances of any value in a provided list.
Unique power: Clean up multiple unwanted values in a single operation.
Syntax:
FOR <array> REMOVE_ANY [<value1>, <value2>, ...]Example that can't be done any other way:
Clean up temporary tags in one operation:
FOR tags REMOVE_ANY ["draft", "wip", "temp"]Before:
tags: [project, draft, active, wip, important, temp]After:
tags: [project, active, important]Why you need REMOVE_ANY: REMOVE_ALL requires multiple rules for multiple values. Only REMOVE_ANY removes multiple values at once.
DELETE - Remove Entire Field
What it does: Removes a field completely from the front matter.
Unique power: Structural cleanup that doesn't care about the field's value or type. Perfect for removing obsolete fields.
Syntax:
DELETE <field>Example that can't be done any other way:
Clean up a deprecated field regardless of its value:
DELETE deprecated_fieldBefore:
---
title: My Note
status: active
deprecated_field: {complex: "object", with: ["nested", "data"]}
old_version: 1.0
---After:
---
title: My Note
status: active
old_version: 1.0
---Why you need DELETE: REMOVE only works on array values. SET updates values, doesn't remove fields. Only DELETE performs structural cleanup.
RENAME - Rename Field Preserving Values
What it does: Renames a field to a new name while preserving each document's unique value.
Unique power: This is an atomic operation that cannot be replicated with other operations. You cannot do this with DELETE + SET because each document has different values.
Syntax:
RENAME <old_field> TO <new_field>Example that can't be done any other way:
Standardize "author" to "creator" across your entire vault:
RENAME author TO creatorBefore (3 different documents):
# Doc 1: author: "Alice"
# Doc 2: author: "Bob"
# Doc 3: author: "Charlie"After:
# Doc 1: creator: "Alice" ✓ Value preserved
# Doc 2: creator: "Bob" ✓ Value preserved
# Doc 3: creator: "Charlie" ✓ Value preservedWhy DELETE + SET won't work:
❌ DELETE author, SET creator "Alice"
Problem: Sets ALL docs to "Alice", loses "Bob" and "Charlie"
❌ DELETE author, SET creator ???
Problem: No way to reference the old valueOther examples:
RENAME due_date TO deadline
RENAME tags TO categories
RENAME project_id TO idWhy you need RENAME: It's the only way to change field names while preserving unique values across all documents. Essential for vault-wide standardization.
REPLACE - Pattern Substitution
What it does: Find and replace patterns in string values using regular expressions.
Unique power: In-place transformation of string content using pattern matching. Essential for data cleanup and normalization.
Syntax:
REPLACE <field> /<regex>/ <replacement>Example that can't be done any other way:
Strip title prefixes like "Dr. " or "Dr " from author names:
REPLACE author /^Dr\.?\s+// ""Before:
---
title: Medical Research
author: Dr. Jane Smith
co_author: Dr Jane Doe
reviewer: Professor Bob Wilson
---After:
---
title: Medical Research
author: Jane Smith # ← "Dr. " removed
co_author: Jane Doe # ← "Dr " removed
reviewer: Professor Bob Wilson # ← Unchanged (no "Dr")
---More examples:
REPLACE title /\s+/ "_" # Spaces → underscores
REPLACE content /TODO: // "✓ " # Mark TODOs complete
REPLACE filename /\.draft$// "" # Remove .draft extensionAdvanced Regex Patterns
Regex flags:
/pattern/i- Case-insensitive matching/pattern/g- Global replace (all occurrences)/pattern/ig- Both case-insensitive and global
Case-Insensitive Replacement:
# Strip any case variation of "draft"
REPLACE title /draft/i ""
# "My Draft" → "My "
# "My DRAFT" → "My "
# "My draft" → "My "
# Remove title regardless of case
REPLACE author /dr\.?\s+/i ""
# "Dr. Smith" → "Smith"
# "DR SMITH" → "SMITH"
# "dr smith" → "smith"Capture Groups & Substitution:
# Extract year from filename
REPLACE title /^.*(\d{4}).*$/ "$1"
# "report-2024-final.md" → "2024"
# Reorder date format (YYYY-MM-DD → MM/DD/YYYY)
REPLACE date /(\d{4})-(\d{2})-(\d{2})/ "$2/$3/$1"
# "2025-01-15" → "01/15/2025"
# Swap first and last name
REPLACE author /^(\w+)\s+(\w+)$/ "$2, $1"
# "John Smith" → "Smith, John"
# Extract domain from email
REPLACE contact /@(.+)$/ "$1"
# "user@example.com" → "example.com"
# Format phone number
REPLACE phone /(\d{3})(\d{3})(\d{4})/ "($1) $2-$3"
# "5551234567" → "(555) 123-4567"Whitespace Normalization:
# Collapse multiple spaces to single space
REPLACE content /\s+/g " "
# "Too many spaces" → "Too many spaces"
# Remove leading and trailing whitespace
REPLACE title /^\s+|\s+$/g ""
# " My Title " → "My Title"
# Remove all whitespace
REPLACE code /\s+/g ""
# "function name ( )" → "functionname()"
# Normalize line breaks (convert to single spaces)
REPLACE description /[\r\n]+/g " "Character Removal & Sanitization:
# Remove special characters (keep alphanumeric and spaces)
REPLACE filename /[^a-zA-Z0-9\s]/g ""
# "My-File_Name#2!" → "My File Name 2"
# Create URL-friendly slug
REPLACE slug /[^a-z0-9]+/ig "-"
# "My Article Title!" → "My-Article-Title-"
# Remove leading/trailing dashes
REPLACE slug /^-+|-+$/g ""
# "-my-slug-" → "my-slug"
# Chain operations in single action:
REPLACE slug /[^a-z0-9]+/ig "-", REPLACE slug /^-+|-+$/g ""
# "My Article!" → "My-Article"Complex Pattern Matching:
# Extract first word only
REPLACE title /^(\w+).*$/ "$1"
# "Getting Started with YAML" → "Getting"
# Remove HTML tags
REPLACE content /<[^>]+>/g ""
# "Text <b>bold</b> more" → "Text bold more"
# Extract initials
REPLACE author /(\w)\w*\s+(\w)\w*/ "$1.$2."
# "John Smith" → "J.S."
# Remove duplicate words
REPLACE content /\b(\w+)\s+\1\b/g "$1"
# "the the quick brown brown fox" → "the quick brown fox"
# Convert markdown links to plain text
REPLACE content /\[([^\]]+)\]\([^)]+\)/g "$1"
# "[Click here](http://example.com)" → "Click here"Real-World Scenarios:
# Normalize author names (remove titles, fix spacing)
REPLACE author /^\s+|\s+$/g "",
REPLACE author /(Dr|Prof|Mr|Mrs|Ms)\.?\s+/i "",
REPLACE author /\s+/g " "
# " Dr. Jane Smith " → "Jane Smith"
# Clean up imported data
REPLACE description /[\r\n\t]+/g " ",
REPLACE description /\s+/g " ",
REPLACE description /^\s+|\s+$/g ""
# Removes tabs, line breaks, excess spaces, trims ends
# Convert file path to relative
REPLACE filepath /^.*\/((?:[^\/]+\/){2}[^\/]+)$/ "$1"
# "/Users/name/Documents/vault/folder/file.md" → "vault/folder/file.md"
# Sanitize for safe filenames
REPLACE filename /[<>:"|?*\/\\]/g "-",
REPLACE filename /\s+/g "_",
REPLACE filename /_{2,}/g "_"
# "My File: Version 2*" → "My_File-_Version_2-"Use cases:
- Data cleanup: Remove prefixes, suffixes, unwanted characters
- Format conversion: Dates, phone numbers, names
- Text normalization: Whitespace, case, special characters
- Content extraction: Capture specific parts of strings
- URL/filename sanitization: Create safe, readable slugs
Why you need REPLACE: SET would require knowing the exact current value. Manual string operations aren't possible. Only REPLACE provides regex-based transformation.
INCREMENT - Numeric Operations
What it does: Adds to numeric fields. Creates field with value 0 if missing.
Unique power: Atomic numeric updates for counters, scores, and quantities. Handles missing fields automatically.
Syntax:
INCREMENT <field> <amount>Example that can't be done any other way:
Track view count across multiple rule executions:
INCREMENT view_count 1Before:
---
title: Popular Article
views: 42
---After (first increment):
---
title: Popular Article
views: 43
---After (second increment):
---
title: Popular Article
views: 44
---If field is missing:
---
title: New Article
---
# Running: INCREMENT views 1
---
title: New Article
views: 1 # ← Created with value 1 (0 + 1)
---Other examples:
DECREMENT priority 1 # Decrement
INCREMENT score 10 # Add 10 points
INCREMENT completion_rate 5 # Increase by 5%Why you need INCREMENT: SET requires reading current value first. String operations don't work on numbers. Only INCREMENT provides true numeric operations.
FOR ... INSERT - Insert at Position
What it does: Insert value at specific position in arrays or strings (concatenation).
Unique power: Single operation handles prepending, appending, and inserting at any position using special indices.
Syntax:
FOR <field> INSERT <value> AT <index>Special indices:
0- Insert at start (prepend)-1- Insert at end (append)- Positive numbers - Insert at that position
- Negative numbers - Count from end
Example 1: Build a processing log (append)
FOR notes INSERT "\n\n---\nProcessed on 2025-12-05" AT -1Before:
---
title: Research Note
notes: "Initial draft completed.\nReady for review."
---After:
---
title: Research Note
notes: "Initial draft completed.\nReady for review.\n\n---\nProcessed on 2025-12-05"
---Example 2: Mark drafts with prefix (prepend)
FOR title INSERT "DRAFT: " AT 0Before:
---
title: Important Article
status: draft
---After:
---
title: DRAFT: Important Article
status: draft
---Pro tip: Combine with conditions to avoid duplicates:
Condition: status = "draft" AND NOT title contains "DRAFT: "
Action: FOR title INSERT "DRAFT: " AT 0Other examples:
FOR title INSERT " (UPDATED)" AT -1 # Append suffix
FOR author INSERT "Dr. " AT 0 # Prepend prefix
FOR tags INSERT "urgent" AT 0 # Array: insert at start
FOR tags INSERT "archived" AT -1 # Array: insert at end
FOR history INSERT "checkpoint" AT 5 # Array: insert at position 5Why you need INSERT: Single operation replaces APPEND/PREPEND/INSERT_AT with consistent, intuitive syntax using familiar negative indices.
Array Operations
FOR ... DEDUPLICATE - Remove Duplicates
Purpose: Remove duplicate values from array
Syntax:
FOR <array> DEDUPLICATEExamples:
FOR tags DEDUPLICATE
FOR categories DEDUPLICATEFOR ... SORT - Sort Array
Purpose: Sort array in ascending or descending order
Syntax:
FOR <array> SORT [<order>]
FOR <array> SORT BY <field> [<order>]Orders: ASC (ascending), DESC (descending). Default is ASC.
Examples:
FOR tags SORT ASC
FOR priorities SORT DESC
FOR tasks SORT BY priority DESC
FOR entries SORT BY date ASCFOR ... MOVE - Move Item by Index
Purpose: Move item from one index to another
Syntax:
FOR <array> MOVE FROM <index> TO <index>Examples:
FOR tags MOVE FROM 0 TO 5
FOR history MOVE FROM -1 TO 0Array of Objects Operations
Operations for arrays containing structured objects:
tasks:
- name: "Task 1"
status: "pending"
priority: 8
- name: "Task 2"
status: "done"
priority: 5These operations work inside arrays, targeting specific items based on their properties.
FOR ... WHERE ... SET - Update Items by Condition
Purpose: Update fields in objects matching condition
Syntax:
FOR <array> WHERE <condition> SET <field> <value> [, <field> <value>]Unique power: Updates specific objects within arrays based on their properties. File-level operations can't target individual array items.
Example - Task reassignment:
Before:
tasks:
- name: "Design mockups"
assignee: "Alice"
- name: "Write tests"
assignee: "Bob"
- name: "Deploy"
assignee: "Bob"Action:
FOR tasks WHERE assignee = "Bob" SET assignee "Alice"After:
tasks:
- name: "Design mockups"
assignee: "Alice" # ← Unchanged
- name: "Write tests"
assignee: "Alice" # ← Changed
- name: "Deploy"
assignee: "Alice" # ← ChangedMore examples:
FOR tasks WHERE status = "pending" SET status "active", started "{{today}}"
FOR readingList WHERE currentPage = pages SET status "finished", completedDate "{{today}}"
FOR meetings WHERE status = "scheduled" AND attendees HAS "Bob" SET status "cancelled"FOR ... WHERE ... MOVE - Move Items by Condition
Purpose: Move items matching condition to start, end, or relative position
Syntax:
FOR <array> WHERE <condition> MOVE TO <position>Positions: START, END, AFTER <condition>, BEFORE <condition>
Unique power: Reorders items within an array based on their properties without full sorting. Preserves relative order of non-matching items.
Example - Prioritize unwatched movies:
Before:
watchlist:
- title: "Inception"
watched: true
- title: "Interstellar"
watched: false
- title: "The Matrix"
watched: true
- title: "Arrival"
watched: falseAction:
FOR watchlist WHERE watched = false MOVE TO STARTAfter:
watchlist:
- title: "Interstellar" # ← Moved to top
watched: false
- title: "Arrival" # ← Moved to top
watched: false
- title: "Inception" # ← Stays below
watched: true
- title: "The Matrix" # ← Stays below
watched: trueMore examples:
FOR tasks WHERE priority > 7 MOVE TO START
FOR items WHERE status = "done" MOVE TO ENDRelative Positioning with AFTER/BEFORE
Move items to specific positions relative to other items in the array.
MOVE TO AFTER - Insert urgent task after planning:
Before:
tasks:
- name: Planning meeting
priority: normal
- name: Implementation
priority: normal
- name: URGENT BUG FIX
priority: critical
- name: Testing
priority: lowAction:
FOR tasks WHERE priority = "critical" MOVE TO AFTER name = "Planning meeting"After:
tasks:
- name: Planning meeting
priority: normal
- name: URGENT BUG FIX # ← Moved here (after Planning)
priority: critical
- name: Implementation # ← Pushed down
priority: normal
- name: Testing
priority: lowMOVE TO BEFORE - Insert review before completion:
Before:
workflow:
- step: Design
status: done
- step: Implementation
status: done
- step: Deployment
status: pendingAction:
FOR workflow WHERE step = "Review" OR step = "Testing" MOVE TO BEFORE step = "Deployment"If the "Review" step exists, it moves before "Deployment". If it doesn't exist, the action has no effect (safe to run).
Use cases:
- Insert urgent items after planning but before execution
- Group related items together without full sort
- Maintain manual ordering with selective repositioning
- Position new items relative to existing anchors
Object Operations
FOR ... MERGE - Deep Merge Objects
Purpose: Deep merge objects (preserves existing nested fields)
Syntax:
FOR <object> MERGE {<key>: <value>, ...}Examples:
FOR metadata MERGE {author: "John", version: 2}
FOR config MERGE {theme: "dark", showIcons: true}Nested objects are recursively merged. Arrays and primitives are replaced.
FOR ... MERGE_OVERWRITE - Shallow Merge Objects
Purpose: Shallow merge objects (overwrites all fields)
Syntax:
FOR <object> MERGE_OVERWRITE {<key>: <value>, ...}Examples:
FOR metadata MERGE_OVERWRITE {author: "Jane", version: 3}
FOR settings MERGE_OVERWRITE {mode: "advanced"}All fields from the new object replace existing fields at the top level only.
Special Values
Template Variables
Template variables are evaluated at runtime and inserted into action values:
- Current timestamp (ISO 8601 format)- Today's date (YYYY-MM-DD)
SET created_date "{{now}}"
SET updated "{{today}}"
SET reviewed_on "{{today}}"Data Types
Supported value types:
- Strings:
"text"(use quotes) - Numbers:
42,3.14 - Booleans:
true,false - Null:
null - Arrays:
["item1", "item2"] - Objects:
{key: "value", count: 5} - Dates:
"2025-01-01"
Multiple Actions
Execute multiple actions in one rule (comma-separated):
SET status "completed", SET completed_date "{{now}}", FOR tags APPEND "done"Actions execute left-to-right in order.
Troubleshooting
Common issues and how to handle them.
Field Doesn't Exist
Problem: Action tries to modify non-existent field
Behavior:
SET field value- Creates the field ✅FOR field APPEND "x"- Creates array["x"]✅INCREMENT field 1- Error (can't increment missing field) ❌REPLACE field /old/new- Error (can't replace in missing field) ❌
Solution: Use conditions to check existence first:
Condition: HAS views
Action: INCREMENT views 1Or create field with SET first:
Action: SET views 0, INCREMENT views 1Type Mismatch Errors
Problem: Operation expects different type
Examples:
# views is string "5"
INCREMENT views 1
→ Error: Cannot increment string
# tags is string "old"
FOR tags APPEND "new"
→ Converts to array: ["old", "new"] ✅
# config is array
FOR config MERGE {key: "value"}
→ Error: Cannot merge with arraySolution: Use type checking conditions:
Condition: views :number
Action: INCREMENT views 1Or normalize types first:
Condition: tags !:array
Action: SET tags ["{{fm:tags}}"] # Convert to arrayEmpty vs Null vs Missing
Understanding the differences:
| State | field exists | field empty | field :null | FOR field APPEND "x" |
|---|---|---|---|---|
| Not present | false | false | false | Creates ["x"] |
field: null | true | false | true | Replaces with ["x"] |
field: [] | true | true | false | Results in ["x"] |
field: "" | true | true | false | Error (can't append to string) |
Best practices:
# Check if field has content
Condition: tags exists AND tags !empty
# Check for null specifically
Condition: deletedAt :null
# Safe append (creates if missing)
Action: FOR tags APPEND "new"No Matches in WHERE
Problem: WHERE condition finds no items
Behavior: Operation succeeds but does nothing (not an error)
Example:
FOR tasks WHERE status = "archived" REMOVE
# No tasks are archived → No change, no error ✅Checking for matches:
Condition: ANY tasks WHERE status = "archived"
Action: FOR tasks WHERE status = "archived" REMOVEArray Index Out of Bounds
Problem: Accessing non-existent index
Behavior:
# tags has 3 items
tasks[100].status = "done"
→ Condition is false (index doesn't exist)
FOR tags INSERT "x" AT 50
→ Inserts at end (safe fallback)
FOR tags INSERT "x" AT -50
→ Inserts at start (safe fallback)Tip: Negative indexing is safer for "last item" access:
# Better (works regardless of array length)
tasks[-1].status = "done"
# Worse (requires knowing exact length)
tasks[4].status = "done"Deep Path Missing
Problem: Intermediate path doesn't exist
Behavior:
# config.server doesn't exist
config.server.database.host = "localhost"
→ Condition is false (path broken at config.server)Solution: Check existence step by step:
Condition: HAS config AND HAS config.server
Action: SET config.server.database.host "localhost"Or create paths explicitly:
Action: SET config.server {database: {host: "localhost"}}Operations That Won't Fail
Always safe (return true/false, never error):
HAS fieldfield existsfield emptyfield :typeANY array WHERE ...ALL array WHERE ...
May fail (require correct types):
INCREMENT/DECREMENT- needs numberREPLACE- needs stringFOR ... MERGE- needs object
Examples
See Examples for real-world usage patterns.