This skill enables skills-compatible agents to create and edit valid Obsidian Bases (`.base` files) including views, filters, formulas, and all related configurations. Obsidian Bases are YAML-based files that define dynamic views of notes in an Obsidian vault. A Base file can contain multiple views, global filters, formulas, property configurations, and custom summaries. Base files use the `.base` extension and contain valid YAML. They can also be embedded in Markdown code blocks.
.base files) including views, filters, formulas, and all related configurations..base extension and contain valid YAML. They can also be embedded in Markdown code blocks.# Global filters apply to ALL views in the base filters: # Can be a single filter string # OR a recursive filter object with and/or/not and: [] or: [] not: [] # Define formula properties that can be used across all views formulas: formula_name: 'expression' # Configure display names and settings for properties properties: property_name: displayName: "Display Name" formula.formula_name: displayName: "Formula Display Name" file.ext: displayName: "Extension" # Define custom summary formulas summaries: custom_summary_name: 'values.mean().round(3)' # Define one or more views views: - type: table | cards | list | map name: "View Name" limit: 10 # Optional: limit results groupBy: # Optional: group results property: property_name direction: ASC | DESC filters: # View-specific filters and: [] order: # Properties to display in order - file.name - property_name - formula.formula_name summaries: # Map properties to summary formulas property_name: Average
# Single filter filters: 'status == "done"' # AND - all conditions must be true filters: and: - 'status == "done"' - 'priority > 3' # OR - any condition can be true filters: or: - 'file.hasTag("book")' - 'file.hasTag("article")' # NOT - exclude matching items filters: not: - 'file.hasTag("archived")' # Nested filters filters: or: - file.hasTag("tag") - and: - file.hasTag("book") - file.hasLink("Textbook") - not: - file.hasTag("book") - file.inFolder("Required Reading")
==!=><>=<=&&||note.author or just authorfile.name, file.mtime, etc.formula.my_formulafile.namefile.basenamefile.pathfile.folderfile.extfile.sizefile.ctimefile.mtimefile.tagsfile.linksfile.backlinksfile.embedsfile.propertiesthis Keywordformulas section.formulas: # Simple arithmetic total: "price * quantity" # Conditional logic status_icon: 'if(done, "✅", "⏳")' # String formatting formatted_price: 'if(price, price.toFixed(2) + " dollars")' # Date formatting created: 'file.ctime.format("YYYY-MM-DD")' # Calculate days since created (use .days for Duration) days_old: '(now() - file.ctime).days' # Calculate days until due date days_until_due: 'if(due_date, (date(due_date) - today()).days, "")'
date()date(string): dateYYYY-MM-DD HH:mm:ssduration()duration(string): durationnow()now(): datetoday()today(): dateif()if(condition, trueResult, falseResult?)min()min(n1, n2, ...): numbermax()max(n1, n2, ...): numbernumber()number(any): numberlink()link(path, display?): Linklist()list(element): Listfile()file(path): fileimage()image(path): imageicon()icon(name): iconhtml()html(string): htmlescapeHTML()escapeHTML(string): stringisTruthy()any.isTruthy(): booleanisType()any.isType(type): booleantoString()any.toString(): stringdate.year, date.month, date.day, date.hour, date.minute, date.second, date.milliseconddate()date.date(): dateformat()date.format(string): stringtime()date.time(): stringrelative()date.relative(): stringisEmpty()date.isEmpty(): booleanduration.daysduration.hoursduration.minutesduration.secondsduration.milliseconds.round(), .floor(), .ceil() directly. You must access a numeric field first (like .days), then apply number functions.# CORRECT: Calculate days between dates "(date(due_date) - today()).days" # Returns number of days "(now() - file.ctime).days" # Days since created # CORRECT: Round the numeric result if needed "(date(due_date) - today()).days.round(0)" # Rounded days "(now() - file.ctime).hours.round(0)" # Rounded hours # WRONG - will cause error: # "((date(due) - today()) / 86400000).round(0)" # Duration doesn't support division then round `### Date Arithmetic` # Duration units: y/year/years, M/month/months, d/day/days, # w/week/weeks, h/hour/hours, m/minute/minutes, s/second/seconds # Add/subtract durations "date + \"1M\"" # Add 1 month "date - \"2h\"" # Subtract 2 hours "now() + \"1 day\"" # Tomorrow "today() + \"7d\"" # A week from today # Subtract dates returns Duration type "now() - file.ctime" # Returns Duration "(now() - file.ctime).days" # Get days as number "(now() - file.ctime).hours" # Get hours as number # Complex duration arithmetic "now() + (duration('1d') * 2)"
string.lengthcontains()string.contains(value): booleancontainsAll()string.containsAll(...values): booleancontainsAny()string.containsAny(...values): booleanstartsWith()string.startsWith(query): booleanendsWith()string.endsWith(query): booleanisEmpty()string.isEmpty(): booleanlower()string.lower(): stringtitle()string.title(): stringtrim()string.trim(): stringreplace()string.replace(pattern, replacement): stringrepeat()string.repeat(count): stringreverse()string.reverse(): stringslice()string.slice(start, end?): stringsplit()string.split(separator, n?): listabs()number.abs(): numberceil()number.ceil(): numberfloor()number.floor(): numberround()number.round(digits?): numbertoFixed()number.toFixed(precision): stringisEmpty()number.isEmpty(): booleanlist.lengthcontains()list.contains(value): booleancontainsAll()list.containsAll(...values): booleancontainsAny()list.containsAny(...values): booleanfilter()list.filter(expression): listvalue, index)map()list.map(expression): listvalue, index)reduce()list.reduce(expression, initial): anyvalue, index, acc)flat()list.flat(): listjoin()list.join(separator): stringreverse()list.reverse(): listslice()list.slice(start, end?): listsort()list.sort(): listunique()list.unique(): listisEmpty()list.isEmpty(): booleanasLink()file.asLink(display?): LinkhasLink()file.hasLink(otherFile): booleanhasTag()file.hasTag(...tags): booleanhasProperty()file.hasProperty(name): booleaninFolder()file.inFolder(folder): booleanasFile()link.asFile(): filelinksTo()link.linksTo(file): booleanisEmpty()object.isEmpty(): booleankeys()object.keys(): listvalues()object.values(): listmatches()regexp.matches(string): booleanviews: - type: table name: "My Table" order: - file.name - status - due_date summaries: price: Sum count: Average `### Cards View` views: - type: cards name: "Gallery" order: - file.name - cover_image - description `### List View` views: - type: list name: "Simple List" order: - file.name - status
views: - type: map name: "Locations" # Map-specific settings for lat/lng properties
AverageMinMaxSumRangeMedianStddevEarliestLatestRangeCheckedUncheckedEmptyFilledUniquefilters: and: - file.hasTag("task") - 'file.ext == "md"' formulas: days_until_due: 'if(due, (date(due) - today()).days, "")' is_overdue: 'if(due, date(due) < today() && status != "done", false)' priority_label: 'if(priority == 1, "🔴 High", if(priority == 2, "🟡 Medium", "🟢 Low"))' properties: status: displayName: Status formula.days_until_due: displayName: "Days Until Due" formula.priority_label: displayName: Priority views: - type: table name: "Active Tasks" filters: and: - 'status != "done"' order: - file.name - status - formula.priority_label - due - formula.days_until_due groupBy: property: status direction: ASC summaries: formula.days_until_due: Average - type: table name: "Completed" filters: and: - 'status == "done"' order: - file.name - completed_date `### Reading List Base` filters: or: - file.hasTag("book") - file.hasTag("article") formulas: reading_time: 'if(pages, (pages * 2).toString() + " min", "")' status_icon: 'if(status == "reading", "📖", if(status == "done", "✅", "📚"))' year_read: 'if(finished_date, date(finished_date).year, "")' properties: author: displayName: Author formula.status_icon: displayName: "" formula.reading_time: displayName: "Est. Time" views: - type: cards name: "Library" order: - cover - file.name - author - formula.status_icon filters: not: - 'status == "dropped"' - type: table name: "Reading List" filters: and: - 'status == "to-read"' order: - file.name - author - pages - formula.reading_time `### Project Notes Base` filters: and: - file.inFolder("Projects") - 'file.ext == "md"' formulas: last_updated: 'file.mtime.relative()' link_count: 'file.links.length' summaries: avgLinks: 'values.filter(value.isType("number")).mean().round(1)' properties: formula.last_updated: displayName: "Updated" formula.link_count: displayName: "Links" views: - type: table name: "All Projects" order: - file.name - status - formula.last_updated - formula.link_count summaries: formula.link_count: avgLinks groupBy: property: status direction: ASC - type: list name: "Quick List" order: - file.name - status `### Daily Notes Index` filters: and: - file.inFolder("Daily Notes") - '/^\d{4}-\d{2}-\d{2}$/.matches(file.basename)' formulas: word_estimate: '(file.size / 5).round(0)' day_of_week: 'date(file.basename).format("dddd")' properties: formula.day_of_week: displayName: "Day" formula.word_estimate: displayName: "~Words" views: - type: table name: "Recent Notes" limit: 30 order: - file.name - formula.day_of_week - formula.word_estimate - file.mtime
![[MyBase.base]] <!-- Specific view --> ![[MyBase.base#View Name]]
'if(done, "Yes", "No")'"My View Name"filters: and: - file.hasTag("project") `### Filter by Folder` filters: and: - file.inFolder("Notes") `### Filter by Date Range` filters: and: - 'file.mtime > now() - "7d"' `### Filter by Property Value` filters: and: - 'status == "active"' - 'priority >= 3' `### Combine Multiple Conditions` filters: or: - and: - file.hasTag("important") - 'status != "done"' - and: - 'priority == 1' - 'due != ""'