Equipping Local AI Agents with Official Obsidian Skills: From Bases and Headless Sync to Defuddle and Knap Pipelines

By | November 15, 2026
Equipping Local AI Agents with Official Obsidian Skills

In The Autonomous Homelab: Building a State-of-the-Art Local AI Agent Architecture and Hardening Local AI Agents: Procedural Skills, Mistake Ledgers, and Real-Time Verification, we explored how local AI coding assistants (Google Antigravity (agy), Claude Code, Codex, and OpenCode) rely on an Obsidian vault as their persistent, human-inspectable cognitive core.

Yet giving an LLM filesystem access to an Obsidian vault is only half the battle. Without explicit domain grammars, even frontier models routinely stumble over Obsidian-specific syntax and tooling:

  • They write unescaped pipe characters inside Markdown table wikilinks ([[Note|Alias]]), shattering table rendering.
  • They try to hide an Obsidian Base column header by setting displayName: "" or forget to prefix frontmatter keys with note..
  • They use raw mv commands on the filesystem instead of the Obsidian CLI, silently breaking dozens of inbound backlinks across the vault.
  • They dump raw, ad-bloated HTML into notes instead of extracting clean Markdown and piping it through structured templates.

To solve this across the ecosystem, Steph Ango (kepano) and the Obsidian team maintain the official obsidianmd/obsidian-skills repository—a vendor-neutral collection of agent skills following the open Agent Skills specification.

Originally launched with three foundational syntax guides (obsidian-markdown, obsidian-bases, and json-canvas), the repository has recently expanded into a comprehensive 7-skill suite that adds native desktop control (obsidian-cli), daemonized server synchronization (obsidian-headless), token-saving web extraction (defuddle), and data-driven template rendering (knap).

In this post, we will break down all seven skills in the updated obsidianmd/obsidian-skills repository, examine the critical syntax refinements in the latest commits, and build an automated weekly systemd synchronization pipeline so your local agents never fall behind upstream improvements.


1. What Changed in obsidianmd/obsidian-skills?

If you adopted obsidian-skills when it first appeared under kepano/obsidian-skills, your local ~/.agents/skills/ or ~/.claude/skills/ directory likely contains only the initial trio of file-format skills.

Comparing that early snapshot against the current main branch of obsidianmd/obsidian-skills reveals two major evolutions:

  1. Hardened Syntax & Edge-Case Guardrails across the original three skills (obsidian-markdown, obsidian-bases, json-canvas).
  2. Four Brand-New CLI & Pipeline Skills (obsidian-cli, obsidian-headless, defuddle, knap) that transform an agent from a passive text editor into a full-stack knowledge automation engine.
Official Obsidian Agent Skills & Weekly Sync Architecture
SkillCategoryPrimary ResponsibilityKey Addition / Latest Guardrail
obsidian-markdownFile Format (.md)Obsidian Flavored Markdown, wikilinks, embeds, callouts, frontmatterObsidian 1.14.1+ colored highlights (==🔴text==), table alias pipe escaping ([[Note\|Alias]]), and non-numeric tag rules (#1984book)
obsidian-basesDatabase Views (.base)Filters, formulas, summaries, table/card views, inline base blocksnote. property prefixing for displayName, empty displayName fallback behavior, and .days duration math
json-canvasVisual Maps (.canvas)JSON Canvas nodes, edges, groups, spatial layout coordinatesCJK 1.5× width multipliers, strict \" quote escaping, and avoiding obsidian create newline corruption
obsidian-cliDesktop IPC (obsidian)Controlling a live Obsidian desktop instance, link-safe moves, plugin devLink-updating rename/move, eval / DOM inspection, screenshot capture, and parameter placement rules
obsidian-headlessServer / CI CLI (ob)Running Obsidian Sync and Obsidian Publish without a GUIE2EE vault setup, continuous background daemon sync, and --dry-run / --yes automated publishing
defuddleWeb Ingestion (defuddle)Extracting clean Markdown & metadata from cluttered HTML pagesStrips navbars/ads to save context tokens; emits clean --md or structured --json payloads
knapTemplating (knap)Rendering Markdown notes from JSON/CSV data and templatesyaml_property safe frontmatter serialization, batch CSV/JSON note generation, and defuddle | knap pipelines

2. Deep-Dive Part 1: Crucial Refinements in Core Vault Syntax

Even small ambiguities in a SKILL.md file can cause recurring formatting bugs across hundreds of agent-generated notes. The latest updates to the core syntax skills close several subtle traps:

A. obsidian-markdown: Colored Highlights, Table Pipes, and Alias Resolution

Three updates in obsidian-markdown immediately improve agent note authoring:

  1. Obsidian 1.14.1+ Colored Highlights: Agents now know how to use native semantic highlight colors by placing one of six circle or square emojis (🔴, 🟠, 🟡, 🟢, 🔵, 🟣) immediately after the opening ==:
==Standard highlight==
==🔴Critical blocker or security constraint==
==🟢Verified production invariant==
  1. Escaping Wikilinks Inside Markdown Tables: Unescaped alias pipes inside tables are parsed as cell delimiters. The updated skill enforces backslash escaping (\|) and blank lines above tables:
| Component | Reference Note |
| :--- | :--- |
| Memory Dreamer | [[Out-of-Band Dreaming\|Dream Engine]] |
  1. Strict Filename Link Resolution & YAML Quoting: The skill clarifies that links resolve strictly by file name, never by the aliases frontmatter property—a bare [[Alias]] stays unresolved unless written as [[Note|Alias]]. Furthermore, wikilinks stored in YAML properties must always be quoted (related: "[[Other Note]]") so YAML parsers do not misinterpret [[...]] as a nested two-dimensional array.

B. obsidian-bases: Mastering .base Schemas and Inline Views

Obsidian Bases (.base) allow agents to build dynamic, Notion-like relational tables and card galleries over vault notes—such as our Meta/agent-notes.base telemetry dashboard. The updated obsidian-bases skill codifies two critical troubleshooting rules:

  • Prefixing note. in properties:: If an agent defines displayName under properties: status:, Obsidian silently ignores it and displays the raw property name. Frontmatter properties must be prefixed with note.:
properties:
  note.status:
    displayName: "Status"
  formula.reading_time:
    displayName: "Est. Time"
  • Duration Arithmetic: Subtracting two dates in a Base formula returns a Duration object, not a number. Calling .round(0) directly on (now() - file.ctime) fails; agents must access .days or .hours first:
formulas:
  age_days: "(now() - file.ctime).days.round(0)"

C. json-canvas: Preventing JSON Corruption and Cramped Layouts

When generating visual architecture maps in .canvas files, json-canvas now instructs agents to:

  • Write .canvas files directly to disk rather than passing them through obsidian create content=..., which converts every \n escape sequence into a literal newline and breaks JSON parsing.
  • Scale widths by 1.5× for CJK content so wide characters do not wrap prematurely inside cards.

3. Deep-Dive Part 2: The 4 New CLI & Pipeline Skills

The biggest leap in obsidianmd/obsidian-skills is the addition of four command-line tool skills that standardize how agents interact with the Obsidian runtime, remote sync servers, and external web data.

1. obsidian-cli: Link-Safe Vault Operations & Live Plugin Debugging

When the Obsidian desktop app is open, obsidian-cli teaches the agent to use the native obsidian binary rather than raw shell file manipulation:

# Rename or move notes via Obsidian CLI so all inbound [[wikilinks]] update automatically!
obsidian move path="00-Inbox/Draft Note.md" to="01-Projects/Architecture/Spec.md"

# Query backlinks, unresolved links, tags, and daily tasks
obsidian backlinks file="Spec"
obsidian links:unresolved total
obsidian daily:append content="- [ ] Review nightly dream journal"

Crucially, the skill warns the agent about CLI edge cases:

  • vault="<Name>" must be the very first parameter, whereas output flags (--json, --md, --csv) must appear after the subcommand name.
  • The CLI exits with status code 0 even when a command fails, so the agent must always inspect stdout/stderr before reporting success.
  • For plugin and theme developers, the skill unlocks headless UI inspection: obsidian plugin:reload id=my-plugin, obsidian dev:errors, obsidian dev:screenshot path=ui.png, and obsidian dev:dom selector=".workspace-leaf".

2. obsidian-headless: Zero-GUI Sync and Publishing (ob)

For homelab servers, CI/CD runners, and headless Linux boxes where no X11/Wayland desktop is running, obsidian-headless gives agents full mastery over the new Node.js 22+ ob CLI:

# Check sync status or run continuous background sync on a headless server
ob sync-status --path ~/Vault/Knowledge
ob sync --path ~/Vault/Knowledge --continuous

# Preview and publish notes marked with 'publish: true' in frontmatter
ob publish --path ~/Vault/Knowledge --dry-run
ob publish --path ~/Vault/Knowledge --yes

The skill includes strict safety guardrails: never run Desktop Sync and Headless Sync concurrently on the same device, never pass user passwords on the command line (--password), and always execute ob publish --dry-run before confirming a live site push.

3. defuddle + knap: Composable Web-to-Vault Ingestion Pipelines

Perhaps the most elegant pattern in the new skill suite is the Unix-style composition between Defuddle (defuddle) and Knap (knap).

When you ask an AI agent to clip a technical article or documentation page into your vault, fetching raw HTML wastes tens of thousands of context tokens on navigation bars, scripts, and ads. Worse, having the LLM manually format the frontmatter burns inference time and risks YAML quoting errors.

With defuddle and knap installed, the agent executes a deterministic, zero-hallucination pipeline:

# Step 1: Extract clean Markdown + structured metadata JSON via Defuddle,
# Step 2: Pipe directly into Knap to render an Obsidian note with safe YAML frontmatter!
defuddle parse "https://agentskills.io/specification" --md --json \
  | knap render ~/Vault/Templates/web-clip.knap.md --data - -o ~/Vault/03-Resources/Agent-Skills-Spec.md

Where web-clip.knap.md uses Knap's yaml_property filter to guarantee properly escaped YAML frontmatter regardless of colons or quotes in the page title:

---
{{ title | yaml_property:"title" }}
{{ domain | yaml_property:"source_domain" }}
{{ description | yaml_property:"summary" }}
tags: [resource, web-clip]
---

# {{ title | trim }}

{{ content }}

And when ingesting structured datasets—such as a CSV export of books, vinyl records, or server inventory—knap batch generates hundreds of sanitized Obsidian notes in milliseconds without a single LLM token spent on boilerplate formatting:

knap batch template.md --data inventory.csv --output-dir ~/Vault/03-Resources/Nodes \
  --filename '{{ hostname | safe_name }}.md' --dry-run

4. Staying in Sync: Automated Weekly Updates with systemd

Because obsidianmd/obsidian-skills is actively evolving alongside new Obsidian releases, manually cloning the repository once means your agents will gradually drift behind new syntax capabilities and CLI flags.

At the same time, if your local agent synthesizes its own custom skills into ~/.agents/skills/ (such as vault-search or curate-memory, as covered in Hardening Local AI Agents), you cannot simply wipe ~/.agents/skills/ and replace it with a git clone.

To keep all official Obsidian skills continuously up to date across both Google Antigravity (~/.agents/skills/) and Claude Code (~/.claude/skills/) while preserving custom local skills, we can build an idempotent synchronization script paired with a weekly systemd --user timer.

The Idempotent Sync Script (sync_obsidian_skills.sh)

We place sync_obsidian_skills.sh in ~/scripts/:

#!/usr/bin/env bash
set -euo pipefail

# sync_obsidian_skills.sh
# Clones or updates https://github.com/obsidianmd/obsidian-skills and syncs all skills
# into ~/.agents/skills/ and ~/.claude/skills/.
# Usage: bash ~/scripts/sync_obsidian_skills.sh [--check-only|--setup-weekly]

REPO_URL="https://github.com/obsidianmd/obsidian-skills.git"
CACHE_DIR="${HOME}/.cache/obsidian-skills-repo"
TARGETS=("${HOME}/.agents/skills" "${HOME}/.claude/skills")
LOG_SCRIPT="${HOME}/scripts/obsidian_memory.py"

MODE="sync"
if [[ "${1:-}" == "--check-only" ]]; then
    MODE="check"
elif [[ "${1:-}" == "--setup-weekly" ]]; then
    MODE="setup"
fi

if [[ "$MODE" == "setup" ]]; then
    UNIT_DIR="${HOME}/.config/systemd/user"
    mkdir -p "$UNIT_DIR"
    cat > "${UNIT_DIR}/obsidian-skills-sync.service" <<EOF
[Unit]
Description=Weekly Sync of Official Obsidian Agent Skills (obsidianmd/obsidian-skills)
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/bin/bash %h/scripts/sync_obsidian_skills.sh
Nice=15
EOF

    cat > "${UNIT_DIR}/obsidian-skills-sync.timer" <<EOF
[Unit]
Description=Weekly Timer for Official Obsidian Agent Skills Sync

[Timer]
OnCalendar=Mon *-*-* 03:15:00
Persistent=true
Unit=obsidian-skills-sync.service

[Install]
WantedBy=timers.target
EOF

    systemctl --user daemon-reload
    systemctl --user enable --now obsidian-skills-sync.timer
    echo "Weekly systemd timer 'obsidian-skills-sync.timer' enabled and active."
    exit 0
fi

mkdir -p "$(dirname "$CACHE_DIR")"
OLD_COMMIT=""
if [[ -d "${CACHE_DIR}/.git" ]]; then
    OLD_COMMIT=$(git -C "$CACHE_DIR" rev-parse --short HEAD 2>/dev/null || true)
    git -C "$CACHE_DIR" fetch --quiet origin main
    REMOTE_COMMIT=$(git -C "$CACHE_DIR" rev-parse --short origin/main)
    if [[ "$MODE" == "check" ]]; then
        echo "Local cached commit: ${OLD_COMMIT:-none}, Remote origin/main: ${REMOTE_COMMIT}"
        exit 0
    fi
    git -C "$CACHE_DIR" reset --hard --quiet origin/main
else
    if [[ "$MODE" == "check" ]]; then
        REMOTE_COMMIT=$(git ls-remote "$REPO_URL" refs/heads/main | awk '{print substr($1,1,7)}')
        echo "Not cached locally yet. Remote origin/main: ${REMOTE_COMMIT}"
        exit 0
    fi
    rm -rf "$CACHE_DIR"
    git clone --quiet --depth 1 "$REPO_URL" "$CACHE_DIR"
fi

NEW_COMMIT=$(git -C "$CACHE_DIR" rev-parse --short HEAD)
SYNC_DATE=$(date +%Y-%m-%d)
SKILLS_SRC="${CACHE_DIR}/plugins/obsidian/skills"

if [[ ! -d "$SKILLS_SRC" ]]; then
    echo "Error: Expected skills directory not found at $SKILLS_SRC" >&2
    exit 1
fi

UPDATED_SKILLS=()
for skill_path in "$SKILLS_SRC"/*/; do
    [[ -d "$skill_path" ]] || continue
    skill_name=$(basename "$skill_path")
    UPDATED_SKILLS+=("$skill_name")
    for target_root in "${TARGETS[@]}"; do
        mkdir -p "${target_root}/${skill_name}"
        rsync -a --delete "$skill_path" "${target_root}/${skill_name}/"
        cat > "${target_root}/${skill_name}/SOURCE.txt" <<EOF
Source: https://github.com/obsidianmd/obsidian-skills
Commit: ${NEW_COMMIT}
Adopted: ${SYNC_DATE}
EOF
    done
done

echo "Synced ${#UPDATED_SKILLS[@]} skills (${UPDATED_SKILLS[*]}) at commit ${NEW_COMMIT}."

if [[ "$OLD_COMMIT" != "$NEW_COMMIT" ]] && [[ -f "$LOG_SCRIPT" ]]; then
    python3 "$LOG_SCRIPT" log "Synced obsidianmd/obsidian-skills (${OLD_COMMIT:-initial} -> ${NEW_COMMIT}): ${UPDATED_SKILLS[*]}" >/dev/null 2>&1 || true
fi

How It Works

  1. Per-Skill Atomic rsync: Rather than overwriting the entire ~/.agents/skills/ folder, the script iterates over plugins/obsidian/skills/*/ in the upstream cache and syncs each individual skill folder (rsync -a --delete). Custom procedural skills (curate-memory, vault-search, etc.) remain untouched side by side.
  2. Provenance Stamping (SOURCE.txt): Every synced skill folder receives a SOURCE.txt metadata stamp recording the exact GitHub repository URL, short commit SHA (3981277), and adoption date.
  3. Zero-Noise Audit Logging: When OLD_COMMIT != NEW_COMMIT, the script automatically appends an audit entry to Meta/agent-log.md inside the Obsidian vault so you have a permanent record of when upstream skill definitions changed.
  4. Persistent Weekly systemd Timer: Running bash ~/scripts/sync_obsidian_skills.sh --setup-weekly provisions and enables obsidian-skills-sync.timer (Mon *-*-* 03:15:00 with Persistent=true). If the workstation is asleep on Monday morning, systemd triggers the sync immediately upon wake.

We can verify the live installation and timer state directly from the terminal:

$ bash ~/scripts/sync_obsidian_skills.sh
Synced 7 skills (defuddle json-canvas knap obsidian-bases obsidian-cli obsidian-headless obsidian-markdown) at commit 3981277.

$ systemctl --user list-timers obsidian-skills-sync.timer --no-pager
NEXT                        LEFT    LAST PASSED UNIT                       ACTIVATES
Mon 2026-11-16 03:15:00 EET 18h left -    -      obsidian-skills-sync.timer obsidian-skills-sync.service

5. Conclusion

An AI agent is only as fluent as the procedural grammars it can access. By adopting the full obsidianmd/obsidian-skills suite and wiring it into an automated weekly sync timer, your local agents gain immediate, always-current mastery over Obsidian Flavored Markdown, relational .base views, .canvas spatial maps, live desktop IPC, headless server synchronization, and token-efficient defuddle | knap web ingestion pipelines.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.