Claude Code x Obsidian: estructura del Vault, permisos, plantillas y auditoría de enlaces
Workflow práctico para Obsidian y Claude Code: notas diarias, handoff, snippets, content ops y auditoría de enlaces.
Un Vault de Obsidian gana valor con el tiempo, pero también acumula mantenimiento. Las notas diarias crecen, los proyectos pierden estado, los snippets de código se quedan sin contexto y las ideas de contenido dejan de apuntar a los enlaces internos o a la CTA correcta. Claude Code puede ayudar porque, en la práctica, un Vault es una carpeta de archivos Markdown.
El enfoque seguro no es pedirle a la IA que reorganice todo. El workflow útil es limitado: una estructura de carpetas pequeña, permisos estrictos, plantillas repetibles y una auditoría de enlaces al final. Para principiantes: el Vault es la carpeta de conocimiento; el harness es la base de trabajo que indica al agente dónde puede leer, dónde puede escribir y qué verificación debe ejecutar.
Esta guía cubre cuatro use case concretos: daily logs, project handoff, snippets de código y content operations. También marca cada pitfall importante, porque el risk real no es un párrafo poco elegante, sino un enlace roto, una propiedad YAML mal escrita o un archivo privado leído sin necesidad.
Modelo de integración
La ayuda oficial de Obsidian explica que los enlaces internos pueden escribirse como Wikilinks, por ejemplo [[Nombre de nota]], o como enlaces Markdown. Daily notes es un plugin principal para notas con fecha. Templates permite insertar valores como {{date}}, y Properties usa YAML al inicio de la nota. Revisa las páginas oficiales sobre internal links, Daily notes, Templates, Properties y Web Clipper templates.
En Claude Code, la frontera de seguridad está en settings y permissions. CLAUDE.md describe las reglas del Vault. .claude/settings.json limita las operaciones.
flowchart LR
A["Inbox"] --> B["Claude Code review"]
B --> C["Daily logs"]
B --> D["Projects"]
B --> E["Content ops"]
C --> F["Obsidian links"]
D --> F
E --> F
F --> G["Link audit"]
La fuente de verdad sigue siendo Markdown en Obsidian. Claude Code ordena, resume, crea borradores y revisa enlaces; no debe convertirse en dueño del Vault.
Empieza con una estructura pequeña
No crees veinte carpetas al principio. Usa una estructura que represente trabajo real.
mkdir -p inbox daily projects content-ops snippets templates scripts archive private
| Carpeta | Uso | Trabajo seguro para Claude Code |
|---|---|---|
inbox/ | capturas sin ordenar y Web Clipper | crear y clasificar |
daily/ | registro diario y memoria de trabajo | crear, añadir, resumir ayer |
projects/ | handoff y decisiones activas | actualizar notas de proyecto |
content-ops/ | ideas de artículos, CTA, publicación | ordenar borradores y enlaces |
snippets/ | comandos y ejemplos de código | añadir contexto y etiquetas |
templates/ | plantillas de Obsidian | leer; editar solo con aprobación |
archive/ | notas cerradas | no editar |
private/ | datos personales o secretos | no leer |
Con esto aparecen flujos útiles. Las notas diarias arrastran tareas pendientes. Las notas de project handoff explican estado, siguiente acción y risk. Los snippets guardan comando, versión y failure case. Las notas de content operations comprueban enlaces oficiales, enlaces internos, /products/ y /training/.
Añade CLAUDE.md en la raíz del Vault
Este archivo debe ser operativo y concreto.
# Obsidian Vault Rules
## Purpose
- This vault stores daily logs, project handoffs, code snippets, and content operations notes.
- Keep notes useful in Obsidian without requiring Claude Code to read private files.
## Directory policy
- `daily/`: create or update daily notes in `YYYY-MM-DD.md`.
- `projects/`: maintain one handoff note per active project.
- `content-ops/`: maintain article plans, CTA checks, and publishing notes.
- `snippets/`: store runnable commands and code examples with context.
- `templates/`: read freely, but ask before editing.
- `archive/` and `private/`: do not edit. Do not summarize private files.
## Note rules
- Use Wikilinks like `[[Project name]]` for internal links.
- Use YAML properties at the top of notes.
- Keep one paragraph under five lines.
- Add a `source:` property when a note comes from a URL.
- Add `status: draft`, `status: active`, or `status: done`.
## Safety rules
- Never rename existing notes without asking first.
- Never rewrite `.obsidian/` settings.
- Before bulk edits, list the target files and wait for approval.
- After changes, run `node scripts/audit-wikilinks.cjs .`.
El pitfall habitual es escribir una regla vaga como “organiza mi Vault”. Claude Code tendrá que inventar carpetas, títulos y tags. Esa inferencia puede sonar razonable, pero romper búsqueda, Graph view y enlaces.
Configura permisos estrechos
Guarda este ejemplo como .claude/settings.json.
{
"$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 *)",
"WebFetch"
],
"deny": [
"Read(./private/**)",
"Read(./**/.env)",
"Read(./**/.env.*)",
"Edit(./.obsidian/**)",
"Edit(./archive/**)",
"Write(./archive/**)",
"Bash(rm *)",
"Bash(del *)"
]
}
}
La idea es permitir trabajo frecuente sin abrir todo el Vault. Si necesitas revisar fuentes web o limpiar capturas, aprueba WebFetch cuando corresponda. Evita modos de bypass en un Vault real.
Tres plantillas de Obsidian
La plantilla diaria debe ser ligera.
---
date: "{{date:YYYY-MM-DD}}"
status: active
tags:
- daily
---
# {{date:YYYY-MM-DD}}
## Today
- [ ]
## Learned
-
## Questions
-
## Links
- [[Weekly review]]
La plantilla de project handoff prioriza la próxima acción.
---
status: active
owner: Masa
tags:
- project
- handoff
updated: "{{date:YYYY-MM-DD}}"
---
# Project handoff: {{title}}
## Goal
## Current state
## Next action
- [ ]
## Decisions
-
## Risks and pitfall
-
## Links
- [[Daily note]]
- [[Related snippet]]
La plantilla de content operations incluye monetización desde el inicio.
---
status: draft
channel: blog
source:
target_cta:
- /products/
- /training/
tags:
- content-ops
---
# Content ops note: {{title}}
## Search intent
## Reader problem
## Outline
## Internal links
- [[Claude Code approval sandbox guide]]
- [[Claude Code documentation generation]]
## Monetization CTA
- Product CTA:
- Training CTA:
## Publish checklist
- [ ] Official links checked
- [ ] Code examples tested
- [ ] Broken internal links audited
Para profundizar, enlaza con approval y sandbox, generación de documentación y content funnel audit. Los materiales reutilizables van a products y la adopción de equipo a training.
Audita enlaces internos con Node
Guarda esto como scripts/audit-wikilinks.cjs.
#!/usr/bin/env node
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("Broken or ambiguous internal links:");
for (const problem of problems) console.error(`- ${problem}`);
process.exit(1);
}
console.log(`OK: checked ${markdownFiles.length} Markdown files in ${vaultRoot}`);
Ejecútalo desde la raíz:
node scripts/audit-wikilinks.cjs .
Prompt recomendado:
Read `daily/2026-06-02.md` and `projects/site-refresh.md`.
Create `daily/2026-06-03.md` from `templates/daily.md`.
Carry over unfinished tasks only when they still have an owner.
Do not edit `.obsidian/`, `archive/`, or `private/`.
After editing, run `node scripts/audit-wikilinks.cjs .` and report the result.
Errores típicos
Primer pitfall: permitir edición de .obsidian/. Configuración de plugins, temas y hotkeys no es contenido normal.
Segundo: renombrar notas fuera de Obsidian. Puede romper backlinks.
Tercero: Properties YAML mal escritas. Si una propiedad contiene un enlace interno, usa comillas: related: "[[Project name]]".
Cuarto: notas diarias demasiado pesadas. Una plantilla que nadie completa se convierte en ruido.
Quinto: tratar content operations como solo redacción. Un artículo público necesita fuentes oficiales, enlaces internos, CTA y verificación.
Lo que probó Masa
En el Vault de prueba de Masa, los mejores resultados vinieron de dos flujos: pasar tareas pendientes al daily log siguiente y auditar enlaces antes de publicar notas de contenido. El peor experimento fue pedir “limpia todo el Vault”; Claude Code creó demasiadas etiquetas y títulos. Permisos estrechos, plantillas pequeñas y auditoría con Node dieron un workflow más estable.
PDF gratis: cheatsheet de Claude Code
Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.
Cuidamos tus datos y no enviamos spam.
Sobre el autor
Masa
Ingeniero enfocado en workflows prácticos con Claude Code.
Artículos relacionados
Escalera de permisos de Claude Code para ampliar acceso sin perder control
Pasa de read-only a ediciones limitadas, comandos de prueba y checks de deploy con menos riesgo.
Claude Code Small PR Proof Pack: cambios pequeños que sí se pueden revisar
Un paquete de prueba para PRs de Claude Code: diff, checks, URL pública, CTA y rollback.
Gate de revisión antes del commit con Claude Code
Cómo revisar con Claude Code antes del commit: diff, build, URL pública, Gumroad, consultoría, tests y archivos ajenos.