A JavaScript library for Scriptable (iOS) to interact with Obsidian vaults, manage notes, and integrate with iOS Calendar.
- [[# Utility Classes]]
- [[# DateFormatter]]
- [[# Tags]]
- [[# File Management]]
- [[# ObsidianFile]]
- [[# ObsidianNote]]
- [[# Note Components]]
- [[# FrontMatter]]
- [[# Section]]
- [[# Sections]]
- [[# Task Management]]
- [[# ObsidianTask]]
- [[# Calendar Integration]]
- [[# Calendar]]
- [[# CalendarEvent]]
const ObsidianJS = importModule('ObsidianJS');Static utility class for consistent date and time formatting.
Parse a date string or return Date object as-is.
- input:
Date | String | null - Returns:
Date | null
Format date as ISO string.
- date:
Date | String - Returns:
String- Format:2025-10-05
Format time in 12-hour format.
- date:
Date | String - Returns:
String- Format:09:00 AM
Format time in 24-hour format.
- date:
Date | String - Returns:
String- Format:09:00
Format date for use in filenames.
- date:
Date | String - Returns:
String- Format:2025-10-05
Format date for display.
- date:
Date | String - Returns:
String- Format:October 5, 2025
Get day of week name.
- date:
Date | String - Returns:
String- Format:Monday
Format date in short format.
- date:
Date | String - Returns:
String- Format:Oct 5, 2025
Get today's date at midnight.
- Returns:
Date
Get start of day (00:00:00) for any date.
- date:
Date | String - Returns:
Date
Get end of day (23:59:59) for any date.
- date:
Date | String - Returns:
Date
const now = new Date();
DateFormatter.toISO(now); // "2025-10-05"
DateFormatter.toTime12Hour(now); // "2:30 PM"
DateFormatter.toDisplayDate(now); // "October 5, 2025"
// Also accepts strings
DateFormatter.toISO('2025-10-05'); // "2025-10-05"Centralized tag handling for both FrontMatter YAML and inline markdown tags.
new Tags(tags)- tags:
Array<String> | String- Array of tags or comma/space-separated string
Convert to array (for FrontMatter YAML).
- Returns:
Array<String>- Tags without#prefix
Convert to inline format with hashes (for Task markdown).
- separator:
String- Separator between tags - Returns:
String- Format:#work #urgent
Add a tag if it doesn't exist.
- tag:
String- Tag to add (with or without#)
Remove a tag.
- tag:
String- Tag to remove
Check if tag exists.
- tag:
String- Tag to check - Returns:
Boolean
Check if no tags exist.
- Returns:
Boolean
Number of tags.
- Type:
Number(read-only)
// From string (iOS Shortcuts friendly)
const tags = new ObsidianJS.Tags('work, urgent, home');
// From array
const tags2 = new ObsidianJS.Tags(['work', 'urgent']);
// Manipulate
tags.add('priority');
tags.remove('home');
tags.has('work'); // true
// Output
tags.toArray(); // ['work', 'urgent', 'priority']
tags.toInlineString(); // '#work #urgent #priority'Base class for file I/O operations with Obsidian vault.
new ObsidianFile({ bookmark, folder, filename })- bookmark:
String- Scriptable bookmark name (default:"obsidian_vault") - folder:
String- Folder path within vault (default:"") - filename:
String- File name (default:"")
newline:String-"\n"nullstring:String-""
Check if file exists.
- Returns:
Boolean
Read file contents.
- Returns:
String- File contents or empty string if not exists
Write content to file.
- content:
String- Content to write
Append content to file.
- content:
String- Content to append
Get file contents as array of lines.
- Returns:
Array<String>
Save array of lines to file.
- lines:
Array<String>
const file = new ObsidianJS.File({
folder: 'Daily Notes',
filename: '2025-10-05.md'
});
if (file.exists()) {
const content = file.read();
file.append('\nNew line');
}Extended file class for managing Obsidian notes with frontmatter and sections.
new ObsidianNote({ bookmark, folder, filename })Same parameters as ObsidianFile.
Get frontmatter object (auto-parses on first access).
- Type:
FrontMatter(read-only)
Get sections collection (auto-parses on first access).
- Type:
Sections(read-only)
Check if note has unsaved changes.
- Type:
Boolean(read-only)
Set a single frontmatter property.
- key:
String - value:
Any - Returns:
this(chainable)
Set multiple frontmatter properties.
- dataObject:
Object- Key-value pairs - Returns:
this(chainable)
Save all changes to file.
Get all section headers as flat list.
- Returns:
Array<Object>- Format:[{ text, level, section }]
Get all content without frontmatter.
- Returns:
String
const note = new ObsidianJS.Note({
folder: 'Daily Notes',
filename: '2025-10-05.md'
});
// Set frontmatter
note.setFrontMatter({
created: '2025-10-05',
tags: 'daily-notes, work'
});
// Work with sections
const section = note.sections.find('Tasks');
section.append('- [ ] New task');
// Save changes
note.save();Handles YAML frontmatter parsing and generation.
new FrontMatter(yamlString)- yamlString:
String- YAML content (without---delimiters)
Get frontmatter property value.
- key:
String - Returns:
Any
Set frontmatter property. Automatically normalizes tags.
- key:
String - value:
Any
Remove frontmatter property.
- key:
String
Convert to YAML string with delimiters.
- Returns:
String
Check if frontmatter has any properties.
- Returns:
Boolean
const fm = note.frontMatter;
fm.set('title', 'My Note');
fm.set('tags', 'work, urgent'); // Normalized to array
fm.get('title'); // "My Note"
fm.remove('draft');Represents a single section of a note (header + content).
new Section({ header, content, level, parent })- header:
String- Header text (without#) - content:
String- Section content - level:
Number- Header level (1-6 for H1-H6) - parent:
ObsidianNote- Parent note (for dirty tracking)
Get formatted header with # symbols.
- Type:
String(read-only)
Append text to section content.
- text:
String
Prepend text to section content.
- text:
String
Check if section has no content.
- Returns:
Boolean
Convert to markdown string.
- Returns:
String
Get all subsections (higher level numbers).
- allSections:
Array<Section>- All sections in note - Returns:
Array<Section>
const section = note.sections.find('Introduction');
section.append('More content');
section.prepend('Opening line');
console.log(section.isEmpty()); // falseCollection class for managing multiple sections within a note.
Find first section with matching header.
- headerText:
String- Header text to search (case-insensitive) - Returns:
Section | undefined
Find section by hierarchical path.
- pathString:
String- Format:"Parent > Child > Section" - delimiter:
String- Path separator - Returns:
Section | null
Find all sections with matching header.
- headerText:
String - Returns:
Array<Section>
Find all sections at specific level.
- level:
Number- Header level (1-6) - Returns:
Array<Section>
Add a new section.
- headerText:
String - content:
String(optional) - level:
Number(default: 1) - insertAfter:
String- Header to insert after (optional) - Returns:
Section- The created section
Remove a section.
- headerOrSection:
String | Section- Header text or Section object - Returns:
Boolean- Success status
Get sections as array.
- Returns:
Array<Section>
Get all headers with metadata.
- Returns:
Array<Object>- Format:[{ text, level, section }]
Number of sections.
- Type:
Number(read-only)
// Find sections
const intro = note.sections.find('Introduction');
const nested = note.sections.findByPath('2025-10-05 > Attendees');
const allH2 = note.sections.findByLevel(2);
// Add section
note.sections.add('Conclusion', 'Final thoughts', 1);
// Remove section
const section = note.sections.findByPath('2025-10-05 > Notes');
note.sections.remove(section);
// Iterate
for (const section of note.sections) {
console.log(section.header);
}Represents a task in Obsidian Tasks plugin format.
new ObsidianTask({
description,
completed,
dueDate,
scheduledDate,
startDate,
priority,
tags
})- description:
String- Task description - completed:
Boolean- Completion status (default: false) - dueDate:
Date | String | null- Due date - scheduledDate:
Date | String | null- Scheduled date - startDate:
Date | String | null- Start date - priority:
'high' | 'medium' | 'low' | null- Priority level - tags:
Array<String> | String- Tags (accepts arrays or comma/space-separated strings)
- tags:
Tags- Tags object
Convert task to Obsidian Tasks plugin markdown format.
- Returns:
String
Format: - [ ] Description 📅 YYYY-MM-DD ⏰ YYYY-MM-DD 🛫 YYYY-MM-DD ⏫ #tag1 #tag2
// iOS Shortcuts friendly - pass strings
const task = new ObsidianJS.Task({
description: 'Call plumber',
dueDate: '2025-10-10',
priority: 'high',
tags: 'home, urgent'
});
console.log(task.toMarkdown());
// - [ ] Call plumber 📅 2025-10-10 ⏫ #home #urgent
// Script friendly - pass objects/arrays
const task2 = new ObsidianJS.Task({
description: 'Review code',
dueDate: new Date('2025-10-10'),
tags: ['work', 'code-review']
});
// Manipulate tags
task2.tags.add('urgent');
task2.tags.remove('code-review');Wrapper around iOS Calendar API for fetching events.
new Calendar(calendarNames)- calendarNames:
Array<String>- Calendar names to include. Empty = all calendars
Get all events for a specific date.
- date:
Date - Returns:
Array<CalendarEvent>
Get all events within date range.
- startDate:
Date - endDate:
Date - Returns:
Array<CalendarEvent>
Get specific event by identifier.
- id:
String- Event identifier - Returns:
CalendarEvent | null
Get all events for today.
- Returns:
Array<CalendarEvent>
Get events matching predicate within date range.
- startDate:
Date - endDate:
Date - predicateFn:
Function(CalendarEvent) => Boolean- Filter function - Returns:
Array<CalendarEvent>
Get events matching predicate for specific date.
- date:
Date - predicateFn:
Function(CalendarEvent) => Boolean- Filter function - Returns:
Array<CalendarEvent>
Get names of all monitored calendars.
- Returns:
Array<String>
const cal = new ObsidianJS.Calendar(['Work', 'Personal']);
// Get events
const today = cal.getTodaysEvents();
const thisMonth = cal.getEventsBetween(
new Date('2025-10-01'),
new Date('2025-10-31')
);
// Find major events (duration >= 2 hours)
const longEvents = cal.getMajorEvents(
new Date('2025-10-01'),
new Date('2025-10-31'),
(event) => event.getDurationHours() >= 2
);
// All-day events
const allDay = cal.getMajorEvents(
new Date('2025-10-01'),
new Date('2025-12-31'),
(event) => event.isAllDay
);
// Events marked in notes
const marked = cal.getMajorEvents(
new Date('2025-10-01'),
new Date('2025-12-31'),
(event) => event.notes.includes('[major]')
);Represents a calendar event with helper methods.
new CalendarEvent(nativeEvent)- nativeEvent:
Object- Native Scriptable Calendar event - Note: Typically created by Calendar methods, not directly
| Property | Type | Description |
|---|---|---|
title |
String |
Event title |
startDate |
Date |
Start date/time |
endDate |
Date |
End date/time |
isAllDay |
Boolean |
All-day event flag |
location |
String |
Event location |
notes |
String |
Event notes |
calendarName |
String |
Calendar name |
id |
String |
Event identifier |
attendees |
Array<Object> |
Attendee objects |
nativeEvent |
Object |
Native event object |
Calculate event duration in hours.
- Returns:
Number
Test if event matches predicate.
- predicateFn:
Function(CalendarEvent) => Boolean - Returns:
Boolean
Get names of all attendees.
- Returns:
Array<String>
Get email addresses of all attendees.
- Returns:
Array<String>
Check if event has attendees.
- Returns:
Boolean
Get attendees excluding current user.
- Returns:
Array<Object>
const events = cal.getTodaysEvents();
const event = events[0];
// Access properties
console.log(event.title); // "Team Meeting"
console.log(event.location); // "Conference Room A"
console.log(event.getDurationHours()); // 1.5
// Check attendees
if (event.hasAttendees()) {
const names = event.getAttendeeNames();
console.log(`Attendees: ${names.join(', ')}`);
}
// Custom predicate
const isLong = event.isMajorEvent(e => e.getDurationHours() > 2);const ObsidianJS = importModule('ObsidianJS');
// Get today's calendar events
const cal = new ObsidianJS.Calendar(['Work', 'Personal']);
const events = cal.getTodaysEvents();
// Create/update daily note
const today = DateFormatter.toFilename(new Date());
const note = new ObsidianJS.Note({
folder: 'Daily Notes',
filename: `${today}.md`
});
// Set frontmatter
note.setFrontMatter({
created: today,
tags: 'daily-notes'
});
// Update Day Planner section
const dayPlanner = note.sections.find('Day Planner');
if (dayPlanner) {
const eventLines = events.map(e => {
const time = e.isAllDay
? 'All Day'
: `${DateFormatter.toTime12Hour(e.startDate)} - ${DateFormatter.toTime12Hour(e.endDate)}`;
return `- ${time} ${e.title}`;
}).join('\n');
dayPlanner.setContent(eventLines);
}
// Add tasks
const tasks = note.sections.find('Tasks');
if (tasks) {
const task = new ObsidianJS.Task({
description: 'Review meeting notes',
dueDate: today,
tags: 'work'
});
tasks.append(task.toMarkdown());
}
// Save all changes
note.save();