Generated banner for ObsidianOS: Work
Generated logo for ObsidianOS: Work

ObsidianOS: Work

Vault template

First committed by benoror

Published in benoror/obsidianos_work. Publisher page

165 GitHub stars

What it is

Obsidian vault template with agent skills — meeting wrap pipeline, Bases views, and QMD search
— the description by benoror

AutoGineer overview, from the brain’s own files

ObsidianOS: Work is a structured Obsidian vault template designed to function as an agentic operating system. It provides a standardized directory structure and a comprehensive suite of AI agent skills that enable users to automate common knowledge work tasks. By integrating with tools like the Obsidian CLI, Google Workspace CLI, and QMD for semantic search, the vault allows AI agents to perform complex operations such as wrapping up meeting notes, triaging inbox items, managing participant wikilinks, and maintaining vault health. It is designed to be agent-agnostic, supporting various MCP-compatible clients like Cursor, Claude Code, and OpenCode, ensuring a consistent experience across different AI environments.

How it works

Memory model: Markdown vault

AutoGineer overview, from the brain’s own files

The system operates as a markdown-based vault where AI agents interact with files via a set of predefined skills located in the .agents/skills/ directory. These skills are triggered by slash commands that execute sequences of operations, such as fetching meeting transcripts from Google Docs, organizing files into specific folders, extracting action items, and committing changes to version control. The vault uses Obsidian Bases for data views and queries, and relies on external CLI tools for tasks like Gmail transcript processing and semantic search indexing via QMD.

Folders
FolderRoleFiles
.claudeagent-config1
.cursoragent-config5
.githubagent-config1
Templatestemplates3
memorymemory1
.agentsfolder60
.assetsfolder3
.opencodefolder1
.scriptsfolder3
Meetingsfolder7
Teamsfolder4

The agent reads

The agent writes

Requirements

Runtimes: Node.js

API keys (by name): GOOGLE_WORKSPACE_CLI_TOKEN

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Google Antigravity, Kiro, OpenCode, Amp, Roo Code, Cline, JetBrains Junie, Devin (ex-Windsurf)

Set it up

  1. Clone the repository at the commit AutoGineer scanned:

    git clone https://github.com/benoror/obsidianos_work.git && cd obsidianos_work && git checkout 3c7923e6423b7e6508b809bade36302c5ca639f9
  2. Claude Code reads CLAUDE.md from this folder automatically.

  3. cd obsidianos_work && claude

  4. AutoGineer scanned these files at commit 3c7923e.

  5. Not scanned by AutoGineerThe author’s README also describes installing it from a clone of its repository. Read its install section: AutoGineer did not scan that path. https://github.com/benoror/obsidianos_work/blob/3c7923e6423b7e6508b809bade36302c5ca639f9/README.md#1-clone-and-install
  6. First committed by benoror. Published in benoror/obsidianos_work. Licence: MIT License.

Usage

AutoGineer overview, from the brain’s own files

  • Automating the end-to-end processing of meeting transcripts from Gmail to organized Obsidian notes.
  • Managing team and individual profiles with automated onboarding and 1:1 tracking.
  • Performing vault-wide maintenance, including link auditing and tag migration.
  • Executing complex agentic workflows like weekly recaps across multiple data sources.
  • Authoring and managing Obsidian-specific structures like JSON canvases and Bases views.
  • Standardizing agent behavior across different IDEs and CLI environments using shared rule sets.
“/meeting wrap pending”
The agent identifies all pending meeting notes, fetches transcripts, resolves participants, extracts action items, and commits the batch.
“/recap last week”
The agent synthesizes a summary of the previous week's activities by scanning emails, Slack, Jira, and vault notes.
“/vault-health”
The agent audits the vault for unresolved links, orphans, and sync conflicts to maintain data integrity.
“/fill-participants all”
The agent scans all meeting notes and automatically converts participant names into [[@Person]] wikilinks.

Documentation by benoror

<p align="center"> <img src=".assets/ObsidianOS-logo.png" alt="ObsidianOS" width="480" /> </p>

ObsidianOS: Work

An Obsidian vault wired with AI agent skills — an Agentic Operating System for Thinkers.

Sneak Peek

Slash commands that run inside your vault, powered by any AI agent:

/meeting wrap pending     → Gmail → triage → cache → participants → todos
/mail-transcripts         → Drain Gemini transcript emails into Notes:
/organize-meetings        → Triage Meetings/_inbox/ into the right folder
/cache-notes              → Embed AI meeting transcripts
/fill-participants        → Resolve names to [[@Person]] wikilinks
/followup-todos           → Extract action items as plain markdown bullets
/note-status              → Verify notes are fully processed
/recap                    → Weekly summary from email, Slack, Jira & vault
/vault-health             → Audit unresolved links and orphans
/commit                   → Stage & commit with inferred intent
/sync-upstream-obsidianos → Pull updates from upstream ObsidianOS

Agent-agnostic — works with Cursor, Claude Code, OpenCode, or any MCP-compatible client. Clone it, fill in USER.md, and go.

<p align="center"> <a href=".assets/demo-obsidian.png"><img src=".assets/demo-obsidian.png" alt="Obsidian vault demo" width="720" /></a> </p> <p align="center"> <a href=".assets/demo-cursor-cli.png"><img src=".assets/demo-cursor-cli.png" alt="Cursor CLI demo — /recap this week" width="720" /></a> </p>

Compatible agents

AgentSupport levelNotes
Cursor IDEFullLoads .cursor/rules/ and .cursor/mcp.json automatically
Cursor CLI (cursor)FullSame engine in background/headless mode
Claude CodeFullReads AGENTS.md + CLAUDE.md natively; see CLAUDE.md for QMD MCP setup
OpenCode / CrushFullReads OpenCode.md; see OpenCode.md for QMD MCP setup
OpenClawFullWorkspace skills in skills/ (symlink to .agents/skills/); config in ~/.openclaw/openclaw.json
Other MCP-compatible clientsPartialCan use the QMD MCP server; agent instructions won't auto-load

Skills

SkillWhat it does
/meetingCreate or wrap up meeting notes (from Google Calendar or manual)
/cache-notesFetch & embed AI meeting transcripts as Obsidian callouts
/fill-participantsResolve names in notes to [[@Person]] wikilinks
/followup-todosExtract action items as plain markdown bullets (no Tasks checkboxes)
/recapWeekly recap from emails, Slack, Jira, and vault notes
/note-statusVerify meeting notes are fully processed (Notes, Cache, Participants, Todos)
/commitStage and commit — accepts file/folder scope, free-text intent, or amend
/sync-upstream-obsidianosPull structural updates from upstream ObsidianOS
defuddleClean markdown from URLs via Defuddle CLI
json-canvasJSON Canvas (.canvas) authoring
obsidian-basesObsidian Bases (.base) views, filters, formulas
obsidian-cliVault operations via the obsidian CLI (Obsidian must be running)
obsidian-markdownObsidian Flavored Markdown conventions
/mail-transcriptsDrain Gmail AI-transcript notifications into meeting Notes:
/organize-meetingsTriage Meetings/_inbox/ into the right subfolder (qmd + memory)
otter-fetchOtter.ai transcript sub-skill (used by cache-notes / fill-participants)
/people-stubsBatch-create @Name.md stubs from unresolved [[@*]] links
/onboard-personCreate/enrich a @Name.md from external sources (ATS / profile)
/last-1on1Flag overdue 1:1s by recency
/vault-healthAudit unresolved links, orphans, dead-ends, and sync conflicts
/migrate-tagsMigrate body #hashtags to frontmatter tags: lists
/workspace-modeSwitch between named Obsidian Workspace layouts
/sprint-retroSynthesize a Sprint Retro draft from vault sources

Each skill supports multiple sub-commands and arguments — see AGENTS.md for the full reference. Skill proxies: .cursor/skills, .claude/skills, .opencode/skills, and repo-root skills/ are symlinks to .agents/skills/ so Cursor, Claude Code, OpenCode, and OpenClaw share one canonical tree.

Core pipeline vs optional modules
TierSkillsWhen you need them
Core — meeting wrap/meeting, /mail-transcripts, /organize-meetings, /cache-notes, /fill-participants, /followup-todos, /note-status, /commitProcessing Gemini (or Otter) meeting transcripts end-to-end
Vault maintenance/people-stubs, /vault-health, /migrate-tagsGrowing vault hygiene
People & teams/onboard-person, /last-1on1HR-style people files and 1:1 tracking
Integrations/recap, otter-fetchWeekly recaps; Otter.ai (manual JSON workflow)
Workflow modules/sprint-retro, /workspace-modeScrum teams; saved Obsidian Workspace layouts
Authoring / toolsdefuddle, json-canvas, obsidian-bases, obsidian-cli, obsidian-markdownBuilding notes, canvases, and bases
Upstream sync/sync-upstream-obsidianosPulling template updates into a fork

Meeting wrap pipeline

The main workflow chains skills in sequence. /meeting wrap pending runs the full batch; /meeting wrap <path> runs a single note.

/mail-transcripts          → link Gemini Docs from Gmail into Notes:
/organize-meetings         → move _inbox/ stubs to the right Meetings/ subfolder
/note-status pending       → discover notes missing a wrap step (Meetings.base Pending view)
/cache-notes               → fetch Docs/Otter → embed ## 🤖 AI Notes callouts
/fill-participants         → resolve Participants: frontmatter
/followup-todos            → propose plain-bullet follow-ups (user confirms)
/commit                    → one commit for the batch
Dependency matrix (core pipeline)
CapabilityRequired forSetup
Obsidian runningBases queries, obsidian property:*, batch pending discoveryOpen the vault; enable Bases (core)
Obsidian CLInote-status, cache-notes, organize-meetings, last-1on1Install from Obsidian download; verify obsidian is on PATH
Meetings.base / People.basePending, CachePending, Inbox, OneOnOnes viewsShipped in repo — open in Obsidian to index
Google Workspace CLI (gws)Calendar, Docs, Gmail transcript drain§ 3 below — Gmail modify scope for /mail-transcripts
Python 3.scripts/gmail_ai_transcripts_to_meetings.pySystem python3 (no extra packages)
QMD/recap, /organize-meetings similarity, date scans§ 4 below — optional if you only use Bases + single-file wrap

NOTE
Google Workspace skills use gws in the terminal, not MCP. Calendar/Docs workflows are read-only; /mail-transcripts also writes meeting notes and marks Gmail messages read (modify scope).

Prerequisites

  • Cursor IDE or CLI (or any agent that supports MCP — see Compatible agents)

  • Node.js v24+ (matches CI; v20 may work but is untested)

  • Python 3 — for /mail-transcripts batch script

  • Obsidian with Bases enabled — required for the meeting wrap pipeline

  • Obsidian CLI — required for Bases queries and frontmatter mutations in batch skills

  • Google Workspace CLI (gws) — optional for Calendar/Docs-only workflows; required for /mail-transcripts

  • QMD — optional; recommended for /recap and /organize-meetings similarity search

Setup

1. Clone and install
git clone https://github.com/benoror/obsidianos_work.git
cd obsidianos_work
npm install
2. Fill in your identity

Edit USER.md with your name, email, timezone, and aliases. This is the single source of truth that all skills reference — no other file needs your personal info.

3. Google Workspace CLI (optional / required for Gmail automation)

Required for /meeting (list today’s Calendar events), /cache-notes / /fill-participants (read Gemini Google Docs), /recap (Gmail + Calendar), and /mail-transcripts (Gmail → vault sync).

  1. Install gws — pick one:

    • GitHub Releases (pre-built binary)

    • brew install googleworkspace-cli

    • npm install -g @googleworkspace/cli

  2. Authenticate (browser flow):

gws auth login

Use readonly scopes for Calendar/Docs/Drive if you only read transcripts manually. For /mail-transcripts, include Gmail modify so the script can mark processed messages read (users.messages.modify).

  1. Command examples for agents are in .agents/skills/_shared/google-workspace-cli.md.

Gmail transcript automation (/mail-transcripts)

Optional but recommended if Gemini emails you Google Doc links after meetings:

  1. Create a Gmail label named exactly 🤖-ai-transcripts (includes the robot emoji).

  2. Filter Gemini “Notes: …” or “Document shared with you: … Notes by Gemini” messages into that label and keep them in Inbox (the script query is label:🤖-ai-transcripts in:inbox).

  3. Customize routing in .scripts/gmail_ai_transcripts_to_meetings.py — edit resolve_path() to match your Meetings/ folder layout (defaults target Meetings/Engineering/…).

  4. Run /mail-transcripts or let /meeting wrap call it as step 1.

Full setup details: .agents/skills/mail-transcripts/SETUP.md.

NOTE
Google Workspace is not exposed via MCP in this vault — agents run gws in the terminal. Cursor loads QMD from .cursor/mcp.json only.

4. QMD vault search (optional)

Required for /recap and vault-wide search. QMD indexes your markdown files for keyword and semantic search.

npx qmd collection add . --name my_vault
npx qmd embed

The npx qmd mcp server (configured in .cursor/mcp.json) will serve searches from this index. Re-run npx qmd embed after adding significant new content.

5. Vault structure

The vault ships with these directories already in place:

Meetings/                      Meeting notes (subfolders per team/project)
Meetings/_inbox/               Untriaged stubs from /mail-transcripts
Meetings/Engineering/Scrum/    Daily standups, sprint ceremonies (example layout)
Meetings/One-on-ones/          1:1 notes
Meetings/Interviews/           Interview notes
Teams/People/                  Person files: @Name.md (example: @Me, @Jane Doe)
Teams/                         Team files: +TeamName.md
Templates/                     Obsidian templates
Meetings.base / People.base    Bases views (Pending, Inbox, OneOnOnes, …)
memory/                        Optional agent memory (see feedback_meeting-routing.md.example)

Example people files @Me.md, @Jane Doe.md, and @Alex Kim.md ship with the template. Replace or extend them as you onboard real colleagues. Add subfolders under Meetings/ to match your org (the defaults use Meetings/Engineering/).

6. Open in Obsidian + Cursor

Open the vault folder in both Obsidian (for viewing/editing notes) and Cursor (for running agent skills). Cursor will auto-load MCP servers from .cursor/mcp.json (this repo ships QMD only) and the rules from .cursor/rules/. Install and log in to gws separately for Google Workspace features.

In Obsidian, hide non-vault folders from the file explorer: go to Settings → Files & Links → Excluded files and add node_modules.

Obsidian plugins

The vault works with vanilla Obsidian, but these community plugins power specific features. Install whichever you need from Settings → Community plugins → Browse.

Required
PluginIDUsed by
Tasksobsidian-tasks-pluginToDo's.md queries, task checkboxes & priorities elsewhere in the vault
Update modified datefrontmatter-modified-dateAuto-updates modified: in YAML frontmatter when you edit a note
PluginIDWhat it adds
Natural Language Datesnldates-obsidianType @today or @next Monday to insert date links — handy for task due dates
CalendarcalendarSidebar calendar widget for navigating daily/meeting notes by date
DataviewdataviewQuery engine for vault data — tables, lists, and tasks from frontmatter and inline fields
Open Tab Settingsopen-tab-settingsTab deduplication and placement control — prevents the same note from opening twice
Optional (cosmetic / workflow)

These are not required by any skill but improve the day-to-day experience:

PluginIDWhat it adds
Obsidian Gitobsidian-gitAuto-backup vault to git on a schedule (alternative to /commit)
Auto Card Linkauto-card-linkPaste a URL and get a rich preview card
File Explorer Note Countfile-explorer-note-countShows note count badges on folders
Icon Folderobsidian-icon-folderCustom icons on folders and files in the explorer
Custom File Explorer Sortingcustom-sortManual sorting rules for files and folders in the explorer
Cycle Through Panescycle-through-panesCtrl/Cmd+Tab to cycle through open tabs like a browser
Optional (agent skills: Obsidian CLI + Bases)

Required for the meeting wrap pipeline — not optional if you use /meeting wrap, /note-status pending, or /cache-notes all:

FeatureID / setupAgent skill
Obsidian CLIInstall/update from the Obsidian download page; enable CLI support per helpobsidian-cli
BasesCore — open Meetings.base once to indexobsidian-bases
CanvasCorejson-canvas
Obsidian Flavored MarkdownCoreobsidian-markdown

The defuddle skill uses the Defuddle CLI (npm install -g defuddle), not an Obsidian plugin.

Updates

If you forked or cloned this repo into a private vault, you can pull structural updates (skills, rules, shared conventions) without overwriting your personal data.

# First time — add the upstream remote
git remote add upstream <url-to-this-repo>

# Pull updates (auto-configures merge driver on first run)
./.scripts/sync-upstream.sh

# Preview what's new without merging
./.scripts/sync-upstream.sh --preview

You can also run /sync-upstream-obsidianos from any supported agent — it wraps the same script with an interactive preview and merge flow.

Personal paths are protected during merges via .gitattributes — your USER.md, Tracker.md, .env, .cursor/mcp.json, Meetings/, Teams/, Templates/, and Recaps/ are always kept as-is. Edit .gitattributes to add or remove protected paths.

Project structure

.agents/skills/       Skill definitions (SKILL.md + supporting scripts)
.agents/rules/        Shared rules (single source of truth for all agents)
.claude/skills/       Symlink → .agents/skills (Claude Code discovery)
.cursor/rules/        Cursor rules (auto-injected by glob; point to .agents/rules/)
.cursor/mcp.json      MCP configuration (QMD vault search)
.cursor/skills/       Symlink → .agents/skills (Cursor)
.opencode/skills/     Symlink → .agents/skills (OpenCode)
skills/               Symlink → .agents/skills (OpenClaw workspace skills)
AGENTS.md             Agent reference: skills, conventions, vault layout
CONTRIBUTING.md       How to add skills, run tests, and avoid personal data
CLAUDE.md             Claude Code instructions + MCP setup
OpenCode.md           OpenCode / Crush instructions + MCP setup
USER.md               Vault owner identity (fill in after cloning)
Templates/            Obsidian note templates

License

MIT

.agents/skills/obsidian-bases/SKILL.md


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. license: MIT

Obsidian Bases Skill

Usage

Use when the user works with .base files, Bases views (table, cards, list, map), filters, formulas, or summaries in Obsidian.

Workflow

  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

Schema

Base 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

Filter Syntax

Filters narrow down results. They can be applied globally or per-view.

Filter Structure
# 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
OperatorDescription
==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
PropertyTypeDescription
file.nameStringFile name
file.basenameStringFile name without extension
file.pathStringFull path to file
file.folderStringParent folder path
file.extStringFile extension
file.sizeNumberFile size in bytes
file.ctimeDateCreated time
file.mtimeDateModified time
file.tagsListAll tags in file
file.linksListInternal links in file
file.backlinksListFiles linking to this file
file.embedsListEmbeds in the note
file.propertiesObjectAll 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.

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, "")'

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.

FunctionSignatureDescription
date()date(string): dateParse string to date (YYYY-MM-DD HH:mm:ss)
now()now(): dateCurrent date and time
today()today(): dateCurrent date (time = 00:00:00)
if()if(condition, trueResult, falseResult?)Conditional
duration()duration(string): durationParse duration string
file()file(path): fileGet file object
link()link(path, display?): LinkCreate 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.

# 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
# 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
views:
  - 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
Map View

Requires latitude/longitude properties and the Maps community plugin.

views:
  - type: map
    name: "Locations"
    # Map-specific settings for lat/lng properties

Default Summary Formulas

NameInput TypeDescription
AverageNumberMathematical mean
MinNumberSmallest number
MaxNumberLargest number
SumNumberSum of all numbers
RangeNumberMax - Min
MedianNumberMathematical median
StddevNumberStandard deviation
EarliestDateEarliest date
LatestDateLatest date
RangeDateLatest - Earliest
CheckedBooleanCount of true values
UncheckedBooleanCount of false values
EmptyAnyCount of empty values
FilledAnyCount of non-empty values
UniqueAnyCount of unique values

Complete Examples

Task Tracker Base
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
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
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

Embedding Bases

Embed in Markdown files:

![[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.

# 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")'
Common Formula Errors

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"

References

110 files · 7 not served here

Advantages

  • Provides a unified, agent-agnostic framework that works across multiple AI clients like Cursor and Claude Code. evidence: README.md
  • Automates repetitive meeting wrap-up tasks, reducing manual overhead for documentation. evidence: README.md

Limitations

  • Requires several external dependencies including the Obsidian CLI, Google Workspace CLI, and QMD to function fully. evidence: README.md
  • Some features, such as Gmail transcript automation, require specific Google Workspace API scopes and manual configuration. evidence: README.md

Security

Risk level: Medium risk

This brain runs

Agent instructions that run or fetch something (71)

  • .agents/skills/cache-notes/SKILL.md: If the target file has an **empty `Notes:` property** (no URLs yet), run **`/mail-transcripts`** first when doing a full wrap (see [meeting](../meeting/SKILL.md) Mode C) — it may populate `Notes:` from the Gemini inbox mail.
  • .agents/skills/cache-notes/SKILL.md: Run **`gws`** in the terminal to fetch the document (read-only).
  • .agents/skills/cache-notes/SKILL.md: **Implementation**: Use the [otter-fetch](../otter-fetch/SKILL.md) skill — ask the user to paste the JSON from `GET .../speech?otid=...`, then run `parse_otter.js` (or parse inline) to produce the callouts above and append them.
  • .agents/skills/cache-notes/SKILL.md: To check whether the body already has an `## 🤖 AI Notes` section without reading the whole file, run `obsidian outline path="<file>" format=json` and look for that heading — much cheaper than a full `Read` on large transcript files.
  • .agents/skills/cache-notes/SKILL.md: **For each URL in `Notes:`**, fetch and parse by provider: · uses the network
  • .agents/skills/cache-notes/SKILL.md: run `otter-fetch/parse_otter.js` or parse inline), then append the resulting callout block.
  • .agents/skills/commit/SKILL.md: Run in parallel:
  • .agents/skills/commit/SKILL.md: `git diff --staged --stat` — staged changes
  • .agents/skills/commit/SKILL.md: `git diff --stat` — unstaged changes
  • .agents/skills/commit/SKILL.md: `git status --short` — untracked files
  • .agents/skills/commit/SKILL.md: `git log --oneline -5` — recent commits (for style and amend safety)
  • .agents/skills/commit/SKILL.md: If unrelated files are staged, unstage them first (`git restore --staged <path>`).
  • .agents/skills/commit/SKILL.md: Analyze the staged diff (`git diff --staged`) and write:
  • .agents/skills/commit/SKILL.md: **Normal mode**: `git commit` with the confirmed message.
  • .agents/skills/commit/SKILL.md: **Amend mode**: `git commit --amend` (see safety rules below).
  • .agents/skills/commit/SKILL.md: **HEAD was created by you** in this conversation — check `git log -1`.
  • .agents/skills/commit/SKILL.md: If `git status` fails, skip entirely without error.
  • .agents/skills/defuddle/SKILL.md: If not installed: `npm install -g defuddle`
  • .agents/skills/fill-participants/SKILL.md: Run [/note-status pending --step=participants](../note-status/SKILL.md#pending-mode) to discover notes missing `Participants:`, present them, and let the user select which to process.
  • .agents/skills/fill-participants/SKILL.md: run `parse_otter.js` or parse inline).
  • .agents/skills/fill-participants/SKILL.md: If `git status` fails, skip the commit step entirely without error.
  • .agents/skills/followup-todos/SKILL.md: `/followup-todos` (no args) — Run [/note-status pending --step=todos](../note-status/SKILL.md#pending-mode) to show meetings missing follow-up extraction.
  • .agents/skills/mail-transcripts/SKILL.md: **`/mail-transcripts`** — Run the Gmail → vault sync **once** (no arguments).
  • .agents/skills/mail-transcripts/SKILL.md: From the **vault root**, run:
  • .agents/skills/mail-transcripts/SKILL.md: python3 .scripts/gmail_ai_transcripts_to_meetings.py
  • .agents/skills/mail-transcripts/SKILL.md: When `/mail-transcripts` is run **standalone**, offer [/commit](../commit/SKILL.md).
  • .agents/skills/mail-transcripts/SKILL.md: When run **inside** `/meeting wrap` or `/meeting wrap pending`, the parent sequence commits once at the end (include any new/updated meeting files in that commit scope).
  • .agents/skills/meeting/SKILL.md: **Run `/note-status pending [<dates>]`** — Discovers meeting files, filters to notes with any missing step, presents the status table, and prompts the user to select which meetings to wrap.
  • .agents/skills/meeting/SKILL.md: **For each selected meeting**, run the Mode C wrap sequence starting at step 2 (`/cache-notes` → `/fill-participants` → `/followup-todos`).
  • .agents/skills/migrate-tags/SKILL.md: `/migrate-tags --dry-run` — Show what would change without writing.
  • .agents/skills/migrate-tags/SKILL.md: Read the file body, collect all `#tag` patterns (respecting word boundaries — `#tag` not `https://foo.com/path#section`). · uses the network
  • .agents/skills/migrate-tags/SKILL.md: Run `obsidian property:read name=tags path="<file>"` on each migrated file to confirm the write.
  • .agents/skills/note-status/SKILL.md: Run the standard workflow (Steps 1–4 above) with the given `[dates]` or `all` if omitted.
  • .agents/skills/obsidian-bases/SKILL.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()` …[+244 chars] · uses the network
  • .agents/skills/obsidian-cli/SKILL.md: Run `obsidian help` to see all available commands.
  • .agents/skills/obsidian-cli/SKILL.md: Run JavaScript in the app context:
  • .agents/skills/obsidian-cli/SKILL.md: Run `obsidian help` to see additional developer commands including CDP and debugger controls.
  • .agents/skills/onboard-person/SKILL.md: Run `obsidian property:read name=FullName path="Teams/People/@<Name>.md"` to confirm the write.
  • .agents/skills/organize-meetings/SKILL.md: The skill does not modify frontmatter — it only moves files (`git mv`) and updates the H1 inside when renaming.
  • .agents/skills/organize-meetings/SKILL.md: **Otherwise, run qmd-vector_search** on the title — return top 5 most similar meeting paths.
  • .agents/skills/organize-meetings/SKILL.md: `git mv "<old path>" "<new path>"` — preserves history.
  • .agents/skills/otter-fetch/SKILL.md: It's a sub-skill: `/cache-notes` and `/fill-participants` invoke its workflow (and run `parse_otter.js`) when a meeting's `Notes:` contains an `https://otter.ai/u/...` URL.
  • .agents/skills/otter-fetch/SKILL.md: **Ask the user** to copy the JSON response from `GET https://otter.ai/forward/api/v1/speech?otid={otid}` (e.g. from DevTools → Network while signed in, or from a signed-in request). · uses the network
  • .agents/skills/otter-fetch/SKILL.md: | Use case | What to use | How | |----------|-------------|-----| | **cache-notes** | Callout markdown | Run `parse_otter.js` with JSON on stdin → stdout is `## 🤖 AI Notes` / `### Otter` block with `[!otter_notes]-`, `[!otter_todos]-`, `[!otter_transcript]-`.
  • .agents/skills/otter-fetch/SKILL.md: node .agents/skills/otter-fetch/parse_otter.js < pasted.json
  • .agents/skills/people-stubs/SKILL.md: Run `obsidian unresolved format=json` and filter to entries where the link target starts with `@`.
  • .agents/skills/people-stubs/SKILL.md: Use `obsidian create path="Teams/People/@<Name>.md" content="<frontmatter>"` so Obsidian indexes it immediately (the next `/vault-health` run won't show the link as unresolved any more).
  • .agents/skills/people-stubs/SKILL.md: - Or run /onboard-person <name> to pull metadata from external sources.
  • .agents/skills/qmd/SKILL.md: !`qmd status 2>/dev/null || echo "Not installed: npm install -g @tobilu/qmd"`
  • .agents/skills/qmd/SKILL.md: curl -X POST http://localhost:8181/query \ · uses the network
  • .agents/skills/recap/SKILL.md: Run the following in parallel where possible:
  • .agents/skills/recap/SKILL.md: For each selected `id`, run `gws gmail users messages get` with `"format":"full"`.
  • .agents/skills/sprint-retro/SKILL.md: If you encounter one while gathering context, flag it and offer to `git mv` it into the canonical form (updating any `[[wikilinks]]` that reference the old name).
  • .agents/skills/sprint-retro/SKILL.md: Confirm the resolved sprint number and `start..end` window with the user if anything is ambiguous (missing prior retro, irregular cadence, mid-sprint run).
  • .agents/skills/sprint-retro/SKILL.md: **Naming consistency** — if you touch sibling planning/retro files with non-canonical names, normalize them via `git mv` and fix referencing wikilinks (see the convention section).
  • .agents/skills/sync-upstream-obsidianos/SKILL.md: Shortcut to run [`.scripts/sync-upstream.sh`](../../../.scripts/sync-upstream.sh).
  • .agents/skills/sync-upstream-obsidianos/SKILL.md: Verify `upstream` remote exists: `git remote get-url upstream`.
  • .agents/skills/sync-upstream-obsidianos/SKILL.md: Verify working tree is clean (`git status --short`).
  • .agents/skills/sync-upstream-obsidianos/SKILL.md: Run `.scripts/sync-upstream.sh --preview` and show the output (new commits and changed files).
  • .agents/skills/sync-upstream-obsidianos/SKILL.md: On confirmation, run the full sync:
  • .agents/skills/sync-upstream-obsidianos/SKILL.md: The final commit (`git log -1 --oneline`).
  • .agents/skills/vault-health/SKILL.md: `/vault-health` — Run all checks, present a triage report.
  • .agents/skills/vault-health/SKILL.md: Run only the requested subset;
  • .agents/skills/workspace-mode/SKILL.md: No args → run `obsidian workspace format=json` and present the list with the current one starred.
  • .agents/skills/workspace-mode/SKILL.md: `<name>` arg → run `obsidian workspace load name=<name>` (or use the Obsidian "Workspaces: Load workspace" command if `load` isn't a direct subcommand: `obsidian command name="Workspaces: Load workspace layout"`).
  • .agents/skills/workspace-mode/SKILL.md: `save <name>` → run `obsidian command name="Workspaces: Save layout"` then prompt for the name in Obsidian's modal.
  • AGENTS.md: **QMD** — Configured in [.cursor/mcp.json](.cursor/mcp.json) for vault search (MCP server `npx qmd mcp`).
  • AGENTS.md: **Google Workspace** — Use the **`gws` CLI** ([Google Workspace CLI](https://github.com/googleworkspace/cli)) for Docs, Drive, Calendar, and Gmail in read-only workflows. · uses the network
  • AGENTS.md: git remote add upstream <url-to-this-repo>
  • AGENTS.md: ./.scripts/sync-upstream.sh # auto-configures merge driver on first run
  • CLAUDE.md: Install and authenticate per [README.md](README.md) § Google Workspace CLI.

MCP servers (1)

  • .cursor/mcp.json (qmd): npx qmd mcp
  • Medium risk: runs-instruction-instruction-network (.agents/skills/cache-notes/SKILL.md:117)
  • Medium risk: runs-instruction-instruction-network (.agents/skills/migrate-tags/SKILL.md:54)
  • Medium risk: runs-instruction-instruction-network (.agents/skills/obsidian-bases/SKILL.md:184)
  • Medium risk: runs-mcp-server-unpinned-runner (.cursor/mcp.json)
  • Medium risk: runs-instruction-instruction-network (AGENTS.md:113)
  • Low risk: network-instructions (.agents/skills/defuddle/SKILL.md:11)
  • Low risk: scripts-present (.agents/skills/otter-fetch/parse_otter.js)
  • Low risk: network-instructions (.agents/skills/qmd/SKILL.md:5)
  • Low risk: scripts-present (.scripts/gmail_ai_transcripts_to_meetings.py)
  • Low risk: scripts-present (.scripts/test_gmail_ai_transcripts.py)

Attribution and licence

First committed by
GitHub avatar of benororbenoror
Declared authors
  • ObsidianOS contributors (declared in package.json)
Publisher
Ben Orozco (Community)
Source
benoror/obsidianos_work · commit 3c7923e
Licence
MIT License (files served here)
  • ATTRIBUTION.md (written by AutoGineer)
Synced
Contributors
benoror

AutoGineer is not affiliated with or endorsed by benoror.

Install from source

7 of its files are not served here, so there is no ZIP. benoror/obsidianos_work at 3c7923e