Tips & Tricks (Updated: 6/6/2026)

Your Obsidian Notes “Grow on Their Own” with AI. Building a Second Brain

How to half-automate linking, summarizing, and tidying scattered Obsidian notes with AI.

Your Obsidian Notes “Grow on Their Own” with AI. Building a Second Brain

Midnight, and I was typing “what was that command again” into Obsidian’s search box.

A three-line shell command I’d noted two years ago. I knew it was in there. But which of my 500-plus notes it was buried in, I had no clue. I gave up looking that night and just googled it again.

I don’t think it’s only me.

Obsidian (a notes app) gets more useful the more you use it. But at the same time, it absolutely gets messier. Daily logs, reading notes, code fragments, article ideas, meeting notes. They all pile up as Markdown files, and within six months you’ve got “a personal, hard-to-search junk house.”

So I started doing this: let an AI read the Vault (the place your notes live) and take over maybe half the tidying. Add links, build summaries, rescue the lost notes. Run a little of this every day, and notes that were scattered start connecting on their own — it genuinely starts to feel like a “second brain.” That’s what today is about.

What does “notes that grow” even mean?

A normal note peaks the instant you write it. After that it just fades into being forgotten.

But Obsidian has a way to connect notes with the syntax [[note name]] (it’s called a Wikilink), and the more you connect, the more it becomes one big map. From a “TypeScript type error” note you can jump to “that Docker thing I got stuck on,” and from there to “last month’s incident retrospective.” Dots become lines, lines become a surface.

The problem: when a human does this linking, it’s too much hassle to keep up.

This is where the AI takes over. Specifically, I use a tool called Claude Code as the partner. It’s an AI for writing code, but really you can use it as “a clerk that can safely read and write a folder full of Markdown files.” Obsidian’s local-first goodness (your files sit on your own PC) stays intact, and you hand over just the labor of tidying. That’s the plan for today.

But let me nail one thing down first. Do not, under any circumstances, hand the whole Vault edit access to an AI.

.obsidian/ (the settings folder), already-published articles, contract-like personal notes, API keys — there’s no reason for the AI to read any of them. So my policy is “read broadly, write extremely carefully.” This is exactly the thinking from what I wrote before in how to build a safety frame for delegating to AI — basically, put the training wheels on before you let it ride.

Where this pays off (three cases)

Abstractions don’t land, so here are three moments where I actually felt “oh, this works.”

First, the morning daily log. Every morning I have the AI read yesterday’s note and ask it to “carry over only the unfinished tasks to today, and compress yesterday’s learnings into three lines.” Out comes the mess yesterday-me made, reshaped into something today-me can act on. “Ah, right, this is the thing I got stuck on” — instant recall. The person you’re handing off to is your future self.

Second, rescuing code fragments. That “command from two years ago” problem. Drop working commands into a snippets/ folder and the AI adds, on its own, an explanation of “what’s this command for?” plus links to related notes. A bare command transforms into a proper note you can actually find in search.

Third, prepping article ideas. On a day I’m writing a blog post, I show the AI the idea file in my content-ops/ folder and ask “which past articles could this one internally link to?” Sometimes it drags up an article from six months ago that even I’d forgotten — and that quietly pays off. It’s that moment when dot connects to dot.

Three accidents I caused myself

This might be the real heart of it. For the first few weeks, my Vault got trashed by the AI. I’ll lay it bare.

One. I asked it to “tidy up” the whole Vault at once. This was the worst. The AI tried to “helpfully” tidy even my cryptic two-year-old notes, sprouting a mountain of arbitrary tags and headings. The Graph view (the screen that visualizes how notes connect) became a jungle of tags I’d never seen. The AI can’t know the intent of old notes. And yet it acts on guesses. Ever since, I limit the target to exactly one folder.

Two. I let the AI rename notes on its own. “Make the titles clearer.” That snapped all my [[old note name]] links in one shot. Obsidian follows the rename if you change the name yourself, but when an external AI bulk-rewrites filenames, that follow-through doesn’t kick in. A battlefield of broken links. Now “renames must always be confirmed by a human” is an iron law.

Three. I let it read private/. This was beyond a mere cold sweat. A folder with notes on contract amounts was readable by the AI because I’d slacked on the permission config. No accident happened, but it was like letting a new hire touch the production DB barehanded. If I’d just written it into deny (the deny list), an accident would have been impossible in the first place. The lesson: it was my fault for skimping on config.

Getting started: just place three files

It’s not hard. You just prepare three things at the root of your Vault.

First, split into folders. Over-classify from the start and it always collapses, so rough is plenty.

# Run at the Vault root. Split only daily-use spots, projects, publishing work, and protected zones
mkdir -p inbox daily projects content-ops snippets templates scripts archive private

Here’s how I allocate each folder’s role and how far the AI gets to act.

FolderRoleWhat the AI may do
inbox/Catch-all for unsorted notes and web clipsRead and create new
daily/Daily logs, working notesCreate, append, summarize the previous day
projects/In-progress tasks, handoffsCreate, update, organize open items
content-ops/Article ideas, internal links, publish checksTidy drafts, check links
snippets/Code fragments and how to use themAdd explanations, organize tags
templates/Obsidian templatesAs a rule, edit only after confirming
archive/Done and storedNo editing
private/Personal info, contracts, secretsNo reading either

Next, place a CLAUDE.md at the Vault root. This is the paper that writes down “our rules” for the AI. Rather than reciting long philosophy, it works better to write the input/output rules you want honored, short.

# Rules for this Obsidian Vault

## Role
- This Vault holds daily logs, project handoffs, code fragments, and article ideas.
- Operate so you're useful without ever reading private.

## Folder policy
- `daily/`: create/update daily notes as `YYYY-MM-DD.md`.
- `projects/`: keep one handoff note per active project.
- `snippets/`: keep working commands together with their background and failure cases.
- `templates/`: reading is fine. Always ask before editing.
- `archive/` and `private/`: don't edit. Don't even summarize private contents.

## Writing rules
- Write internal links in `[[project name]]` Wikilink form.
- Put YAML properties (status, etc.) at the top of each note.
- Keep each paragraph to five lines or fewer.

## Safety rules
- Always confirm before renaming an existing note.
- Don't rewrite `.obsidian/` settings.
- Before any bulk edit, list the target files and wait for approval.
- After editing, always run `node scripts/audit-wikilinks.cjs .`.

The last piece matters most. With .claude/settings.json, physically bind the permissions. CLAUDE.md is a “request,” but this is a “physical lock.” It’s the gatekeeper so failure number three never repeats. Read broadly, write only in the working folders, fully seal dangerous operations with deny. For config details, see the official permissions docs.

{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "permissions": {
    "allow": [
      "Read(./CLAUDE.md)",
      "Read(./daily/**)",
      "Read(./projects/**)",
      "Read(./content-ops/**)",
      "Read(./snippets/**)",
      "Read(./templates/**)",
      "Read(./scripts/**)",
      "Edit(./daily/**)",
      "Edit(./projects/**)",
      "Edit(./content-ops/**)",
      "Edit(./snippets/**)",
      "Write(./inbox/**)",
      "Write(./daily/**)",
      "Write(./projects/**)",
      "Write(./content-ops/**)",
      "Write(./snippets/**)",
      "Bash(node scripts/audit-wikilinks.cjs .)"
    ],
    "ask": [
      "Edit(./templates/**)",
      "Bash(git *)"
    ],
    "deny": [
      "Read(./private/**)",
      "Read(./**/.env)",
      "Read(./**/.env.*)",
      "Edit(./.obsidian/**)",
      "Edit(./archive/**)",
      "Write(./archive/**)",
      "Bash(rm *)",
      "Bash(del *)"
    ]
  }
}

Once these three are in place, the rest is just asking. The knack is to not say “tidy it up nicely.” Scope, deliverable, prohibitions, verification — specify all of it, every time.

Read daily/2026-06-04.md and projects/site-refresh.md.
Based on templates/daily.md, create daily/2026-06-05.md.
For unfinished tasks, carry over only the ones still owned by me.
Don't touch .obsidian/, archive/, or private/.
When editing is done, run node scripts/audit-wikilinks.cjs . and report the result.

Short, but it contains input, output, the off-limits range, and the verification command. It’s many times more reproducible than “nicely.”

Let an external AI edit files and, every so often, a Wikilink breaks. Human eyes miss it. So at the very end I run a script that mechanically surfaces broken links. Save it as scripts/audit-wikilinks.cjs.

#!/usr/bin/env node
// Gatekeeper script that surfaces broken/ambiguous internal links ([[...]]) in the Vault
const fs = require("node:fs");
const path = require("node:path");

const vaultRoot = path.resolve(process.argv[2] || ".");
const ignoredDirs = new Set([".git", ".obsidian", ".trash", "node_modules"]);
const allFiles = [];
const markdownFiles = [];

function walk(dir) {
  for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
    if (ignoredDirs.has(entry.name)) continue;
    const full = path.join(dir, entry.name);
    if (entry.isDirectory()) {
      walk(full);
    } else if (entry.isFile()) {
      allFiles.push(full);
      if (entry.name.toLowerCase().endsWith(".md")) markdownFiles.push(full);
    }
  }
}

function toPosix(filePath) {
  return filePath.split(path.sep).join("/");
}

function withoutMd(value) {
  return value.replace(/\.md$/i, "");
}

function stripTarget(raw) {
  return raw.split("|")[0].split("#")[0].split("^")[0].trim();
}

function safeDecode(value) {
  try {
    return decodeURIComponent(value);
  } catch {
    return value;
  }
}

function isExternal(target) {
  return /^(https?:|mailto:|obsidian:|#|\/)/i.test(target);
}

function candidateKeys(target, fromFile) {
  const clean = safeDecode(stripTarget(target));
  if (!clean) return [];
  const keys = new Set();
  const normalized = toPosix(path.normalize(clean));
  keys.add(normalized);
  keys.add(withoutMd(normalized));

  if (clean.includes("/") || clean.includes("\\")) {
    const fromDir = path.dirname(toPosix(path.relative(vaultRoot, fromFile)));
    const relative = toPosix(path.normalize(path.join(fromDir, clean)));
    keys.add(relative);
    keys.add(withoutMd(relative));
  } else {
    keys.add(withoutMd(path.posix.basename(normalized)));
    keys.add(path.posix.basename(normalized));
  }

  return [...keys].filter(Boolean);
}

walk(vaultRoot);

const byPath = new Map();
const byBase = new Map();

for (const file of allFiles) {
  const rel = toPosix(path.relative(vaultRoot, file));
  const lowerRel = rel.toLowerCase();
  byPath.set(lowerRel, file);
  if (rel.toLowerCase().endsWith(".md")) byPath.set(withoutMd(lowerRel), file);

  const base = rel.toLowerCase().endsWith(".md")
    ? withoutMd(path.posix.basename(rel)).toLowerCase()
    : path.posix.basename(rel).toLowerCase();
  const list = byBase.get(base) || [];
  list.push(file);
  byBase.set(base, list);
}

const problems = [];
const wikilink = /!?\[\[([^\]]+)\]\]/g;
const markdownLink = /!?\[[^\]]*\]\(([^)]+)\)/g;

for (const file of markdownFiles) {
  const text = fs.readFileSync(file, "utf8");
  const rel = toPosix(path.relative(vaultRoot, file));
  const targets = [];
  let match;

  while ((match = wikilink.exec(text))) targets.push(match[1]);
  while ((match = markdownLink.exec(text))) {
    const target = match[1].replace(/^<|>$/g, "").trim();
    if (!isExternal(target)) targets.push(target);
  }

  for (const target of targets) {
    const clean = stripTarget(target);
    if (!clean || isExternal(clean)) continue;
    const keys = candidateKeys(clean, file);
    const pathHit = keys.some((key) => byPath.has(key.toLowerCase()));
    const baseHits = keys.flatMap((key) => byBase.get(path.posix.basename(key).toLowerCase()) || []);

    if (!pathHit && baseHits.length === 0) {
      problems.push(`${rel} -> missing [[${clean}]]`);
    } else if (!pathHit && baseHits.length > 1) {
      problems.push(`${rel} -> ambiguous [[${clean}]] (${baseHits.length} matches)`);
    }
  }
}

if (problems.length) {
  console.error("Found broken/ambiguous internal links:");
  for (const problem of problems) console.error(`- ${problem}`);
  process.exit(1);
}

console.log(`OK: checked ${markdownFiles.length} Markdown files in ${vaultRoot}`);

Running it is just this.

node scripts/audit-wikilinks.cjs .

If every link is alive, you get OK. If something’s broken, it tells you which link in which file is dead, as a list. Running this right after the AI tidies up is my daily closer.

For the exact specs of the Obsidian-side mechanisms (Daily notes, Templates, Properties, internal links), go to the official Obsidian help. Knowing your mothership’s specs before delegating to the AI keeps you from issuing weird instructions.

What actually happened when I tried it

I ran my Vault on this setup for three months.

What worked best was, as expected, the “daily-log handoff” and the “pre-publish link audit.” Having the AI summarize the previous day first thing in the morning, my engine clearly fires up faster. “So that’s where yesterday-me stalled” is visible at a glance, so my head switches to today’s mode while the coffee brews. Since I started slipping in the link audit, the nights of going pale at “oh, an internal link was broken” after publishing dropped to zero. In numbers: before the audit, I shipped broken links two or three times a month; now it’s zero.

There was another unexpected byproduct. With the premise that an AI touches my notes daily, the way I write notes changed. Knowing a machine will read it later, I naturally started adding status: and tacking even one line of context onto rough notes. I’d meant to tidy for the AI — but in the end the one whose reading got easiest was the human, me.

Conversely, the time I had it tidy the entire Vault at once was a clear failure. The AI over-guessed the meaning of old notes, and tags and headings only multiplied and got messier. The conclusion is simple: the more you hold the three points — narrow permissions, thin templates, a Node audit at the end — the better it goes.

The funny thing is, that two-year-old command I could never have recalled six months ago, I now reach in five seconds. I just follow the links the AI diligently added. The notes have, at last, started becoming a brain.

Wrapping up

The truth behind “notes that grow on their own” isn’t magic. Read broadly, write narrowly, double-check with a machine at the end. I just turned that obvious thing into a system.

There are three things to do. Split into folders, write the rules in CLAUDE.md, and physically seal dangerous operations with .claude/settings.json. After that, don’t say “nicely” — just ask within a narrowed scope. Start with one folder, daily/, today. Tomorrow-you will have it a little easier.

If you want to know the thinking on permissions and sandboxes in more detail, Claude Code’s approval and sandbox design is for you. Hands-on templates and where to consult about team rollout are gathered in the materials list.

#obsidian #claude-code #second-brain #pkm #markdown #automation
Free

Free PDF: Claude Code Cheatsheet

Enter your email and download the one-page Claude Code cheatsheet for commands, review habits, and safe workflows.

We handle your data with care and never send spam.

Level up your Claude Code workflow

Start with the free PDF, use Gumroad guides when you need repeatable workflows, and book consultation when rollout or revenue paths need human judgment.

Masa

About the Author

Masa

Engineer focused on practical Claude Code workflows. Runs claudecode-lab.com, a 10-language technical media site.