Skip to main content
ClaudeWave
Skill6.6k repo starsupdated 16d ago

obsidian-bases

Obsidian Bases (launched 2025) transforms vault notes into queryable, dynamic views using `.base` files. This skill creates and edits Bases files containing filters, formulas, and view definitions (table, card, list) to organize notes into databases without requiring plugins. Use it when you need to build task trackers, reading lists, or any structured database view over your vault notes.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/AgriciDaniel/claude-obsidian /tmp/obsidian-bases && cp -r /tmp/obsidian-bases/skills/obsidian-bases ~/.claude/skills/obsidian-bases
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# obsidian-bases: Obsidian's Database Layer

Obsidian Bases (launched 2025) turns vault notes into queryable, dynamic views. Tables, cards, lists, maps. Defined in `.base` files. No plugin required; it is a core Obsidian feature.

**Substrate preference (v1.7+)**: This skill is a self-contained fallback. **Prefer `kepano/obsidian-skills`** as the authoritative substrate — its `obsidian-bases` skill is the canonical reference for Bases YAML, formulas, and view definitions. If you see an `obsidian-bases` skill available without the `claude-obsidian:` namespace, that is kepano's version: use it. The reference below is provided so the plugin remains functional when kepano's marketplace is not installed. Install: `claude plugin marketplace add kepano/obsidian-skills`. Official Bases docs: https://help.obsidian.md/bases/syntax

---

## File Format

`.base` files contain valid YAML. The root keys are `filters`, `formulas`, `properties`, `summaries`, and `views`.

```yaml
# Global filters: apply to ALL views
filters:
  and:
    - file.hasTag("wiki")
    - 'status != "archived"'

# Computed properties
formulas:
  age_days: '(now() - file.ctime).days.round(0)'
  status_icon: 'if(status == "mature", "✅", "🔄")'

# Display name overrides for properties panel
properties:
  status:
    displayName: "Status"
  formula.age_days:
    displayName: "Age (days)"

# One or more views
views:
  - type: table
    name: "All Pages"
    order:
      - file.name
      - type
      - status
      - updated
      - formula.age_days
```

---

## Filters

Filters select which notes appear. Applied globally or per-view.

```yaml
# Single string filter
filters: 'status == "current"'

# AND: all must be true
filters:
  and:
    - 'status != "archived"'
    - file.hasTag("wiki")

# OR: any can be true
filters:
  or:
    - file.hasTag("concept")
    - file.hasTag("entity")

# NOT: exclude matches
filters:
  not:
    - file.inFolder("wiki/meta")

# Nested
filters:
  and:
    - file.inFolder("wiki/")
    - or:
        - 'type == "concept"'
        - 'type == "entity"'
```

### Filter operators

`==` `!=` `>` `<` `>=` `<=`

### Useful filter functions

| Function | Example |
|----------|---------|
| `file.hasTag("x")` | Notes with tag `x` |
| `file.inFolder("path/")` | Notes in folder |
| `file.hasLink("Note")` | Notes linking to Note |

---

## Properties

Three types:
- **Note properties**: from frontmatter: `status`, `type`, `updated`
- **File properties**: metadata: `file.name`, `file.mtime`, `file.size`, `file.ctime`, `file.tags`, `file.folder`
- **Formula properties**: computed: `formula.age_days`

---

## Formulas

Defined in `formulas:`. Referenced as `formula.name` in `order:` and `properties:`.

```yaml
formulas:
  # Days since created
  age_days: '(now() - file.ctime).days.round(0)'

  # Days until a date property
  days_until: 'if(due_date, (date(due_date) - today()).days, "")'

  # Conditional label
  status_icon: 'if(status == "mature", "✅", if(status == "developing", "🔄", "🌱"))'

  # Word count estimate
  word_est: '(file.size / 5).round(0)'
```

**Key rule**: Subtracting two dates returns a `Duration`. Not a number. Always access `.days` first:
```yaml
# CORRECT
age: '(now() - file.ctime).days'

# WRONG: crashes
age: '(now() - file.ctime).round(0)'
```

**Always guard nullable properties with `if()`**:
```yaml
# CORRECT
days_left: 'if(due_date, (date(due_date) - today()).days, "")'
```

---

## View Types

### Table
```yaml
views:
  - type: table
    name: "Wiki Index"
    limit: 100
    order:
      - file.name
      - type
      - status
      - updated
    groupBy:
      property: type
      direction: ASC
```

### Cards
```yaml
views:
  - type: cards
    name: "Gallery"
    order:
      - file.name
      - tags
      - status
```

### List
```yaml
views:
  - type: list
    name: "Quick List"
    order:
      - file.name
      - status
```

---

## Wiki Vault Templates

### Wiki content dashboard (all non-meta pages)

```yaml
filters:
  and:
    - file.inFolder("wiki/")
    - not:
        - file.inFolder("wiki/meta")

formulas:
  age: '(now() - file.ctime).days.round(0)'

properties:
  formula.age:
    displayName: "Age (days)"

views:
  - type: table
    name: "All Wiki Pages"
    order:
      - file.name
      - type
      - status
      - updated
      - formula.age
    groupBy:
      property: type
      direction: ASC
```

### Entity index (people, orgs, repos)

```yaml
filters:
  and:
    - file.inFolder("wiki/entities/")
    - 'file.ext == "md"'

views:
  - type: table
    name: "Entities"
    order:
      - file.name
      - entity_type
      - status
      - updated
    groupBy:
      property: entity_type
      direction: ASC
```

### Recent ingests

```yaml
filters:
  and:
    - file.inFolder("wiki/sources/")

views:
  - type: table
    name: "Sources"
    order:
      - file.name
      - source_type
      - created
      - status
    groupBy:
      property: source_type
      direction: ASC
```

---

## Embedding in Notes

```markdown
![[MyBase.base]]

![[MyBase.base#View Name]]
```

---

## Where to Save

Store `.base` files in `wiki/meta/` for vault dashboards:
- `wiki/meta/dashboard.base`: main content view
- `wiki/meta/entities.base`: entity tracker
- `wiki/meta/sources.base`: ingestion log

---

## YAML Quoting Rules

- Formulas with double quotes → wrap in single quotes: `'if(done, "Yes", "No")'`
- Strings with colons or special chars → wrap in double quotes: `"Status: Active"`
- Unquoted strings with `:` break YAML parsing

---

## What Not to Do

- Do not use `from:` or `where:`: those are Dataview syntax, not Obsidian Bases
- Do not use `sort:` at the root level: sorting is per-view via `order:` and `groupBy:`
- Do not put `.base` files outside the vault: they only render inside Obsidian
- Do not reference `formula.X` in `order:` without defining `X` in `formulas:`

---

## How to think (10-principle mapping)

When working on this skill, apply the 10-principle loop. See [`skills/thin