Teaching Claude Code to Write Real Obsidian Notes: Adding kepano’s obsidian-skills to a Self-Maintained Memory

By | November 9, 2026

This is the fifth post in my series on giving Claude Code a long-term memory in Obsidian. The earlier posts covered session archiving and context injection, sub-second vault search, self-curating memory and out-of-band “dreaming”. Together they let the agent read from my vault and write to it on its own.

Something was still missing: the agent writes notes, but it doesn’t really write Obsidian notes. Ask a model for a note and you get generic Markdown. Links are file paths or plain text, warnings are bold paragraphs, and related notes are listed as names instead of [[wikilinks]]. It renders, but it isn’t connected. The graph view stays empty, backlinks don’t appear, and renaming a note breaks every path that points to it.

Then Steph Ango (kepano), Obsidian’s CEO, published obsidian-skills, a set of Agent Skills that teach an AI Obsidian’s own formats. This post covers which ones I adopted, how I installed them, and how I wired them into the memory system so they change what the agent actually produces.


1. What’s in the Repo

The repo holds six skills. Each one is a SKILL.md with a short description and the instructions, and some have reference files the agent loads only when needed:

SkillWhat it teachesNeeds
obsidian-markdownObsidian Flavored Markdown: wikilinks, embeds, callouts, properties, block IDs, comments, highlightsnothing
obsidian-bases.base files: database-style table, card and list views over notes, with filters and formulasnothing
json-canvas.canvas files: nodes, edges, groups, layout rules, a validation checklistnothing
obsidian-clidriving a running Obsidian through the official obsidian CLIthe Obsidian CLI
defuddleextracting clean Markdown from web pagesan npm tool
knaprendering Markdown templates from JSON or CSVan npm tool

The first three are pure knowledge, mostly syntax tables, worked examples and lists of common mistakes. The last three are wrappers around external tools.


2. Picking What Fits

I applied the same filter I use for every addition to this setup: does it change what the agent produces, and does it overlap something that already works?

  • obsidian-markdown: yes. This is the gap I described at the top. The agent writes Knowledge/ notes through write-note and edits them during curation, and this skill makes those notes proper Obsidian notes.
  • obsidian-bases and json-canvas: yes, cheaply. They cost nothing until used, and when I ask for “a table of every note the agent wrote” or “a diagram of this flow”, the result is a native .base or .canvas instead of a Markdown table or an ASCII diagram.
  • obsidian-cli: no. I don’t have the Obsidian CLI installed, and the vault-search post already gives the agent ranked search through Omnisearch, with a fallback that works when Obsidian is closed. A second path into the same vault would be one more thing to maintain.
  • defuddle and knap: no. They’re useful tools, but they deal with web clipping and templating, not with agent memory.

3. Installing: Pinned, Global, No Auto-Update

The README offers three install paths: the Claude Code plugin marketplace, npx skills add, or copying the folder into the vault’s .claude/ directory. I used none of them as written.

Why not the vault’s .claude/? Claude Code loads project skills from the directory it starts in. My sessions start in code repositories, not in the vault, so skills inside the vault would almost never load. They need to be global: ~/.claude/skills/.

Why not the marketplace? A marketplace plugin follows the upstream repo, and a skill is instructions the agent follows. That’s normally fine, since this is a trustworthy author. But my agent works on code I’m responsible for, and I don’t want its instructions to change without me reading the change. So I treat skills like any other dependency: read them, pin a version, upgrade on purpose.

git clone --depth 1 https://github.com/kepano/obsidian-skills /tmp/obsidian-skills
cd /tmp/obsidian-skills && git log -1 --format=%h      # note the commit

for s in obsidian-markdown obsidian-bases json-canvas; do
  cp -r "skills/$s" ~/.claude/skills/
  printf 'Source: https://github.com/kepano/obsidian-skills (MIT)\nPinned commit: <hash>. Copied, not a marketplace plugin: no auto-update.\n' \
    > ~/.claude/skills/$s/SOURCE.txt
done
cp LICENSE ~/.claude/skills/obsidian-markdown/

Before copying I read every file. These three skills are documentation only, with no scripts and no commands to run, which is part of why they were easy to adopt. The SOURCE.txt next to each skill records where it came from, so upgrading later is just a diff between two commits.

Global skills load everywhere Claude Code runs, so they also work in the Claude extension inside Cursor, which is where many of my sessions start.


4. Wiring It into the Memory System

Installing a skill makes it available. Whether the model uses it depends on its description matching the task. “Use when working with .md files in Obsidian” fits a request like “write me a note”, but it’s less certain to trigger when the agent calls write-note from the middle of a debugging session, where the note is a side effect rather than the task.

In the self-curating memory post I set a rule: every directive gets a mechanism. Here the mechanism is a reference at the two points where the agent writes notes.

At write time, in the global ~/.claude/CLAUDE.md, next to the write-note documentation:

Note syntax: write vault notes (`write-note` bodies, Knowledge/ notes) as Obsidian Flavored Markdown per the
`obsidian-markdown` skill: `[[wikilinks]]` for vault notes, callouts for warnings/gotchas, list-style `tags`.
The `obsidian-bases` / `json-canvas` skills cover `.base` and `.canvas` files.

At curation time, a new step in the curate-memory skill, so older notes get fixed whenever the agent touches them anyway:

- **SYNTAX**: while editing an agent-written note, fix non-Obsidian syntax per the `obsidian-markdown` skill
  (plain-path links → `[[wikilinks]]`, "Note:/Warning:" paragraphs → callouts).

The curation skill’s ownership rule still applies: it only edits notes with author: claude-code. The agent fixes the syntax of its own notes, never mine.

What a Note Looks Like Now

A typical model-written procedure note, without the skill (an illustrative example):

# Resetting the local message broker

Warning: this deletes all local topics.

See Knowledge/Local dev environment.md for the ports.

With the skill in context:

---
type: knowledge
author: claude-code
created: 2026-11-09
tags: [dev-env, messaging]
---

# Resetting the local message broker

> [!warning] Destructive
> Deletes every local topic and consumer offset.

Ports and container names are in [[Local dev environment#Ports]].

The callout renders as a warning box, and the link shows up in backlinks and the graph, survives renames and goes straight to the heading.

What Didn’t Need to Change

I checked the frontmatter my scripts generate (type, author, created, updated, source-session, tags: [a, b]) against the skill’s properties reference. It was already valid: flow-style YAML lists are proper list properties in Obsidian. The scripts didn’t need any change. The skill covers the part a script can’t write: the body.


5. Bases as a View on the Agent’s Memory

obsidian-bases has an obvious use in this setup. The audit file Meta/claude-authored.md lists every note the agent created, but a Base can show the same thing live from the notes’ own properties. You can sort it and open notes from it, and it never goes out of date:

filters:
  and:
    - 'author == "claude-code"'
    - 'type == "knowledge"'
formulas:
  days_since_update: 'if(updated, (today() - date(updated)).days, "")'
views:
  - type: table
    name: "Agent-written notes"
    order:
      - file.name
      - tags
      - created
      - updated
      - formula.days_since_update
      - source-session

Save it as Meta/agent-notes.base and embed it anywhere with ![[agent-notes.base]]. A “stale notes” view, filtering on days_since_update > 90, would complement the curation report from the earlier post. Note the .days access: subtracting two dates gives a Duration, not a number. That’s exactly the kind of detail the skill exists to teach, and one a model gets wrong without it.


6. Security Notes

  1. Skills are instructions, so treat them as code. Read them before installing, pin a commit, and upgrade deliberately.
  2. Prefer knowledge-only skills. The three I adopted contain no scripts. A skill that installs or runs tools (npm install -g …) increases what you’re trusting, so add it only when you need the tool.
  3. The data boundary doesn’t move. These skills change how notes are formatted, not what gets recorded. Redaction on every write path and the “what not to record” rules from the earlier posts still apply.

7. Lessons

  1. Formatting is part of memory quality. A fact the agent records but never links is a fact I’ll never stumble upon. Wikilinks are what make a pile of notes into a knowledge base.
  2. Borrow knowledge, keep your mechanisms. The skill knows Obsidian’s syntax. My setup knows when the agent writes. Adding a reference where the two meet is a two-line change.
  3. Install where the agent actually runs. “Put it in the vault” is the right advice when the vault is your working directory. When your sessions start in code repositories, the skill has to be global.
  4. Adopt less than what’s offered. Three of the six skills fit, and leaving the other three out kept the setup small.

With this in place, the agent records its own memory, keeps it tidy, consolidates it overnight, and writes it in Obsidian’s own syntax.

Leave a Reply

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