654 lines
23 KiB
Markdown
654 lines
23 KiB
Markdown
---
|
||
title: Obsidian CLI:AI 的外部记忆层
|
||
slug: obsidian-cli-ai-external-memory
|
||
style: tech_blog
|
||
audience: AI 从业者、知识管理爱好者
|
||
status: draft
|
||
tags:
|
||
- obsidian
|
||
- ai-memory
|
||
- cli
|
||
- knowledge-management
|
||
source_notes:
|
||
- 01-topics/2026-03-02-obsidian-cli-ai-memory-layer.md
|
||
- 00-inbox/2026-03-02-cli-is-all-you-need.md
|
||
created_at: 2026-03-02T00:00:00+08:00
|
||
updated_at: 2026-03-02T00:00:00+08:00
|
||
id: 2026-03-02-obsidian-cli-ai-external-memory
|
||
content_type: article
|
||
channels:
|
||
- wechat
|
||
- x
|
||
language: zh-CN
|
||
source_urls: []
|
||
assets: []
|
||
cover_image: ""
|
||
template: tech-blog
|
||
owner: content-forge
|
||
---
|
||
|
||
# Obsidian CLI:AI 的外部记忆层
|
||
|
||
## 问题背景
|
||
|
||
AI Agent 有一个致命缺陷:会话结束,记忆清零。
|
||
|
||
每次对话都从零开始。你上周踩的坑、上个月做的架构决策、半年前的最佳实践——全没了。你得重复解释,Agent 重复犯错。
|
||
|
||
有人用 Notion,有人用 GitHub Issues,有人用外部数据库。但这些方案要么 API 臃肿,要么和 AI 的工作方式不匹配。
|
||
|
||
**Obsidian 1.12 给出了另一个答案:命令行工具。**
|
||
|
||
## 核心方案
|
||
|
||
Obsidian 1.12 新增的 CLI 让 AI 可以直接读写你的 vault——不用 API,不用 MCP server,就是普通的 shell 命令。
|
||
|
||
22
|
||
00-inbox/vin-obsidian-workflows.md
|
||
00-inbox/CLAUDE.md Best Practices.md
|
||
Error: File "00-inbox/my-note.md" not found.
|
||
00-inbox/2026-03-02-cli-is-all-you-need.md
|
||
00-inbox/2026-03-02-lessons-from-building-claude-code.md
|
||
00-inbox/2026-03-02-obsidian-kanban-for-ai-tasks.md
|
||
00-inbox/2026-03-02-sync-test.md
|
||
00-inbox/vin-obsidian-workflows.md
|
||
01-topics/2026-03-02-cli-test.md
|
||
01-topics/2026-03-02-obsidian-cli-ai-memory-layer.md
|
||
content-pipeline-v2.md
|
||
templates/article.md
|
||
templates/social-post.md
|
||
templates/tech-blog.md
|
||
|
||
这套方案的核心逻辑是:
|
||
|
||
**Obsidian 管存储,AI 管智能,CLI 把两边接上。**
|
||
|
||
### 为什么不用 MCP?
|
||
|
||
Marco Franzon 在《CLI Is All You Need》里说得很直接:
|
||
|
||
> "Bash is the ultimate MCP."
|
||
> "Agents were trained on Unix pipes—they're ridiculously good at it."
|
||
|
||
MCP server 需要你写 schema、维护 server、处理版本兼容。而 CLI?Agent 本来就会用。它被训练了几十年的 Unix 命令用法,、、 这些它比谁都熟。
|
||
|
||
Obsidian CLI 就是把这个原则用到了知识管理上。
|
||
|
||
## 实现细节
|
||
|
||
### 安装
|
||
|
||
1. 更新 Obsidian 到 1.12+
|
||
2. 设置 → 通用 → 打开「命令行工具」
|
||
3. 验证:终端运行 name content-forge
|
||
path /home/kang/apps/content-forge/content-forge
|
||
files 22
|
||
folders 8
|
||
size 43687
|
||
|
||
### 关键命令
|
||
|
||
| 命令 | 用途 | AI 场景 |
|
||
|------|------|---------|
|
||
| 22 | 统计笔记数量 | 快速了解 vault 规模 |
|
||
| No matches found. | 全文搜索 | 找相关笔记 |
|
||
| Error: File "..." not found. | 读取笔记内容 | 获取具体信息 |
|
||
| 00-inbox/2026-03-02-cli-is-all-you-need.md
|
||
00-inbox/2026-03-02-lessons-from-building-claude-code.md
|
||
00-inbox/2026-03-02-obsidian-kanban-for-ai-tasks.md
|
||
00-inbox/2026-03-02-sync-test.md
|
||
00-inbox/vin-obsidian-workflows.md
|
||
01-topics/2026-03-02-cli-test.md
|
||
01-topics/2026-03-02-obsidian-cli-ai-memory-layer.md
|
||
content-pipeline-v2.md
|
||
templates/article.md
|
||
templates/social-post.md
|
||
templates/tech-blog.md | 查找孤儿笔记 | 发现知识孤岛 |
|
||
| 00-inbox/2026-03-02-claude-code-overnight-work.md
|
||
00-inbox/2026-03-02-cli-is-all-you-need.md
|
||
00-inbox/2026-03-02-lessons-from-building-claude-code.md
|
||
00-inbox/2026-03-02-sync-test.md
|
||
00-inbox/vin-obsidian-workflows.md
|
||
01-topics/2026-03-02-cli-test.md
|
||
01-topics/2026-03-02-obsidian-cli-ai-memory-layer.md
|
||
content-pipeline-v2.md
|
||
templates/article.md
|
||
templates/social-post.md
|
||
templates/tech-blog.md | 查找死链 | 清理断裂链接 |
|
||
| Error: No active file. Use file=<name> or path=<path> to specify a file. | 查看反向链接 | 顺藤摸瓜 |
|
||
|
||
### Token 节省
|
||
|
||
实测数据:
|
||
|
||
| 操作 | 旧方案 | 新方案 | 节省 |
|
||
|------|--------|--------|------|
|
||
| 了解笔记库概况 | 遍历所有文件 (45KB) | 22 (351B) | **99.2%** |
|
||
| 看一篇笔记结构 | 读取整个文件 (63KB) | Error: No active file. Use file=<name> or path=<path> to specify a file. 只看标题 (5KB) | **92%** |
|
||
| 查找孤儿笔记 | 自己写脚本 | 00-inbox/2026-03-02-cli-is-all-you-need.md
|
||
00-inbox/2026-03-02-lessons-from-building-claude-code.md
|
||
00-inbox/2026-03-02-obsidian-kanban-for-ai-tasks.md
|
||
00-inbox/2026-03-02-sync-test.md
|
||
00-inbox/vin-obsidian-workflows.md
|
||
01-topics/2026-03-02-cli-test.md
|
||
01-topics/2026-03-02-obsidian-cli-ai-memory-layer.md
|
||
content-pipeline-v2.md
|
||
templates/article.md
|
||
templates/social-post.md
|
||
templates/tech-blog.md 一行命令 | N/A |
|
||
|
||
## 验证结果
|
||
|
||
### 1. 省 Token
|
||
|
||
这是最直观的收益。AI 不再用 context window 存整个文件系统,而是用 CLI 按需查询。Context 窗口留给真正的推理,不是存文件列表。
|
||
|
||
### 2. 多了一层图谱检索
|
||
|
||
这是更重要的收益。
|
||
|
||
向量搜索找的是「内容相似」的笔记。CLI 的反向链接找的是「你当初主动建立的知识连接」。
|
||
|
||
这两个「相关」不一样。
|
||
|
||
AI 搜到一篇笔记后,可以顺着 Error: No active file. Use file=<name> or path=<path> to specify a file. 拉出你当初链接它的所有笔记——这是传统搜索做不到的。它复活了你构建知识图谱时的意图。
|
||
|
||
## 总结与扩展
|
||
|
||
**Obsidian CLI 把 AI 变成了你的长期记忆外挂。**
|
||
|
||
- **省 token**:CLI 按需查询,不暴力遍历
|
||
- **图谱感知**:反向链接复活你的知识结构意图
|
||
- **零集成成本**:Agent 本来就会用 shell
|
||
|
||
如果你在用 Claude Code 或其他 CLI-native Agent,强烈建议把这个加进工作流。你的 vault 不再只是笔记库——它是 AI 的外部皮层。
|
||
|
||
---
|
||
|
||
**行动建议**:
|
||
|
||
1. 今天就更新 Obsidian 到 1.12,打开 CLI
|
||
2. 把 Obsidian CLI
|
||
|
||
Usage: obsidian <command> [options]
|
||
|
||
Options:
|
||
vault=<name> Target a specific vault by name
|
||
|
||
Notes:
|
||
file resolves by name (like wikilinks), path is exact (folder/note.md)
|
||
Most commands default to the active file when file/path is omitted
|
||
Quote values with spaces: name="My Note"
|
||
Use
|
||
for newline, for tab in content values
|
||
|
||
Commands:
|
||
aliases List aliases in the vault
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
total - Return alias count
|
||
verbose - Include file paths
|
||
active - Show aliases for active file
|
||
|
||
append Append content to a file
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
content=<text> - Content to append (required)
|
||
inline - Append without newline
|
||
|
||
backlinks List backlinks to a file
|
||
file=<name> - Target file name
|
||
path=<path> - Target file path
|
||
counts - Include link counts
|
||
total - Return backlink count
|
||
format=json|tsv|csv - Output format (default: tsv)
|
||
|
||
base:create Create a new item in a base
|
||
file=<name> - Base file name
|
||
path=<path> - Base file path
|
||
view=<name> - View name
|
||
name=<name> - New file name
|
||
content=<text> - Initial content
|
||
open - Open file after creating
|
||
newtab - Open in new tab
|
||
|
||
base:query Query a base and return results
|
||
file=<name> - Base file name
|
||
path=<path> - Base file path
|
||
view=<name> - View name to query
|
||
format=json|csv|tsv|md|paths - Output format (default: json)
|
||
|
||
base:views List views in the current base file
|
||
|
||
bases List all base files in vault
|
||
|
||
bookmark Add a bookmark
|
||
file=<path> - File to bookmark
|
||
subpath=<subpath> - Subpath (heading or block) within file
|
||
folder=<path> - Folder to bookmark
|
||
search=<query> - Search query to bookmark
|
||
url=<url> - URL to bookmark
|
||
title=<title> - Bookmark title
|
||
|
||
bookmarks List bookmarks
|
||
total - Return bookmark count
|
||
verbose - Include bookmark types
|
||
format=json|tsv|csv - Output format (default: tsv)
|
||
|
||
command Execute an Obsidian command
|
||
id=<command-id> - Command ID to execute (required)
|
||
|
||
commands List available command IDs
|
||
filter=<prefix> - Filter by ID prefix
|
||
|
||
create Create a new file
|
||
name=<name> - File name
|
||
path=<path> - File path
|
||
content=<text> - Initial content
|
||
template=<name> - Template to use
|
||
overwrite - Overwrite if file exists
|
||
open - Open file after creating
|
||
newtab - Open in new tab
|
||
|
||
daily Open daily note
|
||
paneType=tab|split|window - Pane type to open in
|
||
|
||
daily:append Append content to daily note
|
||
content=<text> - Content to append (required)
|
||
inline - Append without newline
|
||
open - Open file after adding
|
||
paneType=tab|split|window - Pane type to open in
|
||
|
||
daily:path Get daily note path
|
||
|
||
daily:prepend Prepend content to daily note
|
||
content=<text> - Content to prepend (required)
|
||
inline - Prepend without newline
|
||
open - Open file after adding
|
||
paneType=tab|split|window - Pane type to open in
|
||
|
||
daily:read Read daily note contents
|
||
|
||
deadends List files with no outgoing links
|
||
total - Return dead-end count
|
||
all - Include non-markdown files
|
||
|
||
delete Delete a file
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
permanent - Skip trash, delete permanently
|
||
|
||
diff List or diff local/sync versions
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
from=<n> - Version number to diff from
|
||
to=<n> - Version number to diff to
|
||
filter=local|sync - Filter by version source
|
||
|
||
file Show file info
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
|
||
files List files in the vault
|
||
folder=<path> - Filter by folder
|
||
ext=<extension> - Filter by extension
|
||
total - Return file count
|
||
|
||
folder Show folder info
|
||
path=<path> - Folder path (required)
|
||
info=files|folders|size - Return specific info only
|
||
|
||
folders List folders in the vault
|
||
folder=<path> - Filter by parent folder
|
||
total - Return folder count
|
||
|
||
help Show list of all available commands
|
||
<command> - Show help for a specific command
|
||
|
||
history List file history versions
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
|
||
history:list List files with history
|
||
|
||
history:open Open file recovery
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
|
||
history:read Read a file history version
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
version=<n> - Version number (default: 1)
|
||
|
||
history:restore Restore a file history version
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
version=<n> - Version number (required)
|
||
|
||
hotkey Get hotkey for a command
|
||
id=<command-id> - Command ID (required)
|
||
verbose - Show if custom or default
|
||
|
||
hotkeys List hotkeys
|
||
total - Return hotkey count
|
||
verbose - Show if hotkey is custom
|
||
format=json|tsv|csv - Output format (default: tsv)
|
||
all - Include commands without hotkeys
|
||
|
||
links List outgoing links from a file
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
total - Return link count
|
||
|
||
move Move or rename a file
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
to=<path> - Destination folder or path (required)
|
||
|
||
open Open a file
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
newtab - Open in new tab
|
||
|
||
orphans List files with no incoming links
|
||
total - Return orphan count
|
||
all - Include non-markdown files
|
||
|
||
outline Show headings for the current file
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
format=tree|md|json - Output format (default: tree)
|
||
total - Return heading count
|
||
|
||
plugin Get plugin info
|
||
id=<plugin-id> - Plugin ID (required)
|
||
|
||
plugin:disable Disable a plugin
|
||
id=<id> - Plugin ID (required)
|
||
filter=core|community - Plugin type
|
||
|
||
plugin:enable Enable a plugin
|
||
id=<id> - Plugin ID (required)
|
||
filter=core|community - Plugin type
|
||
|
||
plugin:install Install a community plugin
|
||
id=<id> - Plugin ID (required)
|
||
enable - Enable after install
|
||
|
||
plugin:reload Reload a plugin (for developers)
|
||
id=<id> - Plugin ID (required)
|
||
|
||
plugin:uninstall Uninstall a community plugin
|
||
id=<id> - Plugin ID (required)
|
||
|
||
plugins List installed plugins
|
||
filter=core|community - Filter by plugin type
|
||
versions - Include version numbers
|
||
format=json|tsv|csv - Output format (default: tsv)
|
||
|
||
plugins:enabled List enabled plugins
|
||
filter=core|community - Filter by plugin type
|
||
versions - Include version numbers
|
||
format=json|tsv|csv - Output format (default: tsv)
|
||
|
||
plugins:restrict Toggle or check restricted mode
|
||
on - Enable restricted mode
|
||
off - Disable restricted mode
|
||
|
||
prepend Prepend content to a file
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
content=<text> - Content to prepend (required)
|
||
inline - Prepend without newline
|
||
|
||
properties List properties in the vault
|
||
file=<name> - Show properties for file
|
||
path=<path> - Show properties for path
|
||
name=<name> - Get specific property count
|
||
total - Return property count
|
||
sort=count - Sort by count (default: name)
|
||
counts - Include occurrence counts
|
||
format=yaml|json|tsv - Output format (default: yaml)
|
||
active - Show properties for active file
|
||
|
||
property:read Read a property value from a file
|
||
name=<name> - Property name (required)
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
|
||
property:remove Remove a property from a file
|
||
name=<name> - Property name (required)
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
|
||
property:set Set a property on a file
|
||
name=<name> - Property name (required)
|
||
value=<value> - Property value (required)
|
||
type=text|list|number|checkbox|date|datetime - Property type
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
|
||
random Open a random note
|
||
folder=<path> - Limit to folder
|
||
newtab - Open in new tab
|
||
|
||
random:read Read a random note
|
||
folder=<path> - Limit to folder
|
||
|
||
read Read file contents
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
|
||
recents List recently opened files
|
||
total - Return recent file count
|
||
|
||
reload Reload the vault
|
||
|
||
rename Rename a file
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
name=<name> - New file name (required)
|
||
|
||
restart Restart the app
|
||
|
||
search Search vault for text
|
||
query=<text> - Search query (required)
|
||
path=<folder> - Limit to folder
|
||
limit=<n> - Max files
|
||
total - Return match count
|
||
case - Case sensitive
|
||
format=text|json - Output format (default: text)
|
||
|
||
search:context Search with matching line context
|
||
query=<text> - Search query (required)
|
||
path=<folder> - Limit to folder
|
||
limit=<n> - Max files
|
||
case - Case sensitive
|
||
format=text|json - Output format (default: text)
|
||
|
||
search:open Open search view
|
||
query=<text> - Initial search query
|
||
|
||
snippet:disable Disable a CSS snippet
|
||
name=<name> - Snippet name (required)
|
||
|
||
snippet:enable Enable a CSS snippet
|
||
name=<name> - Snippet name (required)
|
||
|
||
snippets List installed CSS snippets
|
||
|
||
snippets:enabled List enabled CSS snippets
|
||
|
||
sync Pause or resume sync
|
||
on - Resume sync
|
||
off - Pause sync
|
||
|
||
sync:deleted List deleted files in sync
|
||
total - Return deleted file count
|
||
|
||
sync:history List sync version history for a file
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
total - Return version count
|
||
|
||
sync:open Open sync history
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
|
||
sync:read Read a sync version
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
version=<n> - Version number (required)
|
||
|
||
sync:restore Restore a sync version
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
version=<n> - Version number (required)
|
||
|
||
sync:status Show sync status
|
||
|
||
tab:open Open a new tab
|
||
group=<id> - Tab group ID
|
||
file=<path> - File to open
|
||
view=<type> - View type to open
|
||
|
||
tabs List open tabs
|
||
ids - Include tab IDs
|
||
|
||
tag Get tag info
|
||
name=<tag> - Tag name (required)
|
||
total - Return occurrence count
|
||
verbose - Include file list and count
|
||
|
||
tags List tags in the vault
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
total - Return tag count
|
||
counts - Include tag counts
|
||
sort=count - Sort by count (default: name)
|
||
format=json|tsv|csv - Output format (default: tsv)
|
||
active - Show tags for active file
|
||
|
||
task Show or update a task
|
||
ref=<path:line> - Task reference (path:line)
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
line=<n> - Line number
|
||
toggle - Toggle task status
|
||
done - Mark as done
|
||
todo - Mark as todo
|
||
daily - Use daily note
|
||
status="<char>" - Set status character
|
||
|
||
tasks List tasks in the vault
|
||
file=<name> - Filter by file name
|
||
path=<path> - Filter by file path
|
||
total - Return task count
|
||
done - Show completed tasks
|
||
todo - Show incomplete tasks
|
||
status="<char>" - Filter by status character
|
||
verbose - Group by file with line numbers
|
||
format=json|tsv|csv - Output format (default: text)
|
||
active - Show tasks for active file
|
||
daily - Show tasks from daily note
|
||
|
||
template:insert Insert template into active file
|
||
name=<template> - Template name (required)
|
||
|
||
template:read Read template content
|
||
name=<template> - Template name (required)
|
||
resolve - Resolve template variables
|
||
title=<title> - Title for variable resolution
|
||
|
||
templates List templates
|
||
total - Return template count
|
||
|
||
theme Show active theme or get info
|
||
name=<name> - Theme name for details
|
||
|
||
theme:install Install a community theme
|
||
name=<name> - Theme name (required)
|
||
enable - Activate after install
|
||
|
||
theme:set Set active theme
|
||
name=<name> - Theme name (empty for default) (required)
|
||
|
||
theme:uninstall Uninstall a theme
|
||
name=<name> - Theme name (required)
|
||
|
||
themes List installed themes
|
||
versions - Include version numbers
|
||
|
||
unresolved List unresolved links in vault
|
||
total - Return unresolved link count
|
||
counts - Include link counts
|
||
verbose - Include source files
|
||
format=json|tsv|csv - Output format (default: tsv)
|
||
|
||
vault Show vault info
|
||
info=name|path|files|folders|size - Return specific info only
|
||
|
||
vaults List known vaults
|
||
total - Return vault count
|
||
verbose - Include vault paths
|
||
|
||
version Show Obsidian version
|
||
|
||
wordcount Count words and characters
|
||
file=<name> - File name
|
||
path=<path> - File path
|
||
words - Return word count only
|
||
characters - Return character count only
|
||
|
||
workspace Show workspace tree
|
||
ids - Include workspace item IDs
|
||
|
||
|
||
Developer:
|
||
dev:cdp Run a Chrome DevTools Protocol command
|
||
method=<CDP.method> - CDP method to call (required)
|
||
params=<json> - Method parameters as JSON
|
||
|
||
dev:console Show captured console messages
|
||
clear - Clear the console buffer
|
||
limit=<n> - Max messages to show (default 50)
|
||
level=log|warn|error|info|debug - Filter by log level
|
||
|
||
dev:css Inspect CSS with source locations
|
||
selector=<css> - CSS selector (required)
|
||
prop=<name> - Filter by property name
|
||
|
||
dev:debug Attach/detach Chrome DevTools Protocol debugger
|
||
on - Attach debugger
|
||
off - Detach debugger
|
||
|
||
dev:dom Query DOM elements
|
||
selector=<css> - CSS selector (required)
|
||
total - Return element count
|
||
text - Return text content
|
||
inner - Return innerHTML instead of outerHTML
|
||
all - Return all matches instead of first
|
||
attr=<name> - Get attribute value
|
||
css=<prop> - Get CSS property value
|
||
|
||
dev:errors Show captured errors
|
||
clear - Clear the error buffer
|
||
|
||
dev:mobile Toggle mobile emulation
|
||
on - Enable mobile emulation
|
||
off - Disable mobile emulation
|
||
|
||
dev:screenshot Take a screenshot
|
||
path=<filename> - Output file path
|
||
|
||
devtools Toggle Electron dev tools
|
||
|
||
eval Execute JavaScript and return result
|
||
code=<javascript> - JavaScript code to execute (required) 命令加到你的 Agent 可用工具列表
|
||
3. 试着让 Agent 帮你清理一次孤儿笔记
|
||
|
||
---
|
||
|
||
> 参考:
|
||
> - [[2026-03-02-obsidian-cli-ai-memory-layer]] 原始思考
|
||
> - [[2026-03-02-cli-is-all-you-need]] CLI vs MCP 的深度分析 |