From obs-memory
Provides persistent Obsidian vault memory for coding agents. Auto-orients sessions with TODOs and project overviews, supports lookup of notes/patterns, and writes discoveries using commands like init, lookup, note.
npx claudepluginhub adamtylerlynch/obsidian-agent-memory-skillsThis skill uses the workspace's default tool permissions.
You have access to a persistent Obsidian knowledge vault — a graph-structured memory that persists across sessions. Use it to orient yourself, look up architecture and component knowledge, and write back discoveries.
Manages Obsidian vault as developer knowledge base: create/search/update notes with standard frontmatter, organize by projects/technologies/Claude Code, auto-capture commits/tasks/components.
Manages Obsidian vault structure by organizing documents into service and work-log layers, adding files with auto-categorization and metadata, processing meeting notes, running health checks, and committing via Git.
Integrates Claude with Obsidian vaults for note creation, task management, knowledge organization, and project docs using CLI (1.12+), MOCs, properties.
Share bugs, ideas, or general feedback.
You have access to a persistent Obsidian knowledge vault — a graph-structured memory that persists across sessions. Use it to orient yourself, look up architecture and component knowledge, and write back discoveries.
Resolve the vault path using this chain (first match wins):
$OBSIDIAN_VAULT_PATH~/Documents/SomeName/)~/Documents/AgentMemoryStore the resolved path as $VAULT for all subsequent operations. Derive $VAULT_NAME as basename "$VAULT" for CLI calls.
Verify the vault exists by checking for $VAULT/Home.md. If the vault doesn't exist, inform the user and suggest running the init command to bootstrap a new vault from the bundled template.
At the start of every session, orient yourself with at most 2 operations:
CLI-first:
obsidian vault=$VAULT_NAME tasks path="todos" todo verbose
Fallback: Read the file at $VAULT/todos/Active TODOs.md.
Know what's pending, in-progress, and recently completed.
Auto-detect the project from the current working directory:
basename $(git rev-parse --show-toplevel 2>/dev/null) 2>/dev/null || basename $(pwd)
Then check if a matching project exists by listing files in $VAULT/projects/*/. Match the git repo name (or directory name) against project folder names. If a match is found, read the project overview at $VAULT/projects/{matched-name}/{matched-name}.md.
This project overview contains wikilinks to all components, patterns, architecture decisions, and domains. Do not read those linked notes yet — follow them on demand when the current task requires that context.
Home.md (only if you're lost and can't find the project)sessions/ (only if the user references prior work)These behaviors apply to any agent using this skill. They do not require explicit commands.
Auto-orient (TODOs + project overview) without being asked, following the Session Start procedure above. If the vault doesn't exist at the resolved path, inform the user and suggest running init.
When the user says "done", "wrapping up", "that's it", "let's stop", or similar end-of-session language — offer to write a session summary. Don't auto-run; ask first: "Want me to write a session summary to the vault before we wrap up?"
When you deeply analyze a component that has no vault note — and the project has an active vault — offer to create a component note and infer relationships from imports and dependencies. Example: "I noticed there's no vault note for the AuthMiddleware component. Want me to create one and map its dependencies?"
When the vault doesn't exist at any resolved path, guide the user through init, then auto-scaffold the current project if inside a git repo.
Principle: Use CLI queries first, file reads second. The Obsidian CLI provides structured access to properties, links, backlinks, tags, and search — prefer these over reading entire files.
Use these CLI commands for targeted queries without consuming file-read tokens:
# Query a component's dependencies
obsidian vault=$VAULT_NAME property:read file="Component Name" name="depends-on"
# Find what depends on a component
obsidian vault=$VAULT_NAME property:read file="Component Name" name="depended-on-by"
obsidian vault=$VAULT_NAME backlinks file="Component Name"
# Find all outgoing links from a note
obsidian vault=$VAULT_NAME links file="Component Name"
# Find all notes of a type
obsidian vault=$VAULT_NAME tag verbose name="component"
# Search vault content
obsidian vault=$VAULT_NAME search format=json query="search term" matches limit=10
# Get note structure without full read
obsidian vault=$VAULT_NAME outline file="Component Name"
# Read a specific property
obsidian vault=$VAULT_NAME property:read file="Component Name" name="key-files"
Where $VAULT_NAME is the vault folder name (basename of $VAULT).
Fall back to file reads when the Obsidian CLI is not available:
When you need to scan multiple notes to find the right one, read just the first ~10 lines of each file. The tags, project, type, and status fields in the frontmatter tell you if the note is relevant before reading the full body.
List directory contents before reading files — know what exists without consuming tokens:
$VAULT/projects/{name}/**/*.md — all notes for a project$VAULT/domains/{tech}/*.md — domain knowledge filesWrite concisely. Notes are for your future context, not human documentation. Prefer:
| Knowledge type | Location | Example |
|---|---|---|
| One project only | projects/{name}/ | How this API handles auth |
| Shared across projects | domains/{tech}/ | How Go interfaces work |
| Universal, tech-agnostic | patterns/ | SOLID principles |
| Session summaries | sessions/ | What was done and discovered |
| TODOs | todos/Active TODOs.md | Grouped by project |
Always include in new notes:
---
tags: [category, project/short-name]
type: <component|adr|session|project>
project: "[[projects/{name}/{name}]]"
created: YYYY-MM-DD
---
[[projects/{name}/components/Component Name|Component Name]][[domains/{tech}/{Tech Name}|Tech Name]][[projects/{name}/{name}|project-name]]Component Note:
---
tags: [components, project/{short-name}]
type: component
project: "[[projects/{name}/{name}]]"
created: {date}
status: active
layer: ""
depends-on: []
depended-on-by: []
key-files: []
---
Sections: Purpose, Gotchas
Architecture Decision:
---
tags: [architecture, decision, project/{short-name}]
type: adr
project: "[[projects/{name}/{name}]]"
status: proposed | accepted | superseded
created: {date}
---
Sections: Context, Decision, Alternatives Considered, Consequences
Session Note:
---
tags: [sessions]
type: session
projects:
- "[[projects/{name}/{name}]]"
created: {date}
branch: {branch-name}
---
Sections: Context, Work Done, Discoveries, Decisions, Next Steps
init — Initialize the VaultBootstrap a new Obsidian Agent Memory vault from the bundled template.
Usage: init [path]
Determine vault path: Use the first argument if provided, otherwise use the vault resolution chain (default: ~/Documents/AgentMemory).
Check if vault already exists: Look for $VAULT/Home.md. If it exists, tell the user the vault already exists at that path and offer to open it.
Locate the bundled template: The template is at vault-template/ relative to the skill package root. Search for the skill package installation directory — it may be in the agent's plugin/skill cache or a local checkout. Look for the vault-template/Home.md file to confirm the correct path.
Create the vault:
mkdir -p "$VAULT"
cp -r "$TEMPLATE_DIR/vault-template/"* "$VAULT/"
Create Obsidian config directory:
mkdir -p "$VAULT/.obsidian"
Write the following to $VAULT/.obsidian/app.json:
{
"alwaysUpdateLinks": true,
"newFileLocation": "folder",
"newFileFolderPath": "inbox",
"attachmentFolderPath": "attachments"
}
Create empty directories:
mkdir -p "$VAULT/inbox"
mkdir -p "$VAULT/attachments"
Create .gitkeep files in each empty directory.
Report the created vault and provide next steps:
$VAULTOBSIDIAN_VAULT_PATH environment variable or agent configGenerate agent config snippet: Output a vault path snippet appropriate for the user's agent. For Claude Code, output a CLAUDE.md snippet:
## Obsidian Knowledge Vault
Persistent knowledge vault at `$VAULT`.
For other agents, output a generic instruction: "Add OBSIDIAN_VAULT_PATH=$VAULT to your environment or agent config."
Auto-scaffold current project: If inside a git repo, automatically run the project command to scaffold the current project in the vault.
Concise output: Keep the final output to 5-8 lines max: vault path created, project scaffolded (if applicable), how to open in Obsidian, how to set the vault path.
analyze — Analyze Project & Hydrate VaultAnalyze the current codebase and populate the vault with interconnected, content-rich notes.
Usage: analyze (no arguments — uses current repo)
Scan the repo for files that contain pre-existing knowledge:
| Category | Files to scan |
|---|---|
| Agent configs | CLAUDE.md, .claude/CLAUDE.md, .cursorrules, .windsurfrules, .clinerules, AGENTS.md, Agents.md |
| Documentation | README.md, CONTRIBUTING.md, ARCHITECTURE.md, docs/architecture.md, docs/ARCHITECTURE.md |
| Existing ADRs | docs/adr/ADR-*.md, architecture/ADR-*.md, adr/*.md, docs/decisions/*.md |
| Project metadata | package.json, go.mod, Cargo.toml, pyproject.toml, setup.py, Gemfile, pom.xml, build.gradle, *.csproj |
| Build/CI | Makefile, Dockerfile, docker-compose.yml, .github/workflows/*.yml, .gitlab-ci.yml |
| Config | tsconfig.json, .eslintrc.*, jest.config.*, .goreleaser.yml |
Read each discovered file. For large files (README, agent configs), read fully. For metadata files, extract key fields (name, version, dependencies).
Also gather:
git remote get-url origingit rev-parse --show-toplevelgit branch --show-currentUsing the discovered content, synthesize:
internal/ → Go service layers, src/components/ → React app), build systemIdempotency rules:
Notes to write:
Project overview ($VAULT/projects/{name}/{name}.md) — Fully populated:
---
aliases: []
tags: [project/{short-name}]
type: project
repo: {git remote url}
path: {repo root path}
language: {detected language(s)}
framework: {detected framework(s)}
created: {YYYY-MM-DD}
status: active
---
Sections:
Component notes ($VAULT/projects/{name}/components/{Component}.md) — One per major module:
---
tags: [components, project/{short-name}]
type: component
project: "[[projects/{name}/{name}]]"
created: {YYYY-MM-DD}
status: active
layer: {detected layer}
depends-on: []
depended-on-by: []
key-files: [{key files list}]
---
Sections: Purpose, Gotchas
Pattern notes ($VAULT/projects/{name}/patterns/{Pattern}.md) — From agent config conventions:
---
tags: [patterns, project/{short-name}]
type: pattern
project: "[[projects/{name}/{name}]]"
created: {YYYY-MM-DD}
---
Sections: Pattern, When to Use, Implementation
ADR imports ($VAULT/projects/{name}/architecture/ADR-{NNNN} {title}.md) — From existing repo ADRs:
---
tags: [architecture, decision, project/{short-name}]
type: adr
project: "[[projects/{name}/{name}]]"
status: accepted
created: {YYYY-MM-DD}
---
Preserve original content, add vault frontmatter.
Domain notes ($VAULT/domains/{tech}/{Tech}.md):
Index updates:
$VAULT/projects/Projects.md — add/update row$VAULT/domains/Domains.md — add/update rows for new domainsPrint a summary:
Analyzed: {project-name}
Sources read: {N} knowledge files
Created: project overview (populated)
Created: {N} component notes
Created: {N} pattern notes
Imported: {N} architecture decisions
Linked: {N} domain notes
Skipped: {N} existing notes (preserved)
recap — Write Session SummaryWrite a session summary note and update TODOs.
Usage: recap
Gather session context by running:
git log --oneline -20
git diff --stat HEAD~5..HEAD 2>/dev/null || git diff --stat
git branch --show-current
Read current TODOs — CLI-first:
obsidian vault=$VAULT_NAME tasks path="todos" todo verbose
Fallback: Read $VAULT/todos/Active TODOs.md.
Read project overview from $VAULT/projects/$PROJECT/$PROJECT.md (for wikilinks and context).
Write session note — CLI-first:
obsidian vault=$VAULT_NAME create path="sessions/{YYYY-MM-DD} - {title}" template="Session Note" silent
obsidian vault=$VAULT_NAME property:set path="sessions/{YYYY-MM-DD} - {title}" name="type" value="session" type="text"
obsidian vault=$VAULT_NAME property:set path="sessions/{YYYY-MM-DD} - {title}" name="branch" value="{current-branch}" type="text"
obsidian vault=$VAULT_NAME property:set path="sessions/{YYYY-MM-DD} - {title}" name="projects" value="[[projects/$PROJECT/$PROJECT]]" type="list"
Then append body content:
obsidian vault=$VAULT_NAME append path="sessions/{YYYY-MM-DD} - {title}" content="..."
Fallback: Write the file directly at $VAULT/sessions/{YYYY-MM-DD} - {title}.md:
---
tags: [sessions]
type: session
projects:
- "[[projects/$PROJECT/$PROJECT]]"
created: {YYYY-MM-DD}
branch: {current-branch}
---
Sections to fill:
Update TODOs: Edit $VAULT/todos/Active TODOs.md:
[x] items from Active TODOs — append them to $VAULT/todos/Completed TODOs Archive.md under a dated ## $PROJECT (YYYY-MM-DD) heading (create the file if it doesn't exist)[x] items in Active TODOs — they accumulate over time and waste context window on every session startUpdate Session Log: Add an entry to $VAULT/sessions/Session Log.md with the date, project, branch, and a one-line summary.
Report what was written.
project — Scaffold New ProjectScaffold a new project in the vault. Uses the first argument as the project name, or defaults to $PROJECT.
Usage: project [name]
Determine project name: Use the argument if provided, otherwise use $PROJECT.
Check if project exists: Look for $VAULT/projects/{name}/{name}.md. If it exists, tell the user and offer to open it instead.
Create directory structure:
$VAULT/projects/{name}/$VAULT/projects/{name}/architecture/$VAULT/projects/{name}/components/$VAULT/projects/{name}/patterns/Create project overview at $VAULT/projects/{name}/{name}.md:
---
aliases: []
tags: [project/{short-name}]
type: project
repo: {git remote url if available}
path: {working directory}
language: {detected from files}
framework:
created: {YYYY-MM-DD}
status: active
---
Sections: Architecture, Components, Project Patterns, Architecture Decisions, Domains
Auto-detect and fill:
git remote get-url origin$VAULT/domains/Update Projects.md: Add a row to the project table in $VAULT/projects/Projects.md.
Report the scaffolded structure.
note — Create a Note from TemplateCreate a note using a template. The first argument specifies the type: component, adr, or pattern.
Usage: note <component|adr|pattern> [name]
note component [name]Create at $VAULT/projects/$PROJECT/components/{name}.md:
---
tags: [components, project/{short-name}]
type: component
project: "[[projects/$PROJECT/$PROJECT]]"
created: {YYYY-MM-DD}
status: active
layer: ""
depends-on: []
depended-on-by: []
key-files: []
---
Sections: Purpose, Gotchas
If a name argument is provided, use it as the component name. Otherwise, ask the user.
note adr [title]Determine the next ADR number by listing existing ADRs in $VAULT/projects/$PROJECT/architecture/ADR-*.md.
Create at $VAULT/projects/$PROJECT/architecture/ADR-{NNNN} {title}.md:
---
tags: [architecture, decision, project/{short-name}]
type: adr
project: "[[projects/$PROJECT/$PROJECT]]"
status: proposed
created: {YYYY-MM-DD}
---
Sections: Context, Decision, Alternatives Considered, Consequences
note pattern [name]Create at $VAULT/projects/$PROJECT/patterns/{name}.md:
---
tags: [patterns, project/{short-name}]
project: "[[projects/$PROJECT/$PROJECT]]"
created: {YYYY-MM-DD}
---
Sections: Pattern, When to Use, Implementation, Examples
After creating any note, add a wikilink to it from the project overview.
todo — Manage TODOsView and update the Active TODOs for the current project.
Usage: todo [action]
Read current TODOs from $VAULT/todos/Active TODOs.md.
If no additional arguments: Display the current TODOs for $PROJECT and ask what to update.
If arguments provided: Parse as a TODO action:
$PROJECTdone: <text> → Mark item done: remove from Active TODOs, append to $VAULT/todos/Completed TODOs Archive.md under a dated ## $PROJECT (YYYY-MM-DD) heading (create the file if it doesn't exist)remove: <text> → Remove matching itemWrite back Active TODOs (and archive file if items were completed).
lookup — Search the VaultSearch the vault for knowledge. Supports targeted subcommands and freetext search.
Usage: lookup <subcommand|freetext>
lookup deps <name>Query what a component depends on.
obsidian vault=$VAULT_NAME property:read file="<name>" name="depends-on"
Fallback: Read the component note and parse the depends-on frontmatter list.
lookup consumers <name>Query what depends on a component (reverse dependencies).
obsidian vault=$VAULT_NAME property:read file="<name>" name="depended-on-by"
obsidian vault=$VAULT_NAME backlinks file="<name>"
Combine results — depended-on-by gives explicit relationships, backlinks catches implicit references. Fallback: Read the component note and search for backlinks via Grep.
lookup related <name>Query all notes connected to a given note (both directions).
obsidian vault=$VAULT_NAME links file="<name>"
obsidian vault=$VAULT_NAME backlinks file="<name>"
Fallback: Read the note and extract wikilinks, then Grep for [[<name> across the vault.
lookup type <type> [project]Find all notes of a given type (component, adr, session, project).
obsidian vault=$VAULT_NAME tag verbose name="<type>"
If [project] is specified, filter results to notes also tagged project/<short-name>:
obsidian vault=$VAULT_NAME search query="type: <type>" path="projects/<project>"
Fallback: Grep for type: <type> across $VAULT.
lookup layer <layer> [project]Find all components in a specific layer.
obsidian vault=$VAULT_NAME search query="layer: <layer>" path="projects/<project>"
If no project specified, search across all projects:
obsidian vault=$VAULT_NAME search query="layer: <layer>" path="projects"
Fallback: Grep for layer: <layer> across $VAULT/projects/.
lookup files <component>Query key files for a component.
obsidian vault=$VAULT_NAME property:read file="<component>" name="key-files"
Fallback: Read the component note and parse the key-files frontmatter list.
lookup <freetext>General search across the vault.
obsidian vault=$VAULT_NAME search format=json query="<freetext>" matches limit=10
Fallback: Search file contents for the query across all .md files in $VAULT.
If the query looks like a tag (starts with # or project/):
obsidian vault=$VAULT_NAME tags name="<query>"
If the query matches a note name:
obsidian vault=$VAULT_NAME backlinks file="<query>"
Present results: Show matching notes with their frontmatter (first ~10 lines) so the user can decide which to read in full.
relate — Manage RelationshipsCreate and query bidirectional relationships between notes via frontmatter properties.
Usage: relate <subcommand> [args]
| Forward property | Inverse property |
|---|---|
depends-on | depended-on-by |
extends | extended-by |
implements | implemented-by |
consumes | consumed-by |
relate <source> <target> [type]Create a bidirectional relationship between two notes. Default type is depends-on/depended-on-by.
Resolve note names: Use file= parameter for note display names. If ambiguity is possible (same name, different folders), use path= with full vault-relative path.
Read current property on source (forward direction):
obsidian vault=$VAULT_NAME property:read file="<source>" name="<forward-property>"
Fallback: Read the source note frontmatter.
Check if relationship already exists: If <target> (as a wikilink) is already in the list, skip and report "already related".
Append to source (forward direction):
Build the new list locally by appending [[<target>]] to the current values, then set:
obsidian vault=$VAULT_NAME property:set file="<source>" name="<forward-property>" value="<full-list>" type="list"
Fallback: Edit the source note's frontmatter directly.
Read current property on target (inverse direction):
obsidian vault=$VAULT_NAME property:read file="<target>" name="<inverse-property>"
Append to target (inverse direction):
obsidian vault=$VAULT_NAME property:set file="<target>" name="<inverse-property>" value="<full-list>" type="list"
Report the created relationship.
Safety: Always read-then-set. Never blind-append. The full list is constructed locally and set atomically.
relate show <name>Display all relationships for a note.
Query all 8 relationship properties:
obsidian vault=$VAULT_NAME property:read file="<name>" name="depends-on"
obsidian vault=$VAULT_NAME property:read file="<name>" name="depended-on-by"
obsidian vault=$VAULT_NAME property:read file="<name>" name="extends"
obsidian vault=$VAULT_NAME property:read file="<name>" name="extended-by"
obsidian vault=$VAULT_NAME property:read file="<name>" name="implements"
obsidian vault=$VAULT_NAME property:read file="<name>" name="implemented-by"
obsidian vault=$VAULT_NAME property:read file="<name>" name="consumes"
obsidian vault=$VAULT_NAME property:read file="<name>" name="consumed-by"
Fallback: Read the note frontmatter and parse all relationship properties.
Query structural links:
obsidian vault=$VAULT_NAME links file="<name>"
obsidian vault=$VAULT_NAME backlinks file="<name>"
Present results grouped by relationship type. Show explicit (property) relationships first, then structural (wikilink) relationships that aren't already covered.
relate tree <name> [depth]Walk the dependency tree via BFS. Default depth is 2.
Initialize BFS: Start with <name> at depth 0. Maintain a visited set and a queue.
For each node in the queue:
obsidian vault=$VAULT_NAME property:read file="<current>" name="depends-on"
Fallback: Read the note and parse depends-on from frontmatter.
Add unvisited dependencies to the queue at current_depth + 1. Stop when depth limit is reached.
Present the tree as an indented list showing the dependency chain.
obsidian CLI for property reads, backlinks, links, tags, and search — these return targeted data without full file readslookup subcommands and relate show before reading full notes/obs init to bootstrap it/obs project to scaffold it$VAULT/
├── Home.md # Dashboard (read only if lost)
├── projects/{name}/
│ ├── {name}.md # Project overview — START HERE
│ ├── architecture/ # ADRs and design decisions
│ ├── components/ # Per-component notes
│ └── patterns/ # Project-specific patterns
├── domains/{tech}/ # Cross-project knowledge
├── patterns/ # Universal patterns
├── sessions/ # Session logs (read only when needed)
├── todos/Active TODOs.md # Pending work (read at session start)
├── templates/ # Note templates
└── inbox/ # Unsorted