Download →Alfred workflow
Type np
followed by your search term:
np meeting notes
This will search all your NotePlan notes (both regular and calendar notes) for "meeting notes".
Filter your search by note type using prefixes:
np a [query]
- Search all notes (same as np [query]
)np c [query]
- Search only calendar notesnp r [query]
- Search only regular notesExamples:
np a project ideas
np c meeting
np r journal saturday
This workflow:
mdfind
) to search your notes quicklyThe workflow checks for NotePlan data in:
~/Library/Containers/co.noteplan.NotePlan-setapp/Data/Library/Application Support/co.noteplan.NotePlan-setapp/
~/Library/Containers/co.noteplan.NotePlan/Data/Library/Application Support/co.noteplan.NotePlan/
#!/bin/bash
# Parse the input
full_input="$1"
filter_prefix=""
query=""
# Extract the prefix and query
if [[ "$full_input" == "a "* ]]; then
filter_prefix="a"
query="${full_input:2}"
elif [[ "$full_input" == "c "* ]]; then
filter_prefix="c"
query="${full_input:2}"
elif [[ "$full_input" == "r "* ]]; then
filter_prefix="r"
query="${full_input:2}"
else
# No prefix, search all
query="$full_input"
fi
# Define both possible NotePlan directories
setapp_notes_dir=~/Library/Containers/co.noteplan.NotePlan-setapp/Data/Library/Application\ Support/co.noteplan.NotePlan-setapp/Notes/
setapp_calendar_dir=~/Library/Containers/co.noteplan.NotePlan-setapp/Data/Library/Application\ Support/co.noteplan.NotePlan-setapp/Calendar/
regular_notes_dir=~/Library/Containers/co.noteplan.NotePlan/Data/Library/Application\ Support/co.noteplan.NotePlan/Notes/
regular_calendar_dir=~/Library/Containers/co.noteplan.NotePlan/Data/Library/Application\ Support/co.noteplan.NotePlan/Calendar/
# Check which version exists and set the appropriate directories
if [ -d "$setapp_notes_dir" ]; then
notes_dir="$setapp_notes_dir"
calendar_dir="$setapp_calendar_dir"
app_name="NotePlan.app"
elif [ -d "$regular_notes_dir" ]; then
notes_dir="$regular_notes_dir"
calendar_dir="$regular_calendar_dir"
app_name="NotePlan.app"
else
# No valid NotePlan directories found
echo '{"items":[{"uid":"error","title":"NotePlan directories not found","subtitle":"Please check your NotePlan installation","valid":false}]}'
exit 0
fi
# Start Alfred JSON output
echo '{"items":['
# Use mdfind for searching based on the filter
if [ "$filter_prefix" = "c" ]; then
# Calendar notes only
files=$(mdfind -onlyin "$calendar_dir" "$query" | head -15)
elif [ "$filter_prefix" = "r" ]; then
# Regular notes only
files=$(mdfind -onlyin "$notes_dir" "$query" | grep -v "@Archive" | grep -v "@Templates" | grep -v "@Theme" | grep -v "@Trash" | head -15)
else
# All notes (default)
files=$(mdfind -onlyin "$notes_dir" -onlyin "$calendar_dir" "$query" | grep -v "@Archive" | grep -v "@Templates" | grep -v "@Theme" | grep -v "@Trash" | head -15)
fi
# Process each file
first=true
while IFS= read -r file; do
# Skip empty lines
[ -z "$file" ] && continue
# Add comma for all but first item
if [ "$first" = true ]; then
first=false
else
echo ','
fi
# Get filename without extension for fallback title
filename=$(basename "$file")
fallback_title="${filename%.*}"
# Extract title from frontmatter if available
frontmatter_title=$(grep -m 1 "title:" "$file" | sed 's/title: *//' | tr -d '"' | tr -d "'")
# Use frontmatter title if available, otherwise use filename
if [ -n "$frontmatter_title" ]; then
title="$frontmatter_title"
else
title="$fallback_title"
fi
# Get note_type from frontmatter if available
note_type=$(grep -m 1 "type:" "$file" | sed 's/type: *//' | tr -d '"' | tr -d "'")
# Get modification date for the file
mod_date=$(stat -f "%Sm" -t "%Y-%m-%d" "$file")
# Get note type (regular note or calendar note)
if [[ "$file" == *"/Calendar/"* ]]; then
base_type="📅 Calendar Note"
else
base_type="📝 Note"
fi
# Build subtitle with metadata
if [ -n "$note_type" ]; then
subtitle="${base_type} | Type: ${note_type} | Modified: ${mod_date}"
else
subtitle="${base_type} | Modified: ${mod_date}"
fi
# Create Alfred item with proper JSON escaping
title_escaped=$(echo "$title" | sed 's/"/\\"/g')
subtitle_escaped=$(echo "$subtitle" | sed 's/"/\\"/g')
file_escaped=$(echo "$file" | sed 's/"/\\"/g')
cat << EOF
{
"uid": "np-$(echo "$file" | md5)",
"title": "${title_escaped}",
"subtitle": "${subtitle_escaped}",
"arg": "${file_escaped}",
"mods": {
"alt": {
"arg": "copy:${file_escaped}",
"subtitle": "Copy note content to clipboard"
},
"cmd": {
"arg": "reveal:${file_escaped}",
"subtitle": "Reveal in Finder"
}
}
}
EOF
done <<< "$files"
# If no results were found, provide a fallback item
if [ "$first" = true ]; then
# Customize the message based on the filter
if [ "$filter_prefix" = "c" ]; then
filter_message="No matching calendar notes found"
elif [ "$filter_prefix" = "r" ]; then
filter_message="No matching regular notes found"
else
filter_message="No matching notes found"
fi
echo '{
"uid": "no-results",
"title": "'"$filter_message"'",
"subtitle": "Try a different search term",
"valid": false
}'
fi
# End JSON output
echo ']}'
#!/bin/bash
input="$1"
# Handle different action types
if [[ "$input" == copy:* ]]; then
# Copy note content to clipboard
file="${input#copy:}"
cat "$file" | pbcopy
echo "Note content copied to clipboard"
elif [[ "$input" == reveal:* ]]; then
# Reveal in Finder
file="${input#reveal:}"
open -R "$file"
else
# Extract the actual title from the frontmatter
title=$(grep -m 1 "title:" "$input" | sed 's/title: *//' | tr -d '"' | tr -d "'")
# If no title in frontmatter, use filename as backup
if [ -z "$title" ]; then
filename=$(basename "$input")
title="${filename%.*}"
fi
# URL encode the title
encoded_title=$(echo "$title" | sed -e 's/ /%20/g' -e 's/&/%26/g' -e 's/#/%23/g' -e 's/\?/%3F/g' -e 's/=/%3D/g' -e 's/\+/%2B/g')
# Use noteTitle parameter to open the note in NotePlan
open "noteplan://x-callback-url/openNote?noteTitle=$encoded_title"
# If that doesn't work, try directly opening the file as fallback
sleep 0.5
open -a "NotePlan.app" "$input"
fi
Create a Script Filter:
np
/bin/bash
Create a Run Script Action:
/bin/bash
Connect the Script Filter to the Run Script action.
You can modify the script to: