Claude Agent Skill · by Kepano

Obsidian Bases

Creates Obsidian .base files with proper YAML syntax for database-like views of your notes. Handles the full workflow from defining filters and formulas to conf

Install
Terminal · npx
$npx skills add https://github.com/kepano/obsidian-skills --skill obsidian-bases
Works with Paperclip

How Obsidian Bases fits into a Paperclip company.

Obsidian Bases drops into any Paperclip agent that handles this kind of work. Assign it to a specialist inside a pre-configured PaperclipOrg company and the skill becomes available on every heartbeat — no prompt engineering, no tool wiring.

S
SaaS FactoryPaired

Pre-configured AI company — 18 agents, 18 skills, one-time purchase.

$27$59
Explore pack
Source file
SKILL.md497 lines
Expand
---name: obsidian-basesdescription: 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 ## Workflow 1. **Create the file**: Create a `.base` file in the vault with valid YAML content2. **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` section4. **Configure views**: Add one or more views (`table`, `cards`, `list`, or `map`) with `order` specifying which properties to display5. **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 ## Schema Base files use the `.base` extension and contain valid YAML. ```yaml# Global filters apply to ALL views in the basefilters:  # 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 viewsformulas:  formula_name: 'expression' # Configure display names and settings for propertiesproperties:  property_name:    displayName: "Display Name"  formula.formula_name:    displayName: "Formula Display Name"  file.ext:    displayName: "Extension" # Define custom summary formulassummaries:  custom_summary_name: 'values.mean().round(3)' # Define one or more viewsviews:  - 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 filterfilters: 'status == "done"' # AND - all conditions must be truefilters:  and:    - 'status == "done"'    - 'priority > 3' # OR - any condition can be truefilters:  or:    - 'file.hasTag("book")'    - 'file.hasTag("article")' # NOT - exclude matching itemsfilters:  not:    - 'file.hasTag("archived")' # Nested filtersfilters:  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. ```yamlformulas:  # 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, "")'``` ## Key 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 (`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 || `duration()` | `duration(string): duration` | Parse duration string || `file()` | `file(path): file` | Get file object || `link()` | `link(path, display?): Link` | Create a link | ### Duration Type When subtracting two dates, the result is a **Duration** type (not a number). **Duration Fields:** `duration.days`, `duration.hours`, `duration.minutes`, `duration.seconds`, `duration.milliseconds` **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"(date(due_date) - today()).days.round(0)"           # Rounded days # 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"now() + \"1 day\""       # Tomorrow"today() + \"7d\""        # A week from today"now() - file.ctime"      # Returns Duration"(now() - file.ctime).days"  # Get days as number``` ## View Types ### Table View ```yamlviews:  - type: table    name: "My Table"    order:      - file.name      - status      - due_date    summaries:      price: Sum      count: Average``` ### Cards View ```yamlviews:  - type: cards    name: "Gallery"    order:      - file.name      - cover_image      - description``` ### List View ```yamlviews:  - type: list    name: "Simple List"    order:      - file.name      - status``` ### Map View Requires latitude/longitude properties and the Maps community plugin. ```yamlviews:  - 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 ```yamlfilters:  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 ```yamlfilters:  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``` ### Daily Notes Index ```yamlfilters:  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 ## Troubleshooting ### YAML Syntax Errors **Unquoted special characters**: Strings containing `:`, `{`, `}`, `[`, `]`, `,`, `&`, `*`, `#`, `?`, `|`, `-`, `<`, `>`, `=`, `!`, `%`, `@`, `` ` `` must be quoted. ```yaml# WRONG - colon in unquoted stringdisplayName: Status: Active # CORRECTdisplayName: "Status: Active"``` **Mismatched quotes in formulas**: When a formula contains double quotes, wrap the entire formula in single quotes. ```yaml# WRONG - double quotes inside double quotesformulas:  label: "if(done, "Yes", "No")" # CORRECT - single quotes wrapping double quotesformulas:  label: 'if(done, "Yes", "No")'``` ### Common Formula Errors **Duration math without field access**: Subtracting dates returns a Duration, not a number. Always access `.days`, `.hours`, etc. ```yaml# WRONG - Duration is not a number"(now() - file.ctime).round(0)" # CORRECT - access .days first, then round"(now() - file.ctime).days.round(0)"``` **Missing null checks**: Properties may not exist on all notes. Use `if()` to guard. ```yaml# WRONG - crashes if due_date is empty"(date(due_date) - today()).days" # CORRECT - guard with if()'if(due_date, (date(due_date) - today()).days, "")'``` **Referencing undefined formulas**: Ensure every `formula.X` in `order` or `properties` has a matching entry in `formulas`. ```yaml# This will fail silently if 'total' is not defined in formulasorder:  - formula.total # Fix: define itformulas:  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)