obsidian-bases ยท diff

git:20260118.41909ae to git:20260225.5a557ce

64 added, 218 removed. Audit A to A.

---
name: obsidian-bases
description: Create and edit Obsidian Bases (.base files) with views, filters, formulas, and summaries. Use when working with .base files, creating database-like views of notes, or when the user mentions Bases, table views, card views, filters, or formulas in Obsidian.
---
# Obsidian Bases Skill
- This skill enables skills-compatible agents to create and edit valid Obsidian Bases (`.base` files) including views, filters, formulas, and all related configurations.
-
- ## Overview
-
- 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.
+ ## Workflow
- ## File Format
+ 1. **Create the file**: Create a `.base` file in the vault with valid YAML content
+ 2. **Define scope**: Add `filters` to select which notes appear (by tag, folder, property, or date)
+ 3. **Add formulas** (optional): Define computed properties in the `formulas` section
+ 4. **Configure views**: Add one or more views (`table`, `cards`, `list`, or `map`) with `order` specifying which properties to display
+ 5. **Validate**: Verify the file is valid YAML with no syntax errors. Check that all referenced properties and formulas exist. Common issues: unquoted strings containing special YAML characters, mismatched quotes in formula expressions, referencing `formula.X` without defining `X` in `formulas`
+ 6. **Test in Obsidian**: Open the `.base` file in Obsidian to confirm the view renders correctly. If it shows a YAML error, check quoting rules below
- Base files use the `.base` extension and contain valid YAML. They can also be embedded in Markdown code blocks.
+ ## Schema
- ## Complete Schema
+ Base files use the `.base` extension and contain valid YAML.
```yaml
# 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
```
## Filter Syntax
Filters narrow down results. They can be applied globally or per-view.
### Filter Structure
```yaml
# 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")
```
### Filter Operators
| Operator | Description |
|----------|-------------|
| `==` | equals |
| `!=` | not equal |
| `>` | greater than |
| `<` | less than |
| `>=` | greater than or equal |
| `<=` | less than or equal |
| `&&` | logical and |
| `\|\|` | logical or |
| <code>!</code> | logical not |
## Properties
### Three Types of Properties
1. **Note properties** - From frontmatter: `note.author` or just `author`
2. **File properties** - File metadata: `file.name`, `file.mtime`, etc.
3. **Formula properties** - Computed values: `formula.my_formula`
### File Properties Reference
| Property | Type | Description |
|----------|------|-------------|
| `file.name` | String | File name |
| `file.basename` | String | File name without extension |
| `file.path` | String | Full path to file |
| `file.folder` | String | Parent folder path |
| `file.ext` | String | File extension |
| `file.size` | Number | File size in bytes |
| `file.ctime` | Date | Created time |
| `file.mtime` | Date | Modified time |
| `file.tags` | List | All tags in file |
| `file.links` | List | Internal links in file |
| `file.backlinks` | List | Files linking to this file |
| `file.embeds` | List | Embeds in the note |
| `file.properties` | Object | All frontmatter properties |
### The `this` Keyword
- In main content area: refers to the base file itself
- When embedded: refers to the embedding file
- In sidebar: refers to the active file in main content
## Formula Syntax
Formulas compute values from properties. Defined in the `formulas` section.
```yaml
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, "")'
```
- ## Functions Reference
+ ## Key Functions
- ### Global Functions
+ Most commonly used functions. For the complete reference of all types (Date, String, Number, List, File, Link, Object, RegExp), see [FUNCTIONS_REFERENCE.md](references/FUNCTIONS_REFERENCE.md).
| Function | Signature | Description |
|----------|-----------|-------------|
- | `date()` | `date(string): date` | Parse string to date. Format: `YYYY-MM-DD HH:mm:ss` |
- | `duration()` | `duration(string): duration` | Parse duration string |
+ | `date()` | `date(string): date` | Parse string to date (`YYYY-MM-DD HH:mm:ss`) |
| `now()` | `now(): date` | Current date and time |
| `today()` | `today(): date` | Current date (time = 00:00:00) |
| `if()` | `if(condition, trueResult, falseResult?)` | Conditional |
- | `min()` | `min(n1, n2, ...): number` | Smallest number |
- | `max()` | `max(n1, n2, ...): number` | Largest number |
- | `number()` | `number(any): number` | Convert to number |
- | `link()` | `link(path, display?): Link` | Create a link |
- | `list()` | `list(element): List` | Wrap in list if not already |
+ | `duration()` | `duration(string): duration` | Parse duration string |
| `file()` | `file(path): file` | Get file object |
- | `image()` | `image(path): image` | Create image for rendering |
- | `icon()` | `icon(name): icon` | Lucide icon by name |
- | `html()` | `html(string): html` | Render as HTML |
- | `escapeHTML()` | `escapeHTML(string): string` | Escape HTML characters |
-
- ### Any Type Functions
-
- | Function | Signature | Description |
- |----------|-----------|-------------|
- | `isTruthy()` | `any.isTruthy(): boolean` | Coerce to boolean |
- | `isType()` | `any.isType(type): boolean` | Check type |
- | `toString()` | `any.toString(): string` | Convert to string |
-
- ### Date Functions & Fields
-
- **Fields:** `date.year`, `date.month`, `date.day`, `date.hour`, `date.minute`, `date.second`, `date.millisecond`
-
- | Function | Signature | Description |
- |----------|-----------|-------------|
- | `date()` | `date.date(): date` | Remove time portion |
- | `format()` | `date.format(string): string` | Format with Moment.js pattern |
- | `time()` | `date.time(): string` | Get time as string |
- | `relative()` | `date.relative(): string` | Human-readable relative time |
- | `isEmpty()` | `date.isEmpty(): boolean` | Always false for dates |
+ | `link()` | `link(path, display?): Link` | Create a link |
### Duration Type
- When subtracting two dates, the result is a **Duration** type (not a number). Duration has its own properties and methods.
+ When subtracting two dates, the result is a **Duration** type (not a number).
- **Duration Fields:**
- | Field | Type | Description |
- |-------|------|-------------|
- | `duration.days` | Number | Total days in duration |
- | `duration.hours` | Number | Total hours in duration |
- | `duration.minutes` | Number | Total minutes in duration |
- | `duration.seconds` | Number | Total seconds in duration |
- | `duration.milliseconds` | Number | Total milliseconds in duration |
+ **Duration Fields:** `duration.days`, `duration.hours`, `duration.minutes`, `duration.seconds`, `duration.milliseconds`
- **IMPORTANT:** Duration does NOT support `.round()`, `.floor()`, `.ceil()` directly. You must access a numeric field first (like `.days`), then apply number functions.
+ **IMPORTANT:** Duration does NOT support `.round()`, `.floor()`, `.ceil()` directly. Access a numeric field first (like `.days`), then apply number functions.
```yaml
# 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
```yaml
# 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)"
+ "now() - file.ctime" # Returns Duration
+ "(now() - file.ctime).days" # Get days as number
```
- ### String Functions
-
- **Field:** `string.length`
-
- | Function | Signature | Description |
- |----------|-----------|-------------|
- | `contains()` | `string.contains(value): boolean` | Check substring |
- | `containsAll()` | `string.containsAll(...values): boolean` | All substrings present |
- | `containsAny()` | `string.containsAny(...values): boolean` | Any substring present |
- | `startsWith()` | `string.startsWith(query): boolean` | Starts with query |
- | `endsWith()` | `string.endsWith(query): boolean` | Ends with query |
- | `isEmpty()` | `string.isEmpty(): boolean` | Empty or not present |
- | `lower()` | `string.lower(): string` | To lowercase |
- | `title()` | `string.title(): string` | To Title Case |
- | `trim()` | `string.trim(): string` | Remove whitespace |
- | `replace()` | `string.replace(pattern, replacement): string` | Replace pattern |
- | `repeat()` | `string.repeat(count): string` | Repeat string |
- | `reverse()` | `string.reverse(): string` | Reverse string |
- | `slice()` | `string.slice(start, end?): string` | Substring |
- | `split()` | `string.split(separator, n?): list` | Split to list |
-
- ### Number Functions
-
- | Function | Signature | Description |
- |----------|-----------|-------------|
- | `abs()` | `number.abs(): number` | Absolute value |
- | `ceil()` | `number.ceil(): number` | Round up |
- | `floor()` | `number.floor(): number` | Round down |
- | `round()` | `number.round(digits?): number` | Round to digits |
- | `toFixed()` | `number.toFixed(precision): string` | Fixed-point notation |
- | `isEmpty()` | `number.isEmpty(): boolean` | Not present |
-
- ### List Functions
-
- **Field:** `list.length`
-
- | Function | Signature | Description |
- |----------|-----------|-------------|
- | `contains()` | `list.contains(value): boolean` | Element exists |
- | `containsAll()` | `list.containsAll(...values): boolean` | All elements exist |
- | `containsAny()` | `list.containsAny(...values): boolean` | Any element exists |
- | `filter()` | `list.filter(expression): list` | Filter by condition (uses `value`, `index`) |
- | `map()` | `list.map(expression): list` | Transform elements (uses `value`, `index`) |
- | `reduce()` | `list.reduce(expression, initial): any` | Reduce to single value (uses `value`, `index`, `acc`) |
- | `flat()` | `list.flat(): list` | Flatten nested lists |
- | `join()` | `list.join(separator): string` | Join to string |
- | `reverse()` | `list.reverse(): list` | Reverse order |
- | `slice()` | `list.slice(start, end?): list` | Sublist |
- | `sort()` | `list.sort(): list` | Sort ascending |
- | `unique()` | `list.unique(): list` | Remove duplicates |
- | `isEmpty()` | `list.isEmpty(): boolean` | No elements |
-
- ### File Functions
-
- | Function | Signature | Description |
- |----------|-----------|-------------|
- | `asLink()` | `file.asLink(display?): Link` | Convert to link |
- | `hasLink()` | `file.hasLink(otherFile): boolean` | Has link to file |
- | `hasTag()` | `file.hasTag(...tags): boolean` | Has any of the tags |
- | `hasProperty()` | `file.hasProperty(name): boolean` | Has property |
- | `inFolder()` | `file.inFolder(folder): boolean` | In folder or subfolder |
-
- ### Link Functions
-
- | Function | Signature | Description |
- |----------|-----------|-------------|
- | `asFile()` | `link.asFile(): file` | Get file object |
- | `linksTo()` | `link.linksTo(file): boolean` | Links to file |
-
- ### Object Functions
-
- | Function | Signature | Description |
- |----------|-----------|-------------|
- | `isEmpty()` | `object.isEmpty(): boolean` | No properties |
- | `keys()` | `object.keys(): list` | List of keys |
- | `values()` | `object.values(): list` | List of values |
-
- ### Regular Expression Functions
-
- | Function | Signature | Description |
- |----------|-----------|-------------|
- | `matches()` | `regexp.matches(string): boolean` | Test if matches |
-
## View Types
### Table View
```yaml
views:
- type: table
name: "My Table"
order:
- file.name
- status
- due_date
summaries:
price: Sum
count: Average
```
### Cards View
```yaml
views:
- type: cards
name: "Gallery"
order:
- file.name
- cover_image
- description
```
### List View
```yaml
views:
- type: list
name: "Simple List"
order:
- file.name
- status
```
### Map View
Requires latitude/longitude properties and the Maps community plugin.
```yaml
views:
- type: map
name: "Locations"
# Map-specific settings for lat/lng properties
```
## Default Summary Formulas
| Name | Input Type | Description |
|------|------------|-------------|
| `Average` | Number | Mathematical mean |
| `Min` | Number | Smallest number |
| `Max` | Number | Largest number |
| `Sum` | Number | Sum of all numbers |
| `Range` | Number | Max - Min |
| `Median` | Number | Mathematical median |
| `Stddev` | Number | Standard deviation |
| `Earliest` | Date | Earliest date |
| `Latest` | Date | Latest date |
| `Range` | Date | Latest - Earliest |
| `Checked` | Boolean | Count of true values |
| `Unchecked` | Boolean | Count of false values |
| `Empty` | Any | Count of empty values |
| `Filled` | Any | Count of non-empty values |
| `Unique` | Any | Count of unique values |
## Complete Examples
### Task Tracker Base
```yaml
filters:
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
```yaml
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
-
- ```yaml
- 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
```yaml
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
```
## Embedding Bases
Embed in Markdown files:
```markdown
![[MyBase.base]]
<!-- Specific view -->
![[MyBase.base#View Name]]
```
## YAML Quoting Rules
- Use single quotes for formulas containing double quotes: `'if(done, "Yes", "No")'`
- Use double quotes for simple strings: `"My View Name"`
- Escape nested quotes properly in complex expressions
- ## Common Patterns
+ ## Troubleshooting
- ### Filter by Tag
+ ### YAML Syntax Errors
+
+ **Unquoted special characters**: Strings containing `:`, `{`, `}`, `[`, `]`, `,`, `&`, `*`, `#`, `?`, `|`, `-`, `<`, `>`, `=`, `!`, `%`, `@`, `` ` `` must be quoted.
+
```yaml
- filters:
- and:
- - file.hasTag("project")
+ # WRONG - colon in unquoted string
+ displayName: Status: Active
+
+ # CORRECT
+ displayName: "Status: Active"
```
- ### Filter by Folder
+ **Mismatched quotes in formulas**: When a formula contains double quotes, wrap the entire formula in single quotes.
+
```yaml
- filters:
- and:
- - file.inFolder("Notes")
+ # WRONG - double quotes inside double quotes
+ formulas:
+ label: "if(done, "Yes", "No")"
+
+ # CORRECT - single quotes wrapping double quotes
+ formulas:
+ label: 'if(done, "Yes", "No")'
```
- ### Filter by Date Range
+ ### Common Formula Errors
+
+ **Duration math without field access**: Subtracting dates returns a Duration, not a number. Always access `.days`, `.hours`, etc.
+
```yaml
- filters:
- and:
- - 'file.mtime > now() - "7d"'
+ # WRONG - Duration is not a number
+ "(now() - file.ctime).round(0)"
+
+ # CORRECT - access .days first, then round
+ "(now() - file.ctime).days.round(0)"
```
- ### Filter by Property Value
+ **Missing null checks**: Properties may not exist on all notes. Use `if()` to guard.
+
```yaml
- filters:
- and:
- - 'status == "active"'
- - 'priority >= 3'
+ # WRONG - crashes if due_date is empty
+ "(date(due_date) - today()).days"
+
+ # CORRECT - guard with if()
+ 'if(due_date, (date(due_date) - today()).days, "")'
```
- ### Combine Multiple Conditions
+ **Referencing undefined formulas**: Ensure every `formula.X` in `order` or `properties` has a matching entry in `formulas`.
+
```yaml
- filters:
- or:
- - and:
- - file.hasTag("important")
- - 'status != "done"'
- - and:
- - 'priority == 1'
- - 'due != ""'
+ # This will fail silently if 'total' is not defined in formulas
+ order:
+ - formula.total
+
+ # Fix: define it
+ formulas:
+ total: "price * quantity"
```
## References
- [Bases Syntax](https://help.obsidian.md/bases/syntax)
- [Functions](https://help.obsidian.md/bases/functions)
- [Views](https://help.obsidian.md/bases/views)
- [Formulas](https://help.obsidian.md/formulas)
+ - [Complete Functions Reference](references/FUNCTIONS_REFERENCE.md)