musingfox/cc-plugins/tree/main/obsidian-workspace
obw
Obsidian Workspace——面向项目的 vault 生产力工具(捕获 / 笔记 / PM)。技能负责文件夹布局和模板;/obw:pm 会将规范拆分为阻塞工单;/issue 是一个 Claude Mod 面板,会列出项目 dashboard 的视图、将 Mermaid 绘制为文本图表,并可通过 viz 在浏览器中打开卡片。Vault I/O 通过官方 obsidian-cli 技能使用 Obsidian CLI。
关于这个 mod
Obsidian Workspace
面向项目的 Obsidian vault 生产力工具,服务于 Claude Code 的快速捕获、长篇笔记和项目管理。技能负责文件夹布局、文件模板和 PM 约定;/issue Claude Mod 会在面板中列出项目 dashboard 的视图;vault I/O 通过 Obsidian CLI 执行,并将语法交给官方 obsidian:obsidian-cli 技能。每个技能文件都保持精简,不会消耗你的上下文预算。
插件标识符:obw(技能可通过 /obw:<name> 或自然语言调用)。
技能
| 技能 | 用途 |
|-------|---------|
| /obw:init | 选择 vault、写入 .obsidian.yaml、安装起始模板、初始化项目工作区、迁移旧布局 |
| /obw:jot <text> | 快速捕获(将带时间戳的项目符号写入今天的每日笔记)或长篇笔记——按输入形态分流 |
| /obw:pm [intent] | 项目范围内的任务 / 文档生命周期;将规范拆分为阻塞工单 |
工作方式
- Vault I/O 通过
obsidianCLI 执行,直接在主上下文中运行(没有子代理)。此插件不重复 CLI 语法,而是交给官方obsidian:obsidian-cli技能和obsidian help。 - 每日笔记 使用 Obsidian 的 Daily Notes 核心插件(文件夹 / 文件名 / 模板)。快速捕获会调用
daily:append。 - 模板(
task、doc)位于 vault 的 Obsidian Templates 文件夹中。执行/obw:init时,插件只会在同名文件不存在的情况下从templates/复制起始文件——绝不会覆盖你的编辑。 - Dashboard 是 Obsidian Bases(
.base文件——Obsidian 1.9+ 的核心功能),通过 shell 替换从插件内部模板生成,因此内容不会进入 Claude 的上下文。
Issue 面板
运行 /issue <view>,列出由 /obw:pm 创建的已配置项目 dashboard.base 中的一个视图,然后选择一项,在同一面板中读取其标题、状态、优先级和 markdown 正文。不带参数运行 /issue 会在视图选择器下打开 All Tasks 视图,显示可用方向键操作的列表:卡片按状态(todo、in-progress、blocked、done)分组,每个标题带卡片计数;每行显示 [H|M|L] <title> <due> <tags>,按优先级排序,并将 done 在开头折叠。点击列表以接收按键;↑↓ 移动,PgUp/PgDn 翻页,→ 或 Enter 打开卡片或展开标题,← 返回列表或折叠标题。该列表需要终端或桌面环境;在其他地方,All Tasks 会退回其他视图使用的扁平列表。其他视图始终是扁平列表。没有 All Tasks 的 dashboard 会打开 Active,并提示运行 /obw:pm refresh dashboard。/issue <card> 会直接打开该卡片。面板会在原处报告缺少配置、CLI 输出不可用和卡片缺失,不会向对话添加 vault 内容。
细横线会将卡片与列表分开。状态和优先级会显示为带颜色的标签;如果卡片的 Acceptance Criteria 区段含有复选框,后面会加上 AC <checked>/<total> 计数。错误以红色绘制;进度和空列表通知保持暗淡。
卡片正文中的 Mermaid 区块会由 uvx [email protected] 在面板中绘制为文本图表,需要 uv。uv 是可选的:没有 uv 时,区块会保持卡片中的代码区块。图表类型不受支持、以 %% 注释或 --- frontmatter 开头,或 termaid 失败、没有输出、耗时超过 5 s 时,区块同样会保持代码区块。卡片会先绘制,图表准备好后才逐一替换对应的代码区块,因此第一次运行时,在 uv 获取 termaid 之前可能会先看到代码区块。
显示的卡片有一个 Open in browser Button,会通过 viz 插件的 render.sh 渲染卡片正文(包含 Mermaid)。只有在 viz 已安装、能在 $CLAUDE_CONFIG_DIR 或 ~/.claude 下的 installed_plugins.json 中找到,并且当前处于终端时,Button 才会出现。打开浏览器使用 macOS 的 open;通过 SSH 时,面板会改为显示页面 URL。面板会报告卡片渲染到哪里,或说明为什么没有渲染。页面会在运行 Claude Code 的机器上打开:如果你通过没有设置 SSH 变量的终端多路复用器或 relay(例如 herdr)进入工作阶级,浏览器会在那个主机上打开,而不是在你正在查看的设备上。
要从 tailnet 上的另一台设备读取页面,可以用 tailscale serve --bg --https=18090 18090 代理 viz 的端口一次。每次渲染后,面板都会读取 tailscale serve status --json;当某个映射覆盖页面端口时,会加入一行 Tailnet: https://<machine>.<tailnet>.ts.net:18090/…。面板不会自行创建映射;没有映射时,只显示已打开的页面。
使用以下命令测试插件:
claude plugin test obsidian-workspace
面板需要 Claude Code 2.1.287 或更高版本,因为从该版本起 Claude Mods 默认启用。插件以 Claude Code 2.1.287 为目标进行构建和测试。
前置条件
- 官方
obsidian插件(来自obsidian-skillsmarketplace)——声明为插件依赖,因此只要已添加该 marketplace(claude plugin marketplace add),它就会随本插件自动安装 - Obsidian 应用正在运行(无头 CLI 也可以)
- 已安装并启用 Obsidian 社群插件
obsidian-cli。插件名称是obsidian-cli,但它安装的可执行文件是obsidian(调用方式为obsidian vault=<name> ...)。这不是 Yakitrak 提供的无关独立obsidian-cli二进制文件。 - 已启用 Templates 核心插件(
/obw:pm所需——task/doc模板) - 已启用 Daily Notes 核心插件(
/obw:jot快速捕获所需) - 已启用 Bases 核心插件(仅
/obw:pmdashboard 所需——Obsidian 1.9+ 已内置) - uv(可选;让
/issue面板通过uvx [email protected]将 Mermaid 区块绘制为文本图表——没有它们会显示为代码区块) - viz 插件(可选;启用
/issue面板的 Open in browser Button——没有它就不会绘制 Button) - Claude Code 2.1.287 或更高版本(仅
/issue面板需要;技能本身不需要)
安装
/plugin install obsidian-workspace
权限(建议)
Vault 操作会调用 obsidian CLI 以及少量 Unix 辅助工具。为避免反复出现权限提示,可以将以下内容一次性加入用户的 settings.json(~/.claude/settings.json):
{
"permissions": {
"allow": [
"Bash(obsidian:*)",
"Bash(cat:*)",
"Bash(jq:*)",
"Bash(cp:*)",
"Bash(sed:*)"
]
}
}
或者在 /obw:init 卡住后运行 /fewer-permission-prompts,它会扫描转录并提出相同的列表。
配置
在项目根目录中运行 /obw:init。生成的 .obsidian.yaml:
vault: MyVault
note:
default_folder: Inbox
filename_strategy: title # title | slug | timestamp-title
pm:
project: my-project # Omit this section to disable /obw:pm
每日笔记的文件夹 / 文件名 / 模板不在 .obsidian.yaml 中——它们来自 Obsidian 的 Daily Notes 设置。
Vault 布局(/obw:pm)
pm/
├── dashboard.base # Cross-project dashboard (optional, Bases)
└── {project}/
├── dashboard.base # Project dashboard (Bases)
├── tasks/ # Active tasks
│ └── archive/ # Completed tasks
└── docs/ # Docs
每个项目都会获得 tasks/、docs/ 和 dashboard.base——/obw:init 会预先创建这三项,因此项目永远不会只是一个空文件夹。
从 0.9 之前的 vault 升级:重新运行 /obw:init。它会检测旧布局,并分别提供以下选项:将 archive/ 移到 tasks/archive/(通过 CLI,因此链接会跟随移动)、为现有笔记补写 title 属性,以及用新视图重新生成 dashboard。现有文件名永远不会重命名。
插件更新可能会加入 dashboard 视图。在现有 vault 上运行 /obw:pm refresh dashboard,以带入 All Tasks(以及其他新的模板视图)。刷新会从模板重新生成 dashboard.base,因此该文件的手动编辑会被覆盖;它会先警告并询问。
文件名
所有笔记都使用 kebab-case(Implement Auth → implement-auth.md),包括 /obw:jot 笔记和 /obw:pm 任务 / 文档。由于 Obsidian 的 {{title}} 会解析为文件名,人类可读的标题存放在 title 属性中——dashboard 显示的就是这个属性。
属性 schema
Dashboard 和搜索依赖这些 frontmatter 字段。如果你编辑已安装的模板,请保留字段名称。
- Task——
title、type: task、status(todo/in-progress/blocked/done)、priority(high/medium/low)、project、due(日期)、tags(列表)、parent(链接)、blocked_by(链接列表)、related(链接列表)、created、completed - Doc——
title、type: doc、project、created、updated
任务关系
任务通过 wikilink,借助三个属性彼此关联——blocked_by、related 和 parent(epic → subtask)。不存在单独的 issue ID:kebab 文件名就是句柄,笔记重命名时 Obsidian 会重写链接。
这里只存储一个方向。任务会阻塞什么,以及它有哪些子任务,来自 Obsidian 的 backlinks 面板——在 blocked_by 旁边增加 blocks 字段只会造成漂移。添加阻塞项会设置 status: blocked;归档任务时会列出仍依赖它的项目,并在解除阻塞前询问。工单拆分会将阻塞边写入 blocked_by;未阻塞前沿是排除 -[blocked_by: wikilink 的 search,而不是一个视图。
示例
/obw:jot #worklog 完成 API 重构 PR,等 review
/obw:jot API Redesign Proposal --folder Architecture --tag design
/obw:pm add task implement-auth, high priority, due 2026-05-01
/obw:pm implement-auth is blocked by db-migration
/obw:pm implement-auth is done, archive it
/obw:pm split this spec into tickets
/obw:pm refresh dashboard
安装
请先查看作者 README 确认 marketplace 和插件名称;命令可能随仓库结构改变。
claude plugin marketplace add musingfox/cc-plugins claude plugin install obw
原文 / README
Obsidian Workspace
Project-scoped Obsidian vault productivity for Claude Code — quick capture, long-form notes, and project management. Skills own folder layout + file templates + PM conventions, while the /issue Claude Mod lists a view of the project's dashboard in a pane; vault I/O runs through the Obsidian CLI, deferring to the official obsidian:obsidian-cli skill for syntax. Each skill file is kept small so it doesn't burn your context budget.
Plugin identifier: obw (skills invoked as /obw:<name> or via natural language).
Skills
| Skill | Purpose |
|-------|---------|
| /obw:init | Pick a vault, write .obsidian.yaml, install starter templates, bootstrap the project workspace, migrate an older layout |
| /obw:jot <text> | Quick capture (timestamped bullet to today's daily note) or long-form note — triages by input shape |
| /obw:pm [intent] | Task / document lifecycle, project-scoped; split a spec into blocking tickets |
How It Works
- Vault I/O goes through the
obsidianCLI, run directly in the main context (no sub-agent). This plugin does not duplicate CLI syntax; it defers to the officialobsidian:obsidian-cliskill andobsidian help. - Daily notes use Obsidian's Daily Notes core plugin (folder / filename / template). Quick capture calls
daily:append. - Templates (
task,doc) live in your vault's Obsidian Templates folder. On/obw:initthe plugin copies starter files fromtemplates/only if the same name doesn't already exist — it never overwrites your edits. - Dashboards are Obsidian Bases (
.basefiles — core in Obsidian 1.9+) generated from plugin-internal templates via shell substitution, so contents never enter Claude's context.
Issue Pane
Run /issue <view> to list a view from the configured project's dashboard.base, created by /obw:pm, then select one to read its title, status, priority, and markdown body in the same pane. /issue with no argument opens the All Tasks view as an arrow-key list under the view picker: cards grouped by status (todo, in-progress, blocked, done), each heading with its card count, each row reading [H|M|L] <title> <due> <tags> sorted by priority, and done folded at the start. Click the list to give it the keys; ↑↓ move, PgUp/PgDn page, → or Enter opens a card or unfolds a heading, and ← goes back to the list or folds a heading. The list needs the terminal or desktop; elsewhere All Tasks falls back to the flat list other views use. Other views stay flat lists. A dashboard without All Tasks opens Active and says to run /obw:pm refresh dashboard. /issue <card> opens that card directly. The pane reports missing configuration, unavailable CLI output, and missing cards in place without adding vault content to the conversation.
A thin rule sets the card off from the list. Status and priority are coloured labels, followed by an AC <checked>/<total> count when the card's Acceptance Criteria section has checkboxes. Errors are drawn in red; progress and empty-list notices stay dim.
Mermaid blocks in the card body are drawn in the pane as text diagrams by uvx [email protected], which needs uv. uv is optional: without it, a block stays the code block it is in the card. A block also stays a code block when its diagram type is not supported, when it starts with a %% comment or --- frontmatter, or when termaid fails, prints nothing, or takes longer than 5 s. The card is drawn first and each diagram replaces its code block when it is ready, so the first run may show the code block until uv has fetched termaid.
A shown card has an Open in browser Button that renders the card body, Mermaid included, through the viz plugin's render.sh. The Button appears only when viz is installed, found through installed_plugins.json under $CLAUDE_CONFIG_DIR or ~/.claude, and only in the terminal. Opening the browser uses macOS open; over SSH the pane shows the page's URL instead. The pane reports where the card was rendered, or why it was not. The page opens on the machine running Claude Code: when you reach the session through a terminal multiplexer or relay that does not set the SSH variables (herdr, for example), the browser opens on that host, not on the device you are looking at.
To read the page from another device on your tailnet, proxy viz's port once with tailscale serve --bg --https=18090 18090. After each render the pane reads tailscale serve status --json and, when a mapping covers the page's port, adds a Tailnet: https://<machine>.<tailnet>.ts.net:18090/… line. The pane never creates a mapping itself; without one it shows only the opened page.
Test the plugin with:
claude plugin test obsidian-workspace
The pane needs Claude Code 2.1.287 or later, where Claude Mods are on by default. Built and tested against Claude Code 2.1.287.
Prerequisites
- Official
obsidianplugin (from theobsidian-skillsmarketplace) — declared as a plugin dependency, so it auto-installs with this plugin as long as that marketplace is added (claude plugin marketplace add) - Obsidian app running (headless CLI also works)
- Obsidian community plugin
obsidian-cliinstalled and enabled. The plugin's name isobsidian-clibut the executable it installs isobsidian(invoked asobsidian vault=<name> ...). This is not the unrelated standaloneobsidian-clibinary by Yakitrak. - Templates core plugin enabled (required for
/obw:pm—task/doctemplates) - Daily Notes core plugin enabled (required for
/obw:jotquick capture) - Bases core plugin enabled (required only for
/obw:pmdashboards — bundled in Obsidian 1.9+) - uv (optional; lets the
/issuepane draw Mermaid blocks as text diagrams throughuvx [email protected]— without it they show as code blocks) - viz plugin (optional; enables the
/issuepane's Open in browser Button — without it the Button is not drawn) - Claude Code 2.1.287 or later (required only for the
/issuepane; the skills do not need it)
Installation
/plugin install obsidian-workspace
Permissions (recommended)
Vault operations shell out to the obsidian CLI plus a few Unix helpers. To avoid repeated permission prompts, add these to user settings.json (~/.claude/settings.json) once:
{
"permissions": {
"allow": [
"Bash(obsidian:*)",
"Bash(cat:*)",
"Bash(jq:*)",
"Bash(cp:*)",
"Bash(sed:*)"
]
}
}
Or run /fewer-permission-prompts after a stuck /obw:init and it will scan transcripts and propose the same list.
Configuration
Run /obw:init in a project root. The generated .obsidian.yaml:
vault: MyVault
note:
default_folder: Inbox
filename_strategy: title # title | slug | timestamp-title
pm:
project: my-project # Omit this section to disable /obw:pm
Daily note folder / filename / template are not in .obsidian.yaml — they come from Obsidian's Daily Notes settings.
Vault Layout (/obw:pm)
pm/
├── dashboard.base # Cross-project dashboard (optional, Bases)
└── {project}/
├── dashboard.base # Project dashboard (Bases)
├── tasks/ # Active tasks
│ └── archive/ # Completed tasks
└── docs/ # Docs
Every project gets tasks/, docs/, and dashboard.base — /obw:init creates all three up front, so a project is never a bare folder.
Upgrading a vault from before 0.9: re-run /obw:init. It detects the old layout and offers, each separately, to move archive/ into tasks/archive/ (through the CLI, so links follow), backfill the title property on existing notes, and regenerate the dashboards with the new views. Existing filenames are never renamed.
A plugin update can add dashboard views. Run /obw:pm refresh dashboard to bring in All Tasks (and any other new template view) on an existing vault. The refresh regenerates dashboard.base from the template, so hand edits to that file are overwritten; it warns and asks first.
Filenames
All notes are kebab-cased (Implement Auth → implement-auth.md), for both /obw:jot notes and /obw:pm tasks / docs. Because Obsidian's {{title}} resolves to the filename, the human-readable title lives in the title property — that is what the dashboards display.
Property Schema
Dashboards and searches depend on these frontmatter fields. If you edit the installed templates, keep the field names.
- Task —
title,type: task,status(todo/in-progress/blocked/done),priority(high/medium/low),project,due(date),tags(list),parent(link),blocked_by(list of links),related(list of links),created,completed - Doc —
title,type: doc,project,created,updated
Task Relations
Tasks link to each other by wikilink through three properties — blocked_by, related, and parent (epic → subtask). There is no separate issue ID: the kebab filename is the handle, and Obsidian rewrites links when a note is renamed.
Only one direction is stored. What a task blocks, and what its subtasks are, come from Obsidian's backlinks pane — a blocks field alongside blocked_by would only drift. Adding a blocker sets status: blocked; archiving a task lists whatever still depends on it and asks before unblocking. Ticket splitting writes its blocking edges to blocked_by; the unblocked frontier is a search excluding -[blocked_by: wikilinks, not a view.
Examples
/obw:jot #worklog 完成 API 重構 PR,等 review
/obw:jot API Redesign Proposal --folder Architecture --tag design
/obw:pm add task implement-auth, high priority, due 2026-05-01
/obw:pm implement-auth is blocked by db-migration
/obw:pm implement-auth is done, archive it
/obw:pm split this spec into tickets
/obw:pm refresh dashboard
