用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/Bruno-Cunha-Souza/ValarMindSkills --skill obsidian-bases命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
| name | obsidian-bases |
| description | Create/edit Obsidian .base files — views, filters, formulas, summaries. |
| source | https://github.com/kepano/obsidian-skills |
.base file in the vault with valid YAML contentfilters to select which notes appear (by tag, folder, property, or date)formulas sectiontable, cards, list, or map) with order specifying which properties to displayformula.X without defining X in formulas.base file in Obsidian to confirm the view renders correctly. If it shows a YAML error, check quoting rules belowBase files use the .base extension and contain valid 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
Filters narrow down results. They can be applied globally or per-view.
# 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")
| Operator | Description |
|---|---|
== | equals |
!= | not equal |
> | greater than |
< | less than |
>= | greater than or equal |
<= | less than or equal |
&& | logical and |
|| | logical or |
! | logical not |
note.author or just authorfile.name, file.mtime, etc.formula.my_formula| 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 |
this KeywordFormulas compute values from properties. Defined in the formulas 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, "")'
Most commonly used functions. For the complete reference of all types (Date, String, Number, List, File, Link, Object, RegExp), see 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 |
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.
# 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
# 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
views:
- type: table
name: "My Table"
order:
- file.name
- status
- due_date
summaries:
price: Sum
count: Average
views:
- type: cards
name: "Gallery"
order:
- file.name
- cover_image
- description
views:
- type: list
name: "Simple List"
order:
- file.name
- status
Requires notes with latitude and longitude properties.
views:
- type: map
name: "Locations"
# Map-specific settings for lat/lng properties
| 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 |
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
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:
-
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
Embed in Markdown files:
![[MyBase.base]]
<!-- Specific view -->
![[MyBase.base#View Name]]
'if(done, "Yes", "No")'"My View Name"Unquoted special characters: Strings containing :, {, }, [, ], ,, &, *, #, ?, |, -, <, >, =, !, %, @, ` must be quoted.
# WRONG - colon in unquoted string
displayName: Status: Active
# CORRECT
displayName: "Status: Active"
Mismatched quotes in formulas: When a formula contains double quotes, wrap the entire formula in single quotes.
# WRONG - double quotes inside double quotes
formulas:
label: "if(done, "Yes", "No")"
# CORRECT - single quotes wrapping double quotes
formulas:
label: 'if(done, "Yes", "No")'
Duration math without field access: Subtracting dates returns a Duration, not a number. Always access .days, .hours, etc.
# 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.
# 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.
# This will fail silently if 'total' is not defined in formulas
order:
- formula.total
# Fix: define it
formulas:
total: "price * quantity"
@obsidian-brainThe brain/ subtree of any project vault is a closed graph owned by @obsidian-brain. Bases must not breach its isolation.
Never include wikilinks ([[...]]) or embeds (![[...]]) — in the base file body, in any view's name, in formula string literals, or anywhere else — that target files under brain/ (sessions, topics, decisions, or the <slug>-brain.md index file). The brain/ subtree is owned and maintained by @obsidian-brain; bases must not surface its contents through wikilinks or embeds in either direction.
Never embed a .base file inside any note under brain/, and never embed a brain note (or its index) inside a .base file. The ![[<file>.base]] and ![[<brain-note>]] patterns are forbidden across this boundary.
Never author a base whose global or per-view filters resolve into brain/. When a base scopes the entire vault, exclude the subtree explicitly:
filters:
and:
- file.hasTag("task")
- '!file.inFolder("brain")'
The same applies to per-view filters that would otherwise sweep in brain notes.
Never add formula.X expressions that resolve files inside brain/ (e.g., file("brain/<slug>-brain"), link("brain/topics/auth")). Formulas that create links to brain notes are equivalent to a wikilink and fall under the same prohibition.
If the user asks for a base that lists sessions, decisions, or topics, redirect them to @obsidian-brain — that surface is owned there (the brain.base dashboard lives inside brain/ and is generated by @obsidian-brain, not by this skill).
基于 SOC 职业分类