Install
$ agentstack add skill-liuboacean-mubu-integration-mubu-integration ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ● Filesystem access Used
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
幕布集成 Skill
幕布(mubu.com)是一款极简大纲工具,支持将大纲一键转为思维导图。本 Skill 提供 API 集成能力。
权限与安全边界
本 Skill 以你的幕布账号身份操作远程真实内容,使用前请知悉其权限边界:
- 读取:仅读取环境变量
MUBU_PHONE/MUBU_PASSWORD/MUBU_MEMBER_ID(环境变量未设置时,才由仓库外的~/.workbuddy/.env.mubu补全;MUBU_MEMBER_ID即幕布 colla 成员 ID,仅save写回需要,登录后自动缓存到~/.mubu_token)。 - 写入:仅在本地写入 Token 缓存文件
~/.mubu_token(权限0o600+ 跨进程fcntl锁),不写入其它文件。 - 网络:仅访问
api2.mubu.com(base URL 可由MUBU_BASE_URL覆盖,但仅限mubu.com家族域名,防 MITM),无第三方服务、无遥测、无数据外发。 - 写操作需确认:真实会改动幕布内容的写操作为
create(新建)、rename_folder(重命名文件夹)、save(保存文档,端点/colla/events,需member_id)、move(移动,端点/list/custom/drag)、rename_doc(文档重命名,端点/list/rename_doc)、purge(彻底删除,唯一真实调用服务端删除,不可逆);delete现为软删除(仅标记进本地回收站,云端副本仍在)。save/move/rename_doc已在 v1.3.9 经真机验证可用。所有真实写操作均需显式传--yes才执行,否则中止并提示。 - 信任边界:Skill 不读取你的其它本地文件、不执行与幕布无关的 shell 命令;它只做「登录 → 读写你的幕布文档」这一件事。
功能概览
| 功能 | 接口 | 说明 | |------|------|------| | 用户登录 | POST /user/phone_login | 手机号密码登录获取 Token | | Token 刷新 | 自动处理 | access_token 2小时过期,临近过期自动重新登录(重登仅重试 1 次,杜绝死循环) | | 创建文件夹 | POST /list/create_folder | 在指定位置创建文件夹 | | 创建文档 | POST /list/create_doc | 创建新的大纲文档 | | 获取列表 | POST /list/get | 获取文件夹下的文档列表 | | 获取文档 | POST /document/edit/get | 获取文档详细内容(真实端点;body 为 docId+password+isFromDocDir,返回 data.definition 为 JSON 字符串需二次解析) | | 更新文档 | POST /colla/events | 保存/更新文档内容(v1.3.9 起可用;colla 协同端点,events 承载 changeset;需 member_id,私人文档由 MUBU_MEMBER_ID 或 token 缓存提供)| | 删除文档 | POST /list/delete_doc | 删除文档(按类型区分端点) | | 删除文件夹 | POST /list/delete_folder | 删除文件夹(原 /list/delete 实测非法,已弃用) | | 移动文档 | POST /list/custom/drag | 移动文档/文件夹到其他位置(v1.3.9 起可用;body dst/src/folderId,已真机验证)| | 导出 Markdown | 本地转换 | 将大纲结构转换为 Markdown |
API 基础信息
- Base URL:
https://api2.mubu.com/v3/api - 认证方式: JWT Token,通过请求头
Jwt-Token传递 - Content-Type:
application/json;charset=UTF-8
环境变量配置
在使用前,需要配置以下环境变量:
export MUBU_PHONE="your_phone_number" # 幕布账号手机号
export MUBU_PASSWORD="your_password" # 幕布账号密码
# 可选:幕布 colla 成员 ID(仅 save 写回需要;登录后自动缓存到 ~/.mubu_token,一般无需手动设置)
export MUBU_MEMBER_ID="your_collab_member_id"
> 切勿在脚本或代码中硬编码明文密码;凭据仅通过环境变量或仓库外的 > ~/.workbuddy/.env.mubu 提供。
使用说明
1. 使用 MubuClient
所有操作都通过 scripts/mubu/client.py 中的 MubuClient 类完成(scripts/mubu_api.py 仅为向后兼容的重新导出 shim,不再建议直接使用;不再有独立的 login() / create_folder() / create_doc() / get_list() / get_doc() / save_doc() / delete_item() 模块级函数)。实例化时自动读取 MUBU_PHONE / MUBU_PASSWORD 环境变量(或 ~/.workbuddy/.env.mubu)并加载本地缓存 Token:
from mubu.client import MubuClient
# 登录:凭据来自环境变量;返回扁平 data(token / id / name)
client = MubuClient()
info = client.login()
print(info["user_id"], info["username"]) # 注意是扁平 data["id"],非 data["user"]["id"]
# 按名称本地搜索文档/文件夹(递归遍历,大小写不敏感)
results = client.search("项目", max_depth=3, limit=50)["results"]
for r in results:
print(r["type"], r["name"], r["path"])
> 登录返回结构为扁平 data:data["id"]=用户 ID,data["name"]=用户名, > data["token"]=令牌。这与旧版嵌套 result["data"]["user"]["id"] 不同。
大纲内容格式
幕布文档内容使用特定的 JSON 格式表示大纲结构:
{
"name": "文档标题",
"nodes": [
{
"id": "node_1",
"text": "一级标题",
"children": [
{
"id": "node_1_1",
"text": "二级标题",
"children": []
}
],
"collapsed": false,
"finish": false,
"modified": 0
},
{
"id": "node_2",
"text": "另一个一级标题",
"children": [],
"collapsed": false,
"finish": false,
"modified": 0
}
]
}
Token 管理建议
由于幕布的 accesstoken 仅约 2 小时有效(无 refreshtoken 机制,代码也无任何 refresh 逻辑),建议:
- 本地缓存: 将 Token 保存到本地文件(如
~/.mubu_token) - 自动刷新: 在 Token 快过期时自动刷新
- 错误重试: 遇到 401 错误时重新登录
import os
import time
import json
import tempfile
TOKEN_FILE = os.path.expanduser("~/.mubu_token")
def save_token(token_data):
"""原子写 + 仅属主可读写:避免中途崩溃留下残缺文件,并防止其它用户读取。"""
token_data = dict(token_data)
token_data["expires_at"] = time.time() + 7200 # 2小时后过期
# 注:真实 scripts/mubu_api.py 的 _save_token 还会用跨进程 fcntl.flock
# advisory 锁包裹整段写(M4 已做成跨平台安全:无 fcntl 平台降级为无锁);
# 此处省略锁,聚焦写盘逻辑。
dir_name = os.path.dirname(TOKEN_FILE) or "."
fd, tmp = tempfile.mkstemp(dir=dir_name, prefix=".mubu_token.", suffix=".tmp")
try:
with os.fdopen(fd, "w") as f:
json.dump(token_data, f)
os.chmod(tmp, 0o600) # 仅属主可读写
os.replace(tmp, TOKEN_FILE) # 原子重命名,避免残缺文件
except Exception:
if os.path.exists(tmp):
os.remove(tmp)
raise
def load_token():
"""从本地加载未过期的 Token;已过期或损坏则返回 None。"""
if not os.path.exists(TOKEN_FILE):
return None
try:
with open(TOKEN_FILE) as f:
data = json.load(f)
except Exception:
return None
if time.time() >= data.get("expires_at", 0): # 已过期视为无效
return None
return data
说明:原示例中朴素的 is_token_valid 已移除——其职责("是否过期")已并入 load_token,仅返回未过期的 token。真实实现 scripts/mubu_api.py 的 _save_token 还包含跨进程 fcntl.flock 锁与统一的 TOKEN_FILE_MODE 权限管理,此处不再重复。
导出 / 导入 Markdown
M1 已落地真正的 Markdown 导入/导出(往返保真,不再是占位)。核心纯函数位于 scripts/mubu_api.py:
def doc_to_markdown(node, level=0):
"""将节点(及子树)渲染为 Markdown 列表片段。
'- ' 列表项,缩进 = 2 * level;含 checked → '- [x]'/'- [ ]';
含 note → 子树后追加 '> {note}'。根标题由 export_markdown 负责。"""
...
def export_markdown(doc):
"""doc 为 get_doc() 返回的 data 层 {"node": {...}}。
首行 '# 标题',其余递归为 '- ' 列表。结构无效时抛 MubuError。"""
...
def markdown_to_doc(md):
"""Markdown 文本 → {"node": {"id": "root", "text": ..., "children": [...]}}。
标题为顶层节点;多标题时首个为 root,其余作为 root 的 children;
列表项用栈按缩进深度维护层级;'- [ ]'/'- [x]' 设 checked;
'> ' 作为对应层级节点的 note。"""
...
导出示例(幕布 → Markdown):
# 读书笔记
- 第一章
- [x] 读完
- [ ] 写笔记
> 第一章的备注
> 说明:根节点的 text 渲染为 # 标题,其直接子节点从缩进 0 的 - 列表开始; > note 出现在其所属节点(含子树)之后,并按缩进深度归属到对应节点。
命令参考(CLI)
| 命令 | 说明 | |------|------| | login | 手机号密码登录,Token 本地缓存 | | list --folder [--include-trash] | 获取文件夹下的文档/子文件夹列表(--json 输出原始 JSON;--include-trash 包含已软删除项) | | mkdir --parent | 创建文件夹 | | create --folder [--content ] [--md ] | 创建文档;--md 从 Markdown 文件导入 | | get [--export markdown\|json] | 获取文档;--export markdown 输出真实 Markdown | | save [--file ] [--md ] [--content ] | 保存文档;--md 从 Markdown 文件导入 | | delete [--type doc\|folder] --yes | 软删除:移入本地回收站(云端仍在,restore 可恢复,purge 可彻底删除);--type 默认 folder,必须显式 --yes 才执行 | | restore | 从本地回收站恢复(仅移除标记,零服务端调用) | | purge --yes | 彻底删除(不可逆):调用服务端真实删除 API 后移除本地标记;必须显式 --yes 才执行 | | trash | 列出本地回收站中已软删除的项 | | move --target [--type doc\|folder] | 移动文档/文件夹到其他位置(v1.3.9 起可用,端点 /list/custom/drag,已真机验证)| | search [--max-depth N] [--limit N] [--include-trash] | 按名称本地搜索文档/文件夹(递归遍历,大小写不敏感;--include-trash 包含已软删除项) | | export-tree --folder [--output ] [--max-depth N] | 递归导出整个文件夹树为嵌套 Markdown 文件 | | rename --name [--type doc\|folder] | 重命名文档(/list/rename_doc 端点)或文件夹(已验证端点 /list/rename_folder,folderId 填自身 id)| | opml [--format opml\|freeplane] | 导出为 OPML 2.0 / FreeMind XML(兼容 XMind 等其它大纲工具)|
软删除 / 回收站(v1.3.5)
delete 现在不再是真正的服务端删除,而是软删除:
delete [--type doc\|folder] --yes—— 移入本地回收站:仅把项的元数据标记进本地回收站文件~/.workbuddy/.mubu_trash.json,云端副本保持不变,不调用任何删除 API。缺省(无--yes)仅打印提示并退出,绝不软删除。restore—— 从本地回收站恢复:仅移除本地标记,零服务端调用(即使云端项已不存在也安全)。未找到该项时提示「未找到回收站项」。purge --yes—— 彻底删除(不可逆):唯一真正调用服务端删除 API(delete_doc/delete_folder)的操作,成功后移除本地标记。必须显式--yes,否则中止。trash—— 列出本地回收站中已软删除的项(id / type / name / deleted_at)。
list --include-trash 与 search --include-trash 可在列表中包含已软删除项(get_list / search 默认过滤回收站项)。
> 回收站仅存元数据快照(id / type / name / parentid / deletedat),作为「云端仍在、可恢复」的安全网,不作为重建来源。
Markdown 往返示例:
# 导出为 Markdown
python3 scripts/mubu_api.py get --export markdown
# 从 Markdown 创建文档
python3 scripts/mubu_api.py create "我的文档" --folder --md ./outline.md
# 从 Markdown 更新文档
python3 scripts/mubu_api.py save --md ./outline.md
# 移动文档
python3 scripts/mubu_api.py move --target
# 按名称本地搜索文档/文件夹(递归遍历所有子文件夹,大小写不敏感)
python3 scripts/mubu_api.py search "项目"
python3 scripts/mubu_api.py search "项目" --json
# 递归导出整个文件夹树为嵌套 Markdown
python3 scripts/mubu_api.py export-tree --folder --output ./backup
# 重命名文档 / 文件夹
python3 scripts/mubu_api.py rename --name "新标题" --type doc
python3 scripts/mubu_api.py rename --name "新文件夹名" --type folder
# 导出为 OPML / FreeMind
python3 scripts/mubu_api.py opml --format opml
python3 scripts/mubu_api.py opml --format freeplane
Token 刷新策略
- access_token 有效期约 2 小时,本地以
expires_at缓存于~/.mubu_token。 - 每次请求发起前调用
ensure_valid_token():若未持有 token,或距过期不足
300 + 60(leeway)秒,则使用缓存的 phone/password 重新登录获取新 token。
- 刷新不依赖 refresh_token(M1 未启用)。
- 鉴权失败仅重试 1 次:
_request捕获 401 / 登录失效类错误后重新登录并重试最多一次;
第二次仍失败则抛出 MubuError,不再重登,避免密码错误/账号封禁场景下的死循环。
- 403(权限不足)或其它非 0 业务 code 不触发重登。
- Token 写入采用原子写(先写
.tmp再os.rename),写完追加os.chmod(TOKEN_FILE, 0o600),
确保 Token 文件仅属主可读写(M2 的 T5 已实现)。
配置说明
脚本通过环境变量读取凭据(优先级:环境变量 > ~/.workbuddy/.env.mubu 文件; 两者皆无时,login 子命令会交互式提示输入,绝不接受明文命令行参数):
export MUBU_PHONE="你的手机号"
export MUBU_PASSWORD="你的密码"
# 可选:幕布 colla 成员 ID(仅 save 写回需要;登录后自动缓存到 ~/.mubu_token,一般无需手动设置)
export MUBU_MEMBER_ID="你的幕布 colla 成员 ID"
也可在 ~/.workbuddy/.env.mubu 中配置(由 Skill 宿主加载为环境变量,且仅属主可读写):
MUBU_PHONE=你的手机号
MUBU_PASSWORD=你的密码
# 可选:幕布 colla 成员 ID(仅 save 写回需要;登录后自动缓存,一般无需手动设置)
MUBU_MEMBER_ID=你的幕布 colla 成员 ID
已知限制(M1)
expand(幕布大纲的折叠/展开状态)不在本期往返范围内,导入后节点默认展开。- 有序列表
1.不被解析,仅支持无序列表-。 - 图片 / 附件类型节点不在本期 Markdown 往返范围内(会丢失媒体内容)。
- 多个顶层标题导入时,首个为 root,其余作为 root 的 children;其后的列表项统一挂在
root 下(规范未要求按标题再嵌套)。
save(文档保存)需要幕布 colla 成员 ID:私人文档的memberId任何 API 都不暴露,由MUBU_MEMBER_ID环境变量提供,或登录后随 Token 缓存写入~/.mubu_token。缺失时会明确报错(不影响get/create/move/rename等其它操作)。v1.3.9 已修复save(/colla/events)、move(/list/custom/drag)、docrename(/list/rename_doc)的真机可用性。
注意事项
- 非官方 API: 幕布未提供官方开放平台,此 Skill 基于逆向分析实现
- 稳定性: API 可能随版本更新而变化,如遇问题请反馈
- 频率限制: 请勿频繁调用,避免触发限流
- 数据安全: Token 存储在本地,请勿泄露
Agent 使用指引
当用户提到幕布、mubu 相关操作(如将幕布大纲导入 Obsidian、把 Markdown 同步到幕布、查询/导出幕布笔记)时,使用本 Skill 的脚本完成操作。
前置检查
- 确认系统已安装 Python 3 和 requests 库:
``bash python3 -c "import requests; print('OK')" ` 如果缺少 requests:pip3 install requests`
- 确认环境变量已配置:
MUBU_PHONE— 幕布手机号MUBU_PASSWORD— 幕布密码- 如未配置,需提示用户先设置
脚本路径
~/.workbuddy/skills/mubu-integration/scripts/mubu_api.py
常用命令速查
| 用户意图 | 执行命令 | |---------|---------| | 登录幕布 | python3 scripts/mubu_api.py login | | 查看文档列表 | python3 scripts/mubu_api.py list | | 查看某文件夹 | python3 scripts/mubu_api.py list --folder | | 创建文件夹 | python3 scripts/mubu_api.py mkdir "文件夹名" | | 创建文档 | python3 scripts/mubu_api.py create "文档名" --folder | | 从 Markdown 创建文档 | python3 scripts/mubu_api.py create "文档名" --folder --md outline.md | | 获取文档内容 | python3 scripts/mubu_api.py get | | 导出为 Markdown | python3 scripts/mubu_api.py get --export markdown | | 从 Markdown 保存文档 | python3 scripts/mubu_api.py save --md outline.md | | 从文件保存文档 | python3 scripts/mubu_api.py save --file content.json | | 移动文档 | python3 scripts/mubu_api.py move --target | | 软删除(移入回收站) | python3 scripts/mubu_api.py delete --type doc\|folder --yes(云端仍在,restore 可恢复)| | 从回收站恢复 | python3 scripts/mubu_api.py restore | | 彻底删除(不可逆) | python3 scripts/mubu_api.py purge --yes(必须显式 --yes,调用服务端真实删除)| | 查看回收站 | python3 scripts/mubu_api.py trash | | 按名称搜索 | python3 scripts/mubu_api.py search [--max-depth N] [--limit N] | | 按名称搜索(含回收站) | python3 scripts/mubu_api.py search [--max-depth N] [--limit N] --include-trash | | 按名称搜索(JSON) | python3 scripts/mubu_api.py search [--max-depth N] [--limit N] --json |
典型工作流
场景 1:用户说"把这份大纲同步到幕布"
- 确认内容来源(文件或对话中直接提供)
- 如果是 Markdown,直接用脚本创建文档并导入
- 返回新文档 ID 和链接
场景 2:用户说"导出我的幕布笔记"
- 先列出文档列表让用户选择,或按名称搜索
- 获取文档内容
- 转换为 Markdown 格式返回
场景 3:用户说"在幕布建一个项目文件夹"
- 确认文件夹名称和层级结构
- 批量创建文件夹
- 返回创建结果
工作流示例
示例 1: 从 Markdown 创建幕布文档
用户: 把这份 Markdown 大纲同步到幕布
执行步骤:
- 解析 Markdown 结构
- 转换为幕布 JSON 格式
- 登录获取 Token
- 创建文档并保存内容
示例 2: 导出幕布文档为 Markdown
用户: 导出我的"读书笔记"文档
执行步骤:
- 登录获取 Token
- 本地搜索匹配文档:
python3 scripts/mubu_api.py search "读书笔记" - 获取文档内容
- 转换为 Markdown 并返回
示例 3: 批量创建文件夹结构
用户: 在幕布创建项目文档结构:需求分析、设计文档、开发日志、测试报告
执行步骤:
- 登录获取 Token
- 创建项目文件夹
- 批量创建子文件夹
- 返回创建结果
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: liuboacean
- Source: liuboacean/mubu-integration
- License: MIT
- Homepage: https://clawhub.ai/liuboacean/skills/mubu-integration
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.