扫码在其他设备打开

手机 / 平板打不开 moss:它只能在 Windows 10 / 11(64 位)电脑上运行。文档可以随便看,下载请用电脑。
mossmoss 文档
开始 / 什么是 moss

什么是 moss

moss 是一个 Windows 桌面软件,但它的功能不是出厂就定死的 —— 每个功能都是一个可插拔的插件,而 AI 就住在软件里面。你告诉它缺什么,它当场写好插件插进去。

一句话说清

你不装功能,你告诉它缺什么,它长出来。

宿主(moss.exe)本身几乎不提供业务功能,只干四件事:解析命令行、找解释器、把插件列表交给界面、等界面退出。其余全部以「包」的形式挂在 exe 外面。

宿主一个 exe,只管调度。加功能不用重新打包它。
插件一个目录 + pkg.json + 入口文件,任何语言。插上就能用,拔掉不影响别的。
技能AI 在干活途中给自己造的工具,你点「允许」后才生效。

它和普通 AI 有什么区别

聊天型 AI 给你一段答案或一段代码,剩下的(建项目、装依赖、开终端、记在哪)都得你自己来。moss 是软件形态的:成果直接变成软件里一个能点、能拖、能敲的功能,下次打开还在。

普通 AI 助手moss
交付物一段文字 / 一段代码一个装上就能用的插件
在哪里浏览器标签页,聊完就关桌面窗口,天天打开
能力边界模型能做什么就做什么缺什么就给自己长一只手(技能)
重复劳动每次都要重新描述一遍长出来的插件是资产,留在软件里

所以它既能像 agent 一样帮你干整理文档、批量改名这类普通工作,也能给程序员长真正用得上的工具 —— 而且这两种用法是同一套东西。

为什么这么拆

  • 加功能 = 丢一个目录,不用重新编译 exe。
  • 改界面不用重新打包:界面是 system/ui/ 里的网页,不属于任何插件,也删不掉。
  • 你的地盘和出厂件分开:user_data/ 打包时整体排除,升级只覆盖程序本体。
  • 一本契约:宿主、出厂插件、你自己写的包、AI 写出来的包,全部遵守同一份 插件契约。
第一次用,只差一件事

装好就能跑出厂插件;想让它「长功能」,先在 设置 → AI 填一次接口 —— 地址、密钥、模型三段,填完就不管了。见 AI 服务配置。

免费

软件本身免费,无订阅、无内购。AI 功能需要你自己填一个模型接口(DeepSeek、OpenAI、Kimi、通义、智谱、本地 Ollama 等),费用直接给你选的服务商,不经过我们。

接下来读什么

开始 / 安装与第一次启动

安装与第一次启动

moss 是绿色免安装的:解压、双击,没有安装程序,不写注册表,不写系统目录。整个过程不需要命令行。

装好之后第一件事:填 AI 配置

为什么先做这一步

只装不配也能用 —— 出厂插件直接跑。但「说一句话让它长新功能」这件事要靠 AI,所以要填一次接口(地址 / 密钥 / 模型)。

位置:设置 → AI。怎么填、填哪家的,见 AI 服务配置。

三步

  1. 解压到一个固定的文件夹 —— 建议 D:\soft\moss 或 D:\moss 这种你自己的目录。
    • 别放 C:\Program Files:它要往自己目录里写数据,那里没权限。
    • 别放桌面 / 下载目录:升级是整包覆盖,这两处容易被清理工具扫掉。
  2. 双击 moss.exe:直接打开界面。第一次运行会自己建 user_data\(你的插件、技能、配置、快照都在这儿)。
  3. 打开 设置 → AI,填一次接口:填完就能让它长功能了。

装完长这样

moss 主界面:左侧插件列表,右侧插件详情、命令与设置

左边是插件列表,右边是选中插件的详情 / 命令行 / 文件 / AI。它们的作用见 界面导览。

压缩包里只有两样东西

内容说明
moss.exe宿主内核:解析命令行、找解释器、装插件、开界面
system\发行目录:界面、出厂插件、插件契约、技能手册、自带 Python 运行时

user_data\ 不用手动建 —— 第一次运行自动生成。使用说明和开发文档也没放进压缩包(为了目录清爽),完整内容就在这个文档站上。为什么这样不影响 AI 干活,见 目录结构。

不确定环境对不对?

进阶:用自检命令查一遍

习惯命令行的,可以在解压目录开一个终端跑 moss.exe --selfcheck:逐项检查安装根、runner 表、插件能不能读到、自带运行时在不在、cd 增强有没有装。

不习惯命令行也没关系:双击打不开、或者界面白屏,绝大多数情况是目录放错了(比如放进了 Program Files,写不了 user_data)。

把它接进命令行(可选)

不用命令行的可以跳过这一节。想让任何终端、任何目录都能直接敲 moss:打开界面 → 设置 → 命令接入 → 勾选「把 moss 加进系统 PATH」,然后新开一个终端(旧窗口不会自动刷新环境变量)。

moss                # 用法 + 插件列表
moss ui             # 打开界面
moss :md5 你好      # 跑一个插件

几件要知道的事

不用装 Python

自带独立的 Python 运行时(system/runtimes/python),插件都用它跑。你机器上装没装 Python、装的哪个版本,都不影响。

Windows 提示「未知发布者」

目前没有买代码签名。首次运行点「更多信息」→「仍要运行」即可。它不联网(AI 除外,那部分只连你自己配的模型接口)、不写注册表、不写系统目录。

升级与搬家

升级只覆盖 moss.exe 和 system\,user_data\ 一个字都不动。想搬家 / 备份:整个文件夹拷走就行 —— 路径不写进注册表。

开始 / 界面导览

界面导览

主界面就一个窗口:左边插件列表,右边是选中插件的详情、命令、文件、AI。moss ui 或双击 moss.exe 打开。

先看这里:设置 → AI 是核心配置

不填它,软件只能用出厂插件;填了它,才能「说一句话让它长新功能」。位置在右下角齿轮里的第一组,填法见 AI 服务配置。

一图看懂

moss 主界面:左侧插件列表,右侧插件详情、命令输入与高级设置

左边:插件列表

  • 顶部搜索框按包名 / 说明 / 标签过滤,敲几个字就缩到几个。
  • 左上一个开关在「插件 / 历史」之间切换:历史里是最近跑过的路径调用,点一下重跑。旁边那颗按钮能把左栏收起,只留图标(宽度会记住)。
  • 列表工具条:筛选(全部 / 系统 / 用户)、排序(名字 / 加入时间 / 最后运行 / 自定义拖动排序)、刷新、新建包。
  • 拖动文件经过窗口时,这里会浮出一条提示,只列出收得下它的插件。

右边:五个选项卡

选项卡里面是什么
详情插件说明、参数表单、「使用说明」卡(来自包里的 README.md)、自动启动开关、DROP 提示
命令行一条命令输入框 + 终端输出。它等价于在终端敲 moss :包名,插件需要问一句话也能在这里答
文件管理浏览插件目录、看源码、看改动差异、管理版本快照、一键回退
AIAI 工作台:聊天 + 它这一轮读了什么、改了什么、跑了什么(见 AI 工作台)
界面只有插件声明了内嵌界面时才出现:把插件自己的网页嵌进来当标签页用

底部状态栏

左边是最近一条状态提示,右边那颗齿轮就是设置(等于打开 user_data/config.toml 的图形版)。设置面板分七组,详见 设置详解。

拖进来就跑

从资源管理器往窗口里拖文件或文件夹,会浮出一层遮罩,只列出声明了能接这种输入的插件,松手就跑。拖图片、拖 txt、拖文件夹分别会发生什么,见 拖进来就跑。

没有控制台时直接开界面

双击 exe、快捷方式、快速启动栏 —— 这时候没有终端可写,moss 直接开界面;在终端里敲 moss(不带参数)则打印用法和插件列表。带参数时一律按参数干活,不看有没有控制台。

开始 / 命令行基础

命令行基础

不习惯命令行?这一页可以跳过

日常使用完全不需要终端:装好 → 双击 → 点插件 → 拖文件。这一页是给「愿意用键盘」的人准备的加分项,先看 界面导览 也一样能上手。

界面能做到的事,命令行都能做到 —— 而且命令行能做的事,界面不一定有。四件最常用的事先记住就够。

四种入口

你敲的它干什么
moss打印用法 + 插件列表
moss ui打开界面
moss :<包名> [参数]跑一个装好的插件,例如 moss :md5 你好
moss <名字>在当前目录(及向上几层)找匹配的脚本并运行,例如 moss m → main.py / main.go / main.html

找脚本的写法(不带冒号)

moss m              # 当前目录下找 main.py / main.go / main.html
moss b/m            # 进 b 开头的子目录,再找 m 开头的
moss s/t/main       # 逐级往下
moss /m             # 同 moss m,但不切换目录
moss ~m             # 后台脱离运行,不阻塞当前控制台
moss zeen           # 文件系统里没找到?去历史里找上次那个 ZeEn(命中多个取最近的)

跑插件:两种参数写法

位置参数按插件声明的顺序来,key=value 则按名字来 —— 两种都行:

moss :my-first 你好 3
moss :myfirst text=你好 times=3

插件可以把某个参数标成 rest: true,意思是「剩下的全归我,我自己解释」—— img 就是这种:

moss :img webp 60% 1200 *.png -o D:\out

符号可以改

行首那个符号决定命令的种类,默认是:

符号含义默认
路径调用找脚本跑(裸名)
跑包跑装好的插件:
不切目录在当前目录里跑/
后台脱离不阻塞控制台~

如果你的主要用途是「跑装好的插件」,可以在 设置 → 快捷命令 里把「跑包」留空、把「路径调用」设成 : —— 于是 moss img 直接跑包,moss :img 才是找文件。

不知道敲什么

命令用途
moss --history最近跑过什么,方向键选,回车重跑
moss --spec打印插件契约(写插件前读它)
moss --resolve <名字>只看解析结果不执行:为什么选中它 / 为什么没找到
moss --selfcheck自检环境

完整清单见 命令大全。

用起来 / 出厂插件清单

出厂插件清单

发行版自带 17 个插件,开箱就能用。它们和 AI 新长出来的插件、你自己写的插件,用同一套契约、同一套界面 —— 没有任何区别。

怎么跑

界面上点插件再点「运行」,或者命令行 moss :<包名> [参数]。下面每条都给了最常用的写法。

一览

包名名称类型一句话
exec快捷执行界面命令脚本管理器:把常跑的命令存成一张卡片
fanyi快捷翻译界面双击 Ctrl 翻译选中文字并自动粘贴
paste贴边快输界面常用文本 / 剪贴板快速粘贴
img图片工具界面 + 命令行图片压缩 / 格式转换 / 多分辨率 ico
pathPATH 管理界面管理用户 PATH,带备份和差异对比
pipPip 工具界面图形化 Python 包管理器
skill技能界面AI 给自己造的工具都在这儿:允许 / 撤销 / 删除 / 转插件
githubGitHub 可视化助手界面 + 命令行看得见的 git:时间线、同步、镜像、恢复
sync文件同步界面按文件名规则把文件归到该去的地方
h历史快捷运行命令行moss :h 名字 在原来的目录里重跑一次
md5MD5 计算命令行算字符串 / 文件 / 文件夹的 MD5
tree目录树命令行按 .gitignore 过滤的目录树
mark目录书签命令行记下目录,下次一句话跳过去
kill杀进程命令行按进程名或端口结束进程
ipIP 查询命令行查本机出口 IP 或某个 IP 的归属
suoluetu图标修复命令行重建 Windows 图标缓存
dshDSH 桥界面 + 守护在外面访问这台机器上的 DSH(需要账号)

效率与输入

exec · 快捷执行

多语言的命令脚本管理器:把常跑的命令存成一条一条,下次点一下或敲个别名就跑。界面是 Apple 风格的 WebView,可以内嵌成 moss 的标签页,也能自己开窗。

moss :exec                 # 打开管理器
moss :exec list            # 列出存过的命令
moss :exec 别名 参数        # 不打开界面,直接跑那条

类型 app · 数据在 user_data/state/exec

fanyi · 快捷翻译

选中任何一段文字,双击 Ctrl 就翻译并自动粘回去。多个翻译通道自动切换(Google / 有道 / MyMemory),带本地缓存;界面是热键的可视化台(四步进度、任务卡、日志、历史)。

moss :fanyi                # 打开界面,调热键和查看历史

类型 app · 需要联网 · 会读写剪贴板、注册全局热键

paste · 贴边快输

把常用文本(签名、地址、常用回复)分组存好,需要时贴边弹出、一键粘贴。分组之间热键可以重复、也能同时启用多个分组,窗口可拉伸。

moss :paste

类型 app · 会读写剪贴板、注册全局热键

h · 历史快捷运行

moss --history 的短名字版:按名字找回以前跑过的目标,先切到它当时的目录再跑一次,省掉 cd。

moss :h                    # 列出最近记录
moss :h zeen               # 重跑上次那个 ZeEn
moss :h wwwroot/zeen/main  # 逐级写法也认,/ 和 \ 都行

类型 task · 别名 hist / history

mark · 目录书签

在某个目录里敲一下就把这个目录记下来,下次给个关键字就直接跳过去。

moss :mark                 # 记录当前目录
moss :mark list            # 列出所有书签
moss :mark 项目            # 按关键字找并切过去
moss :mark --gui           # 打开界面编辑

类型 task · 只收文件夹拖入 · 数据在 user_data/state/mark

文件与图片

img · 图片工具

压缩、转格式(jpg / png / webp / bmp / gif / tiff)、生成多分辨率 ico。不带参数打开界面(缩略图选择器,可框选、可拖文件夹);带参数走命令行,语法很短、顺序随便。

moss :img                              # 打开界面
moss :img ico a.png -o D:\out          # 转成 ico 放到 D:\out
moss :img webp 60% 1200 *.png -o D:\out   # 转 webp,质量 60、宽 1200
moss :img 1200 -o D:\out               # 全部缩到 1200 宽,格式不动
moss :img 60% /                        # 全部按 60% 重压,写回源目录
必须指定输出位置

命令行里必须给 /(写回源目录)或 -o <目录>,否则它会弹菜单让你选;没有终端可交互时(脚本、管道、AI 调用)直接报错说明该补什么 —— 不会替你猜、更不会覆盖原图。

类型 app · 只收图片扩展名拖入 · -s 16,32 可指定 ico 尺寸

sync · 文件同步

按文件名规则把一堆文件归到该去的地方 —— 下载目录收拾、照片按日期归档这类活。支持把文件夹直接拖进来。

moss :sync                 # 打开界面配规则

类型 app · 收文件夹拖入

tree · 目录树

生成目录树,按 .gitignore 和内置忽略表过滤(node_modules、venv、__pycache__ 这类不会刷屏)。

moss :tree                 # 当前目录
moss :tree docs 2          # docs 目录,深度 2
moss :tree docs 2 -a       # 连隐藏文件一起
moss :tree -node_modules,dist  # 再额外忽略几个名字

类型 task · 收文件夹拖入 · 已对 AI 开放

md5 · MD5 计算

算字符串、文件或整个文件夹的 MD5,结果自动进剪贴板。不填参数就用剪贴板里的内容算。

moss :md5 D:\a.txt
moss :md5 "一段文字"       # 带引号强制按字符串算
moss :md5                  # 算剪贴板里的内容

类型 task · 收文件 / 文件夹拖入 · 已对 AI 开放

suoluetu · 图标修复

桌面图标变成白纸、显示错乱时用它:关掉 explorer、删掉 IconCache.db、再把 explorer 拉起来。屏幕会闪一下,属于正常。

moss :suoluetu

类型 task · 会重启资源管理器

系统与网络

path · PATH 管理

查看和管理 当前用户的 PATH(不需要管理员)。带备份时间线:改动前先存一份,出问题双击就能回退;还能去重、清理失效目录、拖动调整优先级。

moss :path                 # 打开界面
moss :path add D:\tools\bin
moss :path remove D:\old\bin
moss :path add             # 不加路径 = 加这个插件自己的目录
moss :path help

类型 app · 动的是 HKCU\Environment\Path · 改完广播 WM_SETTINGCHANGE,新开终端生效

pip · Pip 工具

图形化的 Python 包管理器:查 / 装 / 卸 / 升级 moss 自己那个 venv 里的包,带 PyPI 搜索、交互式 Shell、操作日志。

moss :pip                  # 打开界面(别直接双击它的 exe)

类型 app · 给插件装依赖时用它,不要动系统 Python

kill · 杀进程

按进程名(大小写不敏感的包含匹配)或端口号结束进程。命中多个时会按可执行文件路径分组,上下键选一组,或者一次清理全部 —— 不会糊里糊涂把同名的别的程序一起杀了。

moss :kill node
moss :kill 8080            # 纯数字 = 找正在监听这个端口的进程

类型 task · 风险等级 high(不会给 AI 调)

ip · IP 查询

查本机当前出口 IP,或某个 IP 的归属地 / 运营商(走 ip-api.com,需要联网)。

moss :ip                   # 本机出口 IP
moss :ip 8.8.8.8           # 查某个 IP

类型 task · 已对 AI 开放

开发与远程

github · GitHub 可视化助手

把 git 状态变成看得见的东西:提交时间线(标出哪些已推送)、一键同步、一键镜像(建远端仓库 / 本地备份 / 加镜像远端)、把某个版本从 GitHub 恢复出来、切分支,本地和远端并排看。拖一个目录进来就换当前仓库。

它的每个按钮都会告诉你等价的 git / gh 命令和原样输出 —— 拿它当 git 的学习器也合适。

moss :github                       # 打开界面
moss :github status D:\code\my-repo
moss :github log

类型 task + 内嵌界面 · 别名 git · 收文件夹拖入

skill · 技能

AI 给自己造的工具(技能)都在这里:图标墙、详情、文件列表、时间,可以允许 / 撤销 / 删除,也能一键转成正式插件。第一次启用必须由人点 —— AI 自己批不了。

moss :skill                        # 打开管理器
moss :skill list                   # 列出技能
moss :skill show <id>              # 看详情
moss :skill allow <id>             # 允许(AI 下次开工才带上)
moss :skill revoke <id>            # 撤销
moss :skill rm <id>                # 删除
moss :skill promote <id> [新id]    # 转成插件,搬进 user_data/pkgs

类型 app · 用户层在 user_data/state/skill/,预制层在 system/pkgs/skill/builtin/

dsh · DSH 桥

在别的设备上访问这台机器上的 DSH:本机起一个桥守护进程,主动连出做 NAT 穿透,带本机密码票据门,把请求转发到 127.0.0.1:3080;DSH 没在跑时会自动把它拉起来。

moss :dsh                  # 前台运行(Ctrl+C 停止)
moss :dsh --daemon         # 转后台守护
moss :dsh --status         # 看配置摘要
moss :dsh --set-token      # 改令牌
moss :dsh --set-password   # 改本机密码
有前置条件

需要本机有 node + @deepseek-ai/dsh,并且要在服务器上注册一个账号、在设置页登录。不满足就只是一个跑不起来的空壳。

类型 app · 风险等级 high

用起来 / 拖进来就跑

拖进来就跑

不用先打开插件、不用选参数:把文件或文件夹拖到 moss 窗口上,能处理它的插件自己亮起来,松手就跑。

三个真实例子

拖一张图片:照片.png

拖动过程中,窗口里只亮两个插件:图片工具和 MD5。松手落到哪个上,就跑哪个:

  • 落到图片工具 → 打开它的界面并把这个文件带进去,可以直接压缩、转格式(jpg / png / webp / ico)、批量处理。
  • 落到 MD5 → 直接算出这个文件的 MD5,结果自动进剪贴板。

为什么只亮这两个:图片工具在声明里写了自己只收 jpg / jpeg / png / bmp / gif / tiff / webp,MD5 没限制扩展名(什么都收)。没声明的插件在这一刻根本不会出现 —— 不会把你的图片塞给处理不了它的插件白跑一趟。

拖一个文本:会议记录.txt

只有一个插件会亮:MD5,因为它没有限制扩展名。落上去就是算这个文件的 MD5。

「我要的是把 txt 整理归类 / 转成 PDF / 提取里面的待办」—— 这些出厂插件里没有,但那正是它的用法:打开 AI 工作台说一句,它长一个能接住 txt 的插件出来;长好之后,你再拖 txt,列表里就会出现它。

为什么不多亮几个:宿主不会为了"看起来丰富"给你一堆接不住的东西。默认列表是空的,缺什么就长什么。

拖一个文件夹:下载

这时会亮起一串(每个都是把整个目录当工作目录):

插件拖进去之后
目录树立刻生成这个文件夹的树,按 .gitignore 过滤,node_modules、venv 这类不会刷屏
目录书签记下来,下次一句话就跳过去
文件同步按你的规则把里面的文件归到该去的位置
图片工具把这个目录里的图片全部拉进界面,批量压缩 / 转格式
GitHub 可视化把这个目录当成当前仓库,打开提交时间线
PATH 管理把这个目录加进用户 PATH

为什么是这些:声明了「我收文件夹」的插件才收。能用文件夹解决的就不去写「只收单个文件」—— 声明窄一点,拖动时候选列表才干净。

那一瞬间,是 AI 在判断吗?

不是。拖动的筛选是宿主按每个插件的 drop 声明做的:纯本地、瞬间出结果、不联网、不花 token。AI 在更前面一层:

分工是这样的

① 谁能接什么 —— 插件自己在 pkg.json 里声明,宿主照单筛选;
② 缺哪一类插件 —— 你跟 AI 说一句,它读契约、写代码、真机跑通,长出一个;
③ 长出来的插件 —— 和出厂插件完全一样,下一次拖动列表里就有它。

所以你会看到两种体验:拖现成的东西 → 秒出候选;缺一类处理 → 说一句话,之后再拖就有了。这两件事都不需要你写配置或改代码。

没有插件接得住的时候

遮罩里是空的,什么都不会跑 —— 不会硬塞给某个插件。这时候直接跟 AI 说你的需求,或者到 出厂插件清单 看看是不是已经有能用的。

是怎么交给插件的

声明效果典型例子
cwd: true把它当工作目录;拖文件时取文件所在的目录目录树:在那个目录生成树
param: true路径追加到参数末尾(带引号,空格路径也安全)MD5:算这个文件的 MD5
base: true只给文件名(配合 cwd)需要相对路径的场合

自己写插件、想让它收拖入:见 收拖入。

用起来 / 历史、cd 与短命令

历史、cd 与短命令

每天要敲的那几条路,moss 都帮你记着:跑过什么、在哪跑的、怎么少敲几个字。

刚才跑的再跑一次

moss --history        # 方向键选,回车直接重跑(去重,最多 20 条)
moss --history 50     # 只打印不交互(管道 / 脚本用这种)

回车进入程序后,程序退出就结束,不会回到列表 —— 不会出现「退不出来」的死循环。

记录存在 user_data/history,可以手动看。

按名字重跑

:h 插件是「历史」的短名字版:按关键字找回那次调用,先切到它当时的目录再跑,省掉 cd。

moss :h                    # 列出最近记录
moss :h zeen               # 重跑上次那个 ZeEn
moss :h wwwroot/zeen/main  # 逐级写法,/ 和 \ 都行

文件系统里找不到 moss zeen 时,宿主也会自动去历史里找同名那次(命中多个取最近的)。

跳到某个目录

moss cd 项目               # 智能找目录并切过去
moss cd --install          # 把包装函数写进 PowerShell 配置 → 屏幕上不留回显
moss cd --uninstall        # 删掉那个包装函数

没有包装函数时,它靠「认出父 shell 并把命令注入控制台」实现,代价是屏幕上会看到它注入的那行命令;--install 之后这一行也没了。

短命令:把 moss :img 缩成 moimg

设置 → 短名设置 里打开,它会在 PATH 上放一个目录,里面是一批小短名。前缀默认 mo:

开关效果
「前缀」= mossmo 一条 ⇒ 等于敲 moss
「前缀+包名」= moss :包名moimg ⇒ 等于敲 moss :img
moss --alias status     # 看现在生成了哪些短名
moss --alias sync       # 手动对账(装了新插件后跑一下)

前缀可以改(shortcut.prefix),短名目录在 user_data/shortcuts。

排障:为什么没找到 / 为什么选中它

moss --resolve img      # 只看解析结果,不执行

它会告诉你这个名字最后落到了哪个插件、哪一层(user_data/pkgs 还是 system/pkgs)、还是根本不是插件。

用起来 / AI 工作台

AI 工作台

界面右边那个 AI 不是聊天框,是一个能动手的循环:读契约、读插件、改代码、跑命令、看退出码,跑通了才算完成。

它一轮在干什么

  1. 读插件契约(system/spec/ 那份,唯一真相)
  2. 读现有插件的代码,或看你这句需求该落在哪个包
  3. 用 search / replace 发改动(不是重写整个文件)
  4. 跑 moss :<id> … 真机验证,看退出码和输出
  5. 不过关就自己回头改,直到跑通才交给你

四条硬规矩(这些不是提示词,是代码里的闸)

规矩为什么
改文件只发 search/replace同样改 3 行输出几十 token 而不是几千;也不会出现「重写时悄悄丢一段」
done 是硬闸最后一次改动之后必须有一次退出码 0 的运行,否则把话打回去继续 —— 不是「模型说完成了」
每一步记 token把「费不费」从感觉变成数字
写权限是一张清单一个目录一对「读 / 写」勾,没勾的地方读都读不了
硬锁目录

core/、moss.exe、moss.py、venv/、.git/、备份库在底层写死保护 —— 就算你勾了「任意路径」也写不了。这条是结构性的,不靠自觉。

动手之前先留一份快照

每一轮对话里第一次改文件之前,宿主会强制存一条「动手前」的版本快照,标题就是你当时说的那句话 —— 之后改坏了,在文件管理里点一下就退回。快照机制见 版本快照与回退。

它怎么用「手」

它手上的工具只有几类:跑 moss 命令(run_moss)、读写你授权过的目录、读契约与技能手册、以及给自己造技能(见 技能)。它不是靠猜,而是靠跑。

怎么用得好

  • 说清「要什么」和「怎么算成功」,别只说「优化一下」。
  • 给一个真实输入的例子:文件名长什么样、在哪个目录、想要什么输出。
  • 它说改好了,你看一眼命令行选项卡里的运行结果 —— 那就是它的验收证据。
  • 不满意就继续说,它会接着改;改到一半发现方向不对,用快照退回去重来。
先配接口

AI 需要一组模型接口(地址 / 密钥 / 模型)。第一次用先看 AI 服务配置,在 设置 → AI 里填一次即可,支持多组切换。

用起来 / 技能:AI 的手

技能:AI 给自己造的手

AI 干到一半发现宿主没给它这个能力(截屏、量像素、解析一个怪格式),可以当场给自己造一个工具 —— 但那只是「声明」,你要点一次「允许」,它下次开工才带上。

技能就是插件

语法一字不差:一个目录 + pkg.json + 入口文件。区别只有三处:

插件技能
住哪user_data/pkgs/<id>/user_data/state/skill/<id>/
谁用你(也能被 AI 调)AI 自己,在你的授权范围内
怎么生效放进去就在列表里必须由你点「允许」

声明 ≠ 授权

插件里写 "ai": {"expose": true} 只是它声明「我可以被 AI 调」,默认是 false(装了 100 个插件,不该 100 个都能被 AI 调)。真正能不能用,还要看 user_data/ai/skills_allow.json 里有没有你的授权,而且绑指纹 —— 包改了就作废,要重新允许。

AI 不能给自己发通行证

allow / revoke / rm / promote 这四个动作只能人做。AI 拿 run_moss 去调这几个词,宿主直接拒掉。这是设计出来的闸,不是防君子。

管理技能

moss :skill                        # 打开管理器(图标墙 / 详情 / 文件 / 时间)
moss :skill list                   # 列出所有技能
moss :skill show <id>              # 看它是什么、为什么造、用了什么
moss :skill allow <id>             # 允许:下一次开工才进工具表
moss :skill revoke <id>            # 撤销
moss :skill rm <id>                # 删掉
moss :skill promote <id> [新id]    # 转成正式插件(搬进 user_data/pkgs)

技能在插件列表里看不见 —— 它不住 user_data/pkgs/。要找它就去「技能」这个插件里找。

什么时候它会造

只有一种情况:缺一个能力,而且这次任务里要反复用。一次性的活它会直接写脚本进你的包,不动技能库。

觉得某个技能好用,就在管理器里 转成插件 —— 它就变成正常插件了:出现在列表里、能被你手动跑、也能被别的流程调。

用起来 / 版本快照与回退

版本快照与回退

改坏了不用重来。快照按内容寻址存,同一个文件存一百次也只占一份;恢复的时候只写回真正变了的文件,别的文件一个都不碰。

界面里怎么用

选中插件 → 文件管理 选项卡:左边是文件,右边是版本快照列表。点一条快照能看「那次动了哪几个文件」,再点「回退」就回到那一刻。

moss 的文件管理页,右侧是版本快照列表和那次快照里的文件

命令行里怎么用

命令干什么
moss --snap list [对象]列出快照;不给对象就是按组汇总
moss --snap save [对象] [--title T]存一次快照;不给路径 = 当前目录
moss --snap show <id>看那一次的清单(有哪些文件)
moss --snap diff <id>和现在比:一致 / 变了 / 快照有我没了 / 我有多
moss --snap revert <对象>一键「对比 + 回退」:先列变了什么,再按只写回对齐
moss --snap restore <id>恢复;默认只写回,--sync 则一模一样(多出来的进回收站)
moss --snap grep <对象> <关键词>在快照里搜内容 —— 包改废了就查原来怎么写的
moss --snap cat <对象> <路径>看快照里某个文件的内容
moss --snap check按指纹校验内容块,被改过 / 丢了当场看得见
moss --snap ignore看过滤规则(哪些文件不会被存进去)
moss --snap gc回收没人引用的内容块

「对象」可以是插件,也可以是路径

moss --snap save :md5              # 插件:写在它自己的组里
moss --snap save D:\proj\x         # 外部目录也行(落在 @abs-xxxxxxxx 组里)
moss --snap group D:\proj\x        # 只算不存:这个对象会落到哪个分组
moss --snap list                   # 不给对象 = 按组汇总
会动磁盘的动作必须显式 --yes

restore / export / rm / gc 不加 --yes 只打印「会干什么」,不动手。加 --json 得到结构化输出(给脚本 / AI 用)。退出码:0 成功、2 用法错、3 没东西可做、4 出错。

哪些文件不进快照

规则文件是 user_data/snapshot.ignore,写法同 .gitignore 的常用那几条。node_modules、venv 这类默认就被挡在外面,所以快照不会一存几百兆。

和 AI 的关系

AI 每次动手前存的那条叫「动手前」快照(by="ai")。它只能删自己存的 —— 你自己存的那份,它删不掉,这是结构性保证。

用起来 / 设置详解

设置详解

界面右下角那颗齿轮打开设置面板,七组 —— 第一组 AI 是核心,其余按需要再动。它背后就是 user_data/config.toml —— 那个文件里每一项都带注释,直接改也完全可以。

七组

分组管什么常动的东西
AI 核心模型接口(可以多组)地址 / 密钥 / 模型 —— 不填它就只能用现成插件,不能长新功能。见 AI 服务配置
命令接入让 moss 在命令行里好用「把 moss 加进系统 PATH」、cd 增强
快捷命令行首符号决定命令种类路径调用 / 跑包 / 不切目录 / 后台脱离 四个符号
短名设置把 moss :img 缩成一条短命令前缀、两种短名开关
执行提示每次运行前 / 后打印的那几行清屏、打印命令、目录、PID、耗时、开始结束时间
输出格式那几行的文字样式起始 / 结束横幅、行首符号
高级设置不常动的三项向上查找层数、Ctrl+C 是否强杀整棵树、退出时是否结束插件进程

配置文件长什么样

user_data\config.toml     # 宿主配置(每项都有注释,直接打开就知道是干什么的)
user_data\config.toml.bak-…   # 改配置前自动留的备份
面板和文件是同一份数据

设置面板不认识任何设置项、也不自己实现校验规则 —— 规则只有 core/config.py 那一份。所以你在面板里改和在文件里改,效果完全一样;面板只是把「现在这样 / 为什么冲突」摆出来。

自动启动不在设置里

「开机 / 登录自动运行某个插件」在插件详情页里(详情 → 自动启动),不在设置面板。因为那是每个插件自己的属性,放在详情里才直观。

几个容易找错的开关

  • 想让 moss img 直接跑插件而不是找文件 → 快捷命令:跑包留空、路径调用填 :。
  • 嫌每次运行前清屏太跳 → 执行提示:关掉「运行前清屏」。
  • Ctrl+C 杀不干净子进程树 → 高级设置:打开「第一次按 Ctrl+C 就强杀整棵树」。
  • 升级后短名失效 → moss --alias sync 手动对账一次。
写插件 / 三分钟写第一个插件

三分钟写第一个插件

一个插件 = 一个目录 + pkg.json + 一个入口文件。不用改宿主、不用重新打包 exe、不用配环境。

1. 生成骨架

moss --new hello
moss --new hello name=打个招呼 desc=把输入重复几遍

它会在 user_data/pkgs/hello/ 生成三个文件:

user_data/pkgs/hello/
├─ pkg.json     声明(零代码)
├─ run.py       入口(真代码)
└─ AGENT.md     给 AI 看的说明:怎么调、有什么副作用、会怎么失败

2. pkg.json

{
  "spec": 1,
  "id": "hello",
  "kind": "task",
  "version": "0.1.0",
  "name": { "zh-CN": "打个招呼" },
  "desc": { "zh-CN": "把输入重复几遍" },
  "aliases": ["hello"],
  "runner": "python",
  "entry": { "file": "run.py" },
  "params": [
    { "name": "text",  "type": "string", "default": "你好", "desc": "要重复的内容" },
    { "name": "times", "type": "int",    "default": 1,      "desc": "重复几遍" }
  ],
  "output": { "mode": "json", "schema": { "text": "string", "times": "int" } }
}

3. run.py

import json, os

params = json.loads(os.environ.get("MOSS_PKG_PARAMS") or "{}")
text  = str(params.get("text") or "你好")
times = max(1, min(int(params.get("times") or 1), 100))

for _ in range(times):
    print(text)                                  # 给人看

data_dir = os.environ["MOSS_PLUGIN_DATA_DIR"]
os.makedirs(data_dir, exist_ok=True)             # 宿主只给路径,目录自己建

with open(os.environ["MOSS_RESULT_FILE"], "w", encoding="utf-8") as f:
    json.dump({"text": text, "times": times}, f, ensure_ascii=False)   # 给机器看

4. 跑它

moss :hello
moss :hello 你好 3          # 位置参数
moss :hello text=你好 times=3   # 或者按名字

界面上也会立刻出现这个插件 —— 不用重启 moss,列表是按目录实时扫的。

5. 改到满意

  • 参数不够用?在 params 里加一条,界面上自动长出对应的输入框。
  • 输出要给人看?print 就进「命令行」选项卡。
  • 输出要给别的程序 / AI 用?写 MOSS_RESULT_FILE。
  • 要界面?别自己开窗口,把界面写成网页并声明 ui.embed,见 界面:一份代码两种跑法。
放哪儿

自己用 → user_data/pkgs/<id>/(升级不碰)。要随 moss 一起发出去 → system/pkgs/<id>/(升级会整体替换成新版)。同名时用户层压住出厂层,出厂原件还在。

6. 验收

改完跑一遍,退出码 0 才算过:

moss :hello 你好 2
echo $LASTEXITCODE

出问题先自己看三样:命令回显、报错原文、moss --resolve hello 说它落在哪一层。

写插件 / pkg.json 字段表

pkg.json 字段表

唯一的格式规范。完整契约在 system/spec/插件契约.md,随时可以用 moss --spec 打印出来 —— 那份永远和当前版本一致。

顶层字段

「内核」那列是诚实标注:真用 已经在按它做事;读 会读、但不据此做事;占位 只是预留,将来才实现。

字段必需说明内核
spec建议格式版本,现在固定 1真用
id是机器身份:目录名 / 台账键 / 数据目录名。发布后不能改(小写字母开头,只含 a-z 0-9 _ -,≤32 字符)真用
kind是task 跑完就结束 · app 界面型(会藏控制台窗口) · agent 预留真用
version是你自己的版本号,跟 moss 版本无关真用
name desc是展示名与说明,多语言对象 {"zh-CN": "…", "en": "…"}真用
aliases可选你敲的短名,可多个:moss :myfirst真用
icon可选图标文件名(相对包目录)。不写就自动找 icon.svg → .png → .webp → .jpg/.jpeg → .ico → .gif → .bmp真用
tags可选检索用真用
runner是python / go / html / exe / shell / powershell真用
entry.file是入口代码文件(相对包目录)真用
params可选参数声明,见下真用
env.cwd可选用哪个目录当工作目录;不写=你敲命令时所在的目录真用
env.elevated可选要不要管理员权限(预留)占位
output可选结果形状(mode + schema),给人 / 给 AI 看读
capabilities可选能力声明(net / clipboard / fsRead / fsWrite / elevated)占位
requires可选钉死运行时版本,例如 {"python": "3.12"}真用
ai可选能不能被 AI 调,见下真用
docs是详情页那块「使用说明」指向哪些文件(readme / usage / agent)真用
ui可选内嵌界面声明,见 界面真用
drop可选拖进来收不收、怎么收,见 收拖入真用
accepts可选更宽的「能接受什么输入」占位(拖放已由 drop 承担)占位

未知字段会被原样保留:老宿主读到新包不会把它写残,所以你可以放心加自己的键。

params 每一项

键说明
name参数名(key=value 写法用的就是它)
typestring(默认) / int / float / bool
required必填?缺了宿主会报错
default默认值
placeholder界面输入框的提示文字
desc说明
rest设成 true 表示「剩下的参数全归我,宿主原样拼成一串交给我」

ai 块

"ai": {
  "expose": true,          // 声明「我可以被 AI 调」,默认 false
  "risk": "low",           // 风险等级
  "timeout": 60,           // 单次最多跑多久(默认 60 秒,最多 300)
  "examples": [            // 给 AI 的少样本示例
    { "target": "D:\\a.txt", "note": "算这个文件的 md5" }
  ]
}
声明 ≠ 授权

expose: true 只是包自己的声明。真正能不能用还要看 user_data/ai/skills_allow.json 里有没有你的授权,而且绑指纹 —— 包改了就作废。因为 AI 自己也能写文件,把 expose 当授权等于让它自己给自己发通行证。

docs 块

"docs": {
  "readme": "README.md",   // 详情页渲染成「使用说明」卡,可展开/收起
  "usage":  "USAGE.md",    // 用法说明
  "agent":  "AGENT.md"     // 只给 AI 看,不上界面
}

宿主会把文件读成文本塞进界面数据(每个最多 24000 字符,超了带 truncated)。没有参数、desc 只有一句话的包必须写这个,否则详情页一个字的使用方法都没有。

最小可用清单

只想到「能跑起来」的话,这几个字段就够:spec、id、kind、version、name、desc、runner、entry.file。

写插件 / 参数、输出与结果文件

参数、输出与结果文件

输入只有一个来源(环境变量),输出有两条通道(stdout 给人、结果文件给机器)。不要自己解析 sys.argv。

参数怎么进来

宿主按 pkg.json 的 params 解析好,以 JSON 字符串放进 MOSS_PKG_PARAMS:

import json, os
params = json.loads(os.environ.get("MOSS_PKG_PARAMS") or "{}")

用户写 moss :hello 你好 3 和写 moss :hello text=你好 times=3,你这边看到的都是同一个 dict。

原始参数字符串另有一个 MOSS_ARGS(空格连接),排障时好打印。

rest:把一长串收进一个参数

像 img 那种「自己有小语法、参数个数不定」的插件,就把一个参数标成 rest: true:宿主把包名后面那一整串原样塞进这个字段,由插件自己解释。

"params": [
  { "name": "args", "type": "string", "rest": true,
    "desc": "留空 = 打开界面;填了 = 命令行参数" }
]
不写 rest 会静默丢参数

没标 rest 时,宿主只取前 N 个位置参数,多余的静默丢掉 —— 用户多打一个词就悄无声息地没了,这种坑比报错难查得多。rest 参数要声明在 params 最后。

两条输出通道

通道给谁怎么写
print() / stdout人(命令行选项卡里直接看到)随便印,带表情也行
MOSS_RESULT_FILE机器(界面 / AI / 脚本)按 output.schema 写 JSON
result_file = os.environ.get("MOSS_RESULT_FILE")
if result_file:
    with open(result_file, "w", encoding="utf-8") as f:
        json.dump({"ok": True, "files": 12}, f, ensure_ascii=False)

output.mode 写 "json" 时,界面和 AI 会按 schema 去读这个文件;写 "text" 就只用 stdout。

要问用户一句话怎么办

别只看 sys.stdin.isatty() —— 界面模式下 stdin 是一根管子,isatty() 永远是假,可界面其实能回答你。正确的判据是「真终端 或者 宿主说有人在听」:

def can_ask():
    if sys.stdin.isatty():
        return True
    return str(os.environ.get("MOSS_INTERACTIVE") or "").strip() not in ("", "0", "false")

def ask(prompt, choices):
    if not can_ask():
        print("这里没法交互,请明确指定:…(列出非交互的写法)")
        return None
    print(prompt)
    for i, c in enumerate(choices, 1):
        print("   %d) %s" % (i, c))
    try:
        return int(input().strip())
    except (EOFError, ValueError):
        return None
没人在听时别 input()

MOSS_INTERACTIVE 没设就表示「没人在听」(计划任务、后台跑)。这时候 input() 会永远卡住 —— 给个明确的用法提示,像 img 那样列出 -o <目录> / / 两种非交互写法。

中文与编码

宿主把 PYTHONIOENCODING 设成 utf-8(你自己设过就尊重你的)。所以 print("✔ 完成") 不会因为 cp936 崩掉;但如果你的代码里出现了奇怪的中文乱码,先检查你有没有自己又把它改回去。

写插件 / 环境变量与数据目录

环境变量与数据目录

一条铁律:只认环境变量,不要猜路径。宿主的内部布局随时可能变(数据目录名就改过一次),环境变量是对外承诺。

宿主注入的变量

变量是什么
MOSS_HOME安装根(moss.exe 所在目录)
MOSS_USER_DATA_DIRuser_data/ 的完整路径
MOSS_PLUGIN_DATA_DIR你的数据根(user_data/state/<你的 id>/)
MOSS_PLUGIN_CACHE_DIR可再生的缓存
MOSS_PLUGIN_LOG_DIR日志
MOSS_PLUGIN_TMP_DIR临时文件
MOSS_PKG_ID MOSS_PKG_VERSION你是谁
MOSS_PKG_PARAMS参数(JSON 字符串)
MOSS_ARGS原始参数字符串(空格连接)
MOSS_VIA谁触发的:cli / history / …
MOSS_RESULT_FILE把结构化结果写进这个文件
MOSS_VENV宿主识别到虚拟环境时给出
MOSS_APPEARANCE外观 JSON(深浅色 / 强调色),界面型包用
MOSS_PKG_ICON你自己图标的绝对路径;没有图标时不注入
MOSS_INTERACTIVE1 = 有人在听你说话,可以 input()
PYTHONIOENCODING宿主设成 utf-8

数据放哪儿

宿主只给路径、不预建目录 —— 你用哪个就自己 makedirs。约定四个子目录:

子目录放什么会被备份吗
data/持久数据(配置、数据库、成品)要备份
cache/可再生(缩略图、临时索引)不用,删了就重建
tmp/随便清不用
logs/日志不用
import os
from pathlib import Path

root = Path(os.environ["MOSS_PLUGIN_DATA_DIR"])
(root / "data").mkdir(parents=True, exist_ok=True)
(root / "cache").mkdir(parents=True, exist_ok=True)
绝不往自己包目录里写数据

重装 / 升级会把包目录整体换掉,写进去的东西就没了。包目录是只读的。

要密钥怎么办

绝不写进 pkg.json(分享插件就等于泄露)。契约里留了 keyRef 指向宿主托管的口令 —— 但这一块宿主还没实现,现在只能让用户自己在插件配置里填,并存在 data/ 里(自己写清楚这是明文)。

钉运行时版本

"requires": { "python": "3.12" }

不写就用默认版本(现在是 3.12)。自带运行时在 system/runtimes/python/;加别的解释器就再建 system/runtimes/<名字>/。

为什么我的 import 能用

自带运行时是 Python 嵌入式发行版(隔离模式,不把脚本目录加进 sys.path、也忽略 PYTHONPATH)。所以用自带运行时跑 .py 时,宿主动会走一下 system/bootstrap.py 引导 —— 于是你 import 同目录的模块照样能工作。系统 Python / venv 里则照常直接跑。

写插件 / 界面:一份代码两种跑法

界面:一份代码两种跑法

想要界面就把界面写成网页(HTML)。同一份页面既能内嵌进 moss 的「界面」选项卡,也能自己开一个窗口 —— 靠一个垫片自动分流,你的界面代码一个字都不用改。

声明

"ui": { "embed": "ui/index.html", "title": { "zh-CN": "我的插件" } }

路径相对包目录。不写就没有「界面」选项卡 —— 那个选项卡只在当前插件声明了它时才出现。

页面里引三个脚本(顺序别换)

<script src="vendor/vue.global.prod.js"></script>   <!-- 你的框架,本地放着 -->
<script src="moss-embed.js"></script>                <!-- 垫片:从样板包抄走 -->
<script src="app.js"></script>

然后只认这一套(window.moss):

await moss.call('do_it', {text: 'hello'});   // 调后端的方法(后端就是你的 main.py)
moss.on('time', d => { ... });               // 接后端主动推的事件
moss.on('ready' | 'invoke' | 'drop' | 'theme' | 'visible' | 'close', fn);
moss.on('captured' | 'dragend', fn);         // 拖放期间宿主告诉你「怎么回事」
moss.env.embedded;                            // true = 被嵌在 moss 里;false = 独立窗口

老写法 window.pywebview.api.xxx() 也能用 —— 垫片在内嵌环境下把它垫出来了,所以现成界面搬进来不用改代码。

后端怎么配合

独立窗口(moss :<id>)内嵌(界面里点「运行」)
你怎么知道环境里没有 MOSS_UI_EMBED宿主机给了 MOSS_UI_EMBED=1
你该干什么自己 webview.create_window(url=…, js_api=Api())别开窗口,在 stdin/stdout 上说话
调用怎么回js_api 的方法(收到一份 dict)一行一个 JSON 对象

内嵌模式的协议细节(消息长什么样、方法白名单、错误怎么回)在契约 §4.2,样板是现成的:system/pkgs/skill/ —— pkg.json + embed.py + main.py + 一整套 ui/,能跑、能抄。

什么时候可以不写网页界面

只有这三种:① 必须是个独立的大窗口(比如要铺一片缩略图);② 界面必须用非网页技术(Tk / 原生控件);③ 这个包根本没有界面(命令行 / 托盘 / 后台)。这三种也照样要在 AGENT.md 里写清为什么。

别一上来就 webview.create_window

那是例外,不是默认。默认方案是「网页界面 + ui.embed」—— 你只写一份页面,用户既能在 moss 里当标签页用,也能单独开窗。

内嵌时拖放怎么收

Chromium 不给页面真实路径,路径只能从宿主来(moss.on('drop', …))。这一块有六个坑,单独一页:收拖入。

写插件 / 收拖入

收拖入

不写 drop = 完全不收拖入。 写了才在拖动时被考虑,而且收文件 / 收文件夹要分开声明 —— 声明窄一点最好。

声明

"drop": {
  "label": "算它",
  "dir":  { "cwd": true },
  "file": { "cwd": true, "param": true, "base": true, "ext": ["png", "jpg"] }
}
键说明
label投放框上的字,默认「运行」
file / dir收文件 / 收文件夹(false = 不收这一种)。用不上就别写
cwd把它当工作目录;拖的是文件 = 文件所在的目录
param路径追加到参数串末尾
quote加双引号,默认 true(不加引号的 C:\a\b.ico 过 shlex 会变成 C:ab.ico)
base只给文件名(配合 cwd)
ext只收这几种扩展名(小写不带点)。不写 = 什么都收;[] 或 "*" 也 = 什么都收。文件夹不看它

drop 也可以是一个数组,表示一次拖入跑多条命令。

两条硬要求

  1. 能收文件夹就够的,别写 file —— tree / mark / sync 只收文件夹。声明窄一点,拖动时列表才干净,不该收的东西根本不会来烦你。
  2. 声明必须跟代码一致 —— img 的 ext 就是它代码里那份支持格式清单,多写一个就是把处理不了的文件塞进来白跑。

内嵌界面里收拖放:三个最容易翻车的点

1. 别指望页面读 dataTransfer.files

Chromium 不给页面真实路径。路径只从宿主来:moss.on('drop', d => d.items)。

2. 拖放提示只有一个,而且要自己收

内嵌时宿主会铺一层罩子接住这一拖,于是 ① 你会收到一次假的 dragleave;② 你再也收不到 drop。

规矩:moss.on('captured') 之后别信 dragleave;moss.on('dragend') 和 moss.on('drop') 里都要把提示收掉。只写 dragleave / drop 的页面,症状就是「松手之后提示一直挂在那儿」。

3. 后端别把页面要调的方法挡掉

内嵌模式有方法白名单:页面会调的每一个方法,后端都要在协议里认得,否则页面拿到的是一个错误,而不是数据。

自查顺序

  1. 先按 moss --spec 里的拖放那张表逐条对一遍。
  2. 真起一个后端进程(MOSS_UI_EMBED=1),把页面会调的每个方法都发一遍。
  3. 真渲染页面(无头浏览器),按宿主真实的顺序发 captured → dragend → drop:注意 dragend 前面不一定有 dragleave,断言别依赖它。
  4. 最后在 moss 里手动拖一次真文件 —— 自动化探针过了不代表真机过。
写插件 / 调试与验收

调试与验收

moss 的验收标准很朴素:跑得通、退出码 0。下面是查问题的顺序。

四把钥匙

命令什么时候用
moss --selfcheck整体不对劲:路径、runner、插件、运行时
moss --resolve <名字>「为什么跑的是它 / 为什么没找到」
moss --spec不确定某个字段怎么写
moss --history忘了上次怎么调通的

退出码

插件自己的退出码会原样传上来;宿主自己的错误有自己的码(比如 --snap 那套:2 用法错、3 没东西可做、4 出错)。脚本里判断「成功」就认 0。

moss :hello 你好 2
echo $LASTEXITCODE     # PowerShell:0 = 成功

日志放哪

  • 插件自己的日志 → MOSS_PLUGIN_LOG_DIR(就是数据根下的 logs/)。
  • 界面型插件初始化失败 → 宿主会把「卡在哪一步 + 异常原文」写进 user_data/state/<id>/ui-error.log,页面上也报中文原因。
  • 运行记录 → 命令行选项卡里能回看,历史在 user_data/history。

界面型包最常见的三个坑

  1. JS 里一个小错,整个界面白屏:加 window.onunhandledrejection 和 try/catch 把「卡在哪一步」写出来,别只弹一句英文。
  2. 先切模式再弹对话框:用户一取消,状态已经变了,界面就回不去了。规矩是挑到东西才改状态。
  3. 焦点 / hover 事件只绑一次:下拉框在「收起再点开」时常常不再触发 focus,因为 mousedown 被 preventDefault 了。补一次 click 检查。

验收清单

  • moss :<id> <典型参数> 退出码 0,输出是你要的。
  • 不带参数时的行为也想过了(开界面?打用法?用剪贴板?)。
  • 非法参数不会崩,给的是人话。
  • 数据只写在 MOSS_PLUGIN_DATA_DIR 里,包目录没被写脏。
  • 要界面的:ui.embed 声明了,内嵌和独立窗口两种都打开试过。
  • 要拖放的:真的拖一个文件进来试过,不是只跑了单元测试。
  • AGENT.md 写了:怎么调、副作用、失败模式。
参考 / 目录结构

目录结构

发行包只有两样东西:moss.exe 和 system\。user_data\ 是软件第一次运行时自己生成的,不用你建,也不随包发。

moss\                    ← 你解压出来的文件夹(比如 D:\soft\moss)
├─ moss.exe              宿主内核(解析命令行、找解释器、装插件、开界面)
├─ system\               ★ 跟发行版一起走(升级时整体替换)
│  ├─ ui\                 宿主自己的界面(不属于任何插件,删不掉)
│  ├─ pkgs\               出厂插件(只读层)
│  ├─ spec\               插件契约 —— 格式的唯一真相
│  ├─ skills\             给 AI 看的技能手册
│  ├─ ai\                 技能库(宿主和 :skill 插件共用)
│  ├─ runtimes\           自带 Python 运行时
│  ├─ option\             设置面板的规则与清单
│  ├─ icon\               图标
│  ├─ bootstrap.py        用自带运行时跑插件时的引导
│  └─ runners.json        执行方式(加一门语言只改这个文件)
└─ user_data\            ← ★ 第一次运行自动生成(打包时整体排除)
   ├─ pkgs\               你自己装的插件
   ├─ state\              各插件的数据、技能、界面错误日志
   ├─ backups\            版本快照(内容寻址,改坏了能退)
   ├─ history\            运行历史
   ├─ shortcuts\          短命令(moimg 这类)
   ├─ ai\                 AI 授权(skills_allow.json)
   ├─ resolve\            解析缓存
   ├─ trash\              回收站
   ├─ config.toml         设置(每项都带注释)
   └─ snapshot.ignore     快照的过滤规则

就三个东西,各归各的

目录谁的地盘升级时
core/(编进 exe)宿主换新
system/官方整体替换
user_data/你的不碰;同名插件还会压住出厂版

同名时高优先级遮蔽低优先级:user_data/pkgs/img 存在时,你跑 moss :img 得到的是你那份,出厂原件仍在 system/pkgs/img 里 —— 可对比、可还原。

放哪儿

位置行不行为什么
D:\soft\moss、D:\moss 这类自己的目录推荐有写权限,升级覆盖方便
U 盘 / 移动硬盘可以绿色软件,路径不写进注册表
C:\Program Files不行它要往自己目录写 user_data,那里默认没权限
桌面 / 下载目录不建议容易被清理工具扫掉;升级是整包覆盖,放这儿容易乱

路径里尽量不要有中文和空格 —— 绝大多数插件不在乎,但少数会去调外部程序的插件会稳一点。

为什么压缩包里没有说明书和开发文档

为了目录清爽:用户打开文件夹只需要认两个东西 —— moss.exe 和 system\。所以根目录不放 README.md、使用说明.txt、插件开发向导.md 这类人看的文档;完整文档在这个站点上(会更新),软件里每个插件的详情页也有用法。

AI 不依赖这些文档

AI 干活时读的是:system/spec/插件契约.md(也就是 moss --spec 打印的那份)、system/skills/ 里的技能手册、以及每个插件自己的 AGENT.md。根目录那几份人看的文档删掉不影响 AI —— 前提是 system\ 完整。

插件的数据在哪

插件的运行数据按 id 算,不跟着层走:不管这个插件住在 system/pkgs 还是 user_data/pkgs,它的数据都在 user_data/state/<id>/。所以在两层之间搬插件,数据不会丢。

moss --layer img            # 看 img 现在在哪一层
moss --layer img user       # 搬到 user_data/pkgs(升级不再碰它)
moss --layer img system     # 搬回出厂层(升级会替换成官方新版)

搬家与备份

整个文件夹拷走就行 —— 路径不写进注册表。只想备一份「我的东西」,拷 user_data/ 即可。

参考 / 命令大全

命令大全

不用记,moss 不带参数就打印用法和插件列表。这里是全量整理,方便扫。

运行

命令说明
moss <名字>在当前目录(及向上几层)找匹配的脚本并运行
moss b/m · moss s/t/main逐级往下找
moss /<名字>同上,但不切换目录
moss ~<名字>后台脱离运行,不阻塞当前控制台
moss :<别名> [参数]运行一个已安装的插件
moss --resolve <名字>只看解析结果,不执行

界面

命令说明
moss ui打开界面(双击 exe 也是这个)
moss --ui同上,写全的形式

目录与历史

命令说明
moss cd <目标>智能找目录并切过去
moss cd --install / --uninstall装 / 卸 PowerShell 包装函数(屏幕上不留回显)
moss --history方向键选,回车重跑(去重,最多 20 条)
moss --history <条数>只打印不交互

插件管理

命令说明
moss --new <id> [name=… desc=… kind=…]生成一个能跑的插件骨架
moss --remove <别名>卸载插件:本体 + 数据(永久删除,需确认;-y 跳过)
moss --rename <旧> <新id>改名:目录 / 数据目录 / 清单里的 id 一起改
moss --layer <包> [user|system]在两层之间搬插件目录
moss --alias [sync|status]短命令对账 / 看现状
moss --spec打印插件契约

AI

命令说明
moss --ai-config看当前那组参数(key 默认打码)
moss --ai-config-reveal同上,但 key 给全文
moss --ai-profile-set <组> k=v…加 / 改一组(base_url / api_key / model)
moss --ai-active <组>选当前用哪一组
moss --ai-profile-del <组>删一组
moss --ai-rename <旧> <新>改名(整块搬,key 不用再读一遍)
moss --ai-presets常见服务商的预制参数
moss --ai-test [组]测试连接(流式发一个最小请求,报状态码和第一个增量)
moss --ai-models [组]获取可用模型清单
moss --ai-balance [组]查询余额(支持已知接口的服务商)
moss --ai-import-legacy把旧配置文件导成一组

版本快照

完整用法见 版本快照与回退。会动磁盘的动作都要 --yes。

子命令说明
list / save / show列出 / 存一次 / 看清单
diff / revert / restore对比 / 一键对比+回退 / 恢复
grep / cat / ls在快照里搜内容 / 看单个文件 / 列文件
export / rm / gc导出 / 删一次 / 回收无引用内容块
tags / group / presets看标签 / 这个对象会落到哪个分组 / 看过滤命中
ignore / check看过滤规则 / 按指纹校验

诊断

命令说明
moss --selfcheck自检:安装根 / runner 表 / 插件 / 自带运行时 / cd 注入
moss用法 + 插件列表
参数写法

位置参数(按 params 顺序)或 key=value 都行。带空格的参数建议用 key=value 或插件自己的写法 —— 有些 rest 通道会把引号吃掉。

参考 / AI 服务配置

AI 服务配置

AI 功能要你自己提供一组模型接口:地址、密钥、模型名。可以存多组来回切 —— 便宜的用来干杂活,强的用来写插件。

在界面里配

设置 → AI,三个视图:

  1. 列表:已存的所有组,标出当前用的是哪一组。
  2. 选服务商:九宫格里挑一个预制模板(地址自动填好),或者手动填基地址。
  3. 编辑:名字 / 接口地址 / 密钥 / 模型。三项都填了才保存得了。

改完点「测试连接」,它会流式发一个最小请求,回状态码和第一个增量 —— 通了就是真通了,不用等真干活才发现 key 写错。

预制服务商

服务商说明
DeepSeek官方 API
GeminiGoogle(OpenAI 兼容口)
OpenAIChatGPT 系列
Kimi月之暗面
通义千问阿里(兼容模式)
智谱GLM
硅基流动聚合平台
本地 Ollama本机 127.0.0.1:11434,不用 key

任何 OpenAI 兼容的接口都能用 —— 选中「自定义」把基地址填成 https://…/v1 就行。

命令行配

moss --ai-presets                                   # 看有哪些预制
moss --ai-profile-set 主 force=1 base_url=https://api.deepseek.com/v1 api_key=sk-… model=deepseek-chat
moss --ai-active 主                                  # 切到这一组
moss --ai-test 主                                    # 测试连接
moss --ai-models 主                                  # 拉可用模型清单
moss --ai-balance 主                                 # 查余额
moss --ai-config                                     # 看当前配置(key 打码)

model 可以写多个,逗号隔开(界面上是一个下拉可以切)。

关于密钥

明文存在 config.toml

现在就是明文写在 user_data/config.toml 里,没有加密。所以:别把这个文件夹发给别人;备份文件(config.toml.bak-…)同样含明文密钥。

请求直连你自己填的那个接口,不经过任何中间服务器。哪次 AI 干活要联网,只有这一条路。

花多少钱

AI 工作台会逐年轮记 token(usage),你可以在界面上看到它这一轮用了多少。想省钱:

  • 杂活用便宜模型,写插件再切强的;
  • 一句话把需求说清楚,别让它来回猜;
  • 它只在「写 / 改插件」时才调模型,平时跑插件不联网、不花钱。
参考 / 常见问题

常见问题

先用搜索框找找,没有的话进群问(页面底部有两个群二维码)。

装和用

要装 Python 吗?

不用。自带独立的 Python 3.12(system/runtimes/python),插件都用它跑,不依赖你机器上的 Python,也不会弄乱原有环境。

要装 Node 吗?

不用 —— 只有 dsh 那个远程桥插件需要 node + @deepseek-ai/dsh。别的插件和宿主都不需要。

Windows 提示「未知发布者」怎么办?

没有代码签名。点「更多信息」→「仍要运行」即可。它不联网(AI 除外)、不写注册表、不写系统目录。

升级会不会弄丢我的东西?

不会。升级只覆盖 moss.exe 和 system\,user_data\ 一个字都不动。

能装在 Program Files 吗?

不建议。它要往自己目录写 user_data,那里没权限。放 D:\Tools\moss 这类自己的目录。

手机 / 平板能用吗?

不能。这是 Windows 桌面软件,只支持 Windows 10 / 11(64 位)。

AI

AI 会不会乱改我的东西?

四道闸:① 每次动手改文件之前先存「动手前」快照,改坏了能退回;② 它能读写哪些目录是一张清单,没勾的地方读都读不了;③ core\、moss.exe、venv\、.git\、备份库是硬锁,勾了「任意路径」也写不了;④ 它给自己新造的工具(技能)要你点一次「允许」才生效。

为什么第一次用技能要我先点「允许」?

因为「声明」不等于「授权」。AI 自己也能写文件,如果把插件里的 expose 当授权,就等于让它自己给自己发通行证。这一次点击是设计,不是待修的 bug。

AI 说做完了,但我不满意怎么办?

继续说就行,它会接着改;想推倒重来就在文件管理里回到那条「动手前」快照。它的验收标准是「真机跑通、退出码 0」,所以先去看命令行选项卡里那次运行。

必须联网吗?

只有让 AI 写插件 / 造工具时要联网(调你自己配的模型接口)。跑现有插件、管文件、快照回退这些全程离线可用。

为什么压缩包里没有使用说明 / README?

为了目录清爽 —— 根目录只该有 moss.exe 和 system\,用户一眼知道点哪个。文档在这个站点上(会更新),每个插件的详情页也有它自己的用法。AI 也不需要这几份文件,它读的是 system/spec 和 system/skills(见 目录结构)。

一定要用命令行吗?

不。装好双击就是界面,点插件、拖文件、点运行。命令行是可选的那一半 —— 给愿意用键盘的人。

插件

插件会不会互相影响?

不会。每个插件一个独立目录,数据按 id 分开放,拔掉一个不影响别的。它自己长出来的插件和原生插件用同一份契约,没有区别。

能写 Go / PowerShell 插件吗?

能。runner 支持 python / go / html / exe / shell / powershell。加一门新语言只改 system/runners.json,不用动宿主代码。

怎么把一个插件分享给别人?

把它在 user_data/pkgs/<id> 的整个目录打包发过去,对方解压到自己的 user_data/pkgs/ 即可。注意别把密钥写进 pkg.json。

卸载插件会删我的数据吗?

moss --remove 会连数据一起删(永久,需要确认)。只想暂时不用,就把目录挪走或在界面里关掉。

排障

终端里敲 moss 提示找不到命令?

没加进 PATH。设置 → 命令接入 → 勾上「把 moss 加进系统 PATH」,然后新开一个终端(旧窗口不会自动刷新环境变量)。

界面打不开 / 白屏?

先 moss --selfcheck。界面型插件白屏的话,看 user_data/state/<id>/ui-error.log,里面写着卡在哪一步和异常原文。

双击 exe 弹了一下黑框就没了?

那是控制台窗口在启动阶段被藏起来,正常。要是真的没反应,用终端跑 moss.exe --selfcheck 看报错。

改坏了怎么退回?

文件管理 → 版本快照 → 选「动手前」那条 → 回退。命令行里是 moss --snap revert :<插件>。详见 版本快照与回退。

参考 / 边界与版本

边界与版本

这些是「现在的样子」,不是承诺。写在这里是为了让你少猜。

已经能用

  • Windows 单机,不需要装任何服务、不写注册表(path 插件改 PATH 除外,那是它的本职)。
  • 插件:多语言、可插拔、能内嵌界面、能收拖入、能被 AI 调。
  • AI:写插件、改插件、造技能、跑验证;带快照、权限清单、硬锁。
  • 版本快照:存 / 比 / 回退 / 导出 / 在快照里搜内容。
  • 绿色便携:整个文件夹拷走就是搬家。

还没有 / 还不完整

项现状
插件契约 spec 1没到 1.0,契约还会动。以 moss --spec 为准
托管密钥(keyRef)宿主还没实现 —— 别指望它替你管凭据
capabilities 声明会读,但不据此拦截(真正生效的是 AI 的目录权限清单)
verify / accepts / env.elevated只是占位字段,将来才实现
插件商店 / 在线分发没有。现在靠目录拷贝和群
非 Windows 平台没有。Linux / macOS 不在计划内
手机端没有,也不会有 —— 它是桌面软件

会变的地方

你写的插件不用怕这些变化:环境变量是对外承诺,宿主的内部布局(state/ 下怎么分目录、快照怎么存)随时可能改,所以插件里请只认环境变量。

想要新功能

最好的方式不是等发版 —— 打开 moss,直接跟它说。它读契约、写插件、跑一遍验证,然后交给你验收。真要落到出厂里,再让它进 system/pkgs。

反馈

遇到问题、想要个新插件,进群说一声更快:QQ 群 / 微信群二维码。