
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 withnote.. - They use raw
mvcommands 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:
- Hardened Syntax & Edge-Case Guardrails across the original three skills (
obsidian-markdown,obsidian-bases,json-canvas). - 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.

| Skill | Category | Primary Responsibility | Key Addition / Latest Guardrail |
|---|---|---|---|
obsidian-markdown | File Format (.md) | Obsidian Flavored Markdown, wikilinks, embeds, callouts, frontmatter | Obsidian 1.14.1+ colored highlights (==🔴text==), table alias pipe escaping ([[Note\|Alias]]), and non-numeric tag rules (#1984book) |
obsidian-bases | Database Views (.base) | Filters, formulas, summaries, table/card views, inline base blocks | note. property prefixing for displayName, empty displayName fallback behavior, and .days duration math |
json-canvas | Visual Maps (.canvas) | JSON Canvas nodes, edges, groups, spatial layout coordinates | CJK 1.5× width multipliers, strict \" quote escaping, and avoiding obsidian create newline corruption |
obsidian-cli | Desktop IPC (obsidian) | Controlling a live Obsidian desktop instance, link-safe moves, plugin dev | Link-updating rename/move, eval / DOM inspection, screenshot capture, and parameter placement rules |
obsidian-headless | Server / CI CLI (ob) | Running Obsidian Sync and Obsidian Publish without a GUI | E2EE vault setup, continuous background daemon sync, and --dry-run / --yes automated publishing |
defuddle | Web Ingestion (defuddle) | Extracting clean Markdown & metadata from cluttered HTML pages | Strips navbars/ads to save context tokens; emits clean --md or structured --json payloads |
knap | Templating (knap) | Rendering Markdown notes from JSON/CSV data and templates | yaml_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:
- 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==
- 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]] |
- Strict Filename Link Resolution & YAML Quoting: The skill clarifies that links resolve strictly by file name, never by the
aliasesfrontmatter 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.inproperties:: If an agent definesdisplayNameunderproperties: status:, Obsidian silently ignores it and displays the raw property name. Frontmatter properties must be prefixed withnote.:
properties:
note.status:
displayName: "Status"
formula.reading_time:
displayName: "Est. Time"
- Duration Arithmetic: Subtracting two dates in a Base formula returns a
Durationobject, not a number. Calling.round(0)directly on(now() - file.ctime)fails; agents must access.daysor.hoursfirst:
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
.canvasfiles directly to disk rather than passing them throughobsidian create content=..., which converts every\nescape 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
0even 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, andobsidian 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
- Per-Skill Atomic
rsync: Rather than overwriting the entire~/.agents/skills/folder, the script iterates overplugins/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. - Provenance Stamping (
SOURCE.txt): Every synced skill folder receives aSOURCE.txtmetadata stamp recording the exact GitHub repository URL, short commit SHA (3981277), and adoption date. - Zero-Noise Audit Logging: When
OLD_COMMIT != NEW_COMMIT, the script automatically appends an audit entry toMeta/agent-log.mdinside the Obsidian vault so you have a permanent record of when upstream skill definitions changed. - Persistent Weekly
systemdTimer: Runningbash ~/scripts/sync_obsidian_skills.sh --setup-weeklyprovisions and enablesobsidian-skills-sync.timer(Mon *-*-* 03:15:00withPersistent=true). If the workstation is asleep on Monday morning,systemdtriggers 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.