Mafdet CLI
@mafdet/cli 是官方命令行:调用模型、查询账户,以及运行一个受权限约束的本地
Agent,在你自己的机器上读取和修改代码。Agent 的工具在本地执行——服务端只返回
结构化的 tool call,不放宽任何服务端 Agent 权限。
需要 Node.js 20 或更高。
安装
npm install -g @mafdet/cli
也可以免安装直接运行:
npx @mafdet/cli doctor
交互式会话
在终端里不带参数直接敲 mafdet 就进入会话:选认证方式、选模型,然后和 Agent 对话。
mafdet # 只读
mafdet --allow-write # 改动先展示 diff 再确认
mafdet --allow-command "pnpm test"
它和 mafdet agent 是同一个 Agent,只是画法不同——同样的工具、同样的审批、
同样的计费。参数含义与那边完全一致,两个都不给的会话根本没有加载写工具和命令工具。
管道里、--json 下、CI 中、TERM=dumb、或带 --no-tui 时,mafdet 仍然是把用法写
stderr 并 exit 2,与之前完全一样。任何读取 CLI 输出的程序都不会突然收到一个界面。
快速开始
export MAFDET_API_KEY="sk-mafdet-live-..."
export MAFDET_MODEL="deepseek-v4-flash"
mafdet doctor # Key、端点、模型、余额、工作区、git 一次查完
mafdet models list # 这把 Key 实际能调用的模型
mafdet chat "解释一下 TypeScript 装饰器"
mafdet account balance
出问题时先跑 mafdet doctor。它会检查 Node、两个端点、Key、工作区、git、
两个 API 面、选定模型、该模型的工具调用能力和余额,并且只有真正阻断的问题才判
失败——缺一个可选 scope 只是警告,不会误报成错误。
PowerShell
$env:MAFDET_API_KEY = "sk-mafdet-live-..."
$env:MAFDET_MODEL = "deepseek-v4-flash"
mafdet doctor
所有用户可见输出都是纯 ASCII,因此在非 UTF-8 代码页的控制台(Windows PowerShell
5.1 的默认状态,中文系统为 cp936)也不会变成乱码。PowerShell 默认按 UTF-16 走管道,
所以请把 prompt 作为参数传入,或使用 --input <文件>,而不要用管道。
命令
| 命令 | 作用 |
|---|---|
mafdet doctor | 一次检查 Node、端点、Key、工作区、git、模型与工具调用、余额 |
mafdet models list [--surface chat|embeddings|speech] [--agent] | 这把 Key 能调用的模型,并附上目录元数据 |
mafdet models show <id> | 单个模型详情,含 Agent 是否可以驱动它 |
mafdet chat [提示词] [--model] [--system <文件>] [--input <文件>] | 发一次对话,默认流式 |
mafdet agent "<目标>" | 本地 Agent,默认只读 |
mafdet agent | 交互会话(需要终端) |
mafdet embed [文本|<文件>] --model <id> [--output <文件>] | 文本转向量 |
mafdet speech [文本|<文件>] --model <id> --output <文件> --voice | 文本转音频 |
mafdet account balance|usage|subscription | 钱包、用量、套餐(需 account:read scope) |
mafdet sessions list|show|usage|delete | 保存在这台电脑上的会话(不会调用模型) |
mafdet sessions usage <id> --refresh | 在本地估算旁显示账单账本的已结算金额 |
mafdet config list | 当前生效的配置及其来源 |
--json 输出一份完整 JSON 文档;--plain 输出无表头的 TSV,方便 cut、awk 处理。
Agent 的权限模型
默认只读:可以列目录、搜索、读文件、看 git status / git diff,不能改
任何东西。
--allow-write 才会加上 edit_file 与 create_file,并且:
- 每次改动都先展示 diff 再询问,回车即拒绝;
- 非交互环境一律不给写权限,即使显式传了该参数——此时写工具根本不会提供给模型;
- 没有任何"全部同意"的开关。
批准一条命令,意味着允许那个程序在你的机器上、以你的身份运行。
工作区限定的是 Agent 自己的工具能碰哪些文件,它不是沙箱,也约束不了那个程序。
我们会拒绝一小份明显破坏性的名字(sudo、su、doas、chown、shutdown、reboot,
以及按路径调用),但请把它当作防手滑的护栏,而不是隔离。
--allow-command "<前缀>" 才会加上 run_command,且只对这些命令前缀免提示:
pnpm test 放行 pnpm test --filter web,但不放行 pnpm publish。
没有 shell——命令被切成 argv 直接执行,所以管道、重定向、;、&&、反引号、
$( ) 一律被拒绝并说明原因,而不是尝试"消毒"。
看起来像密钥的文件——.env*、私钥、id_rsa*、kubeconfig、credentials*、
.npmrc,以及 .ssh、.aws、.gnupg、.docker、.kube 整个子树——一律拒绝,
没有任何总开关可以绕过。工作区边界按真实路径判定,符号链接无法指向工作区外。
会话内命令:/model、/permissions、/diff、/cost、/compact、/exit。
哪些模型可以驱动 Agent
只有工具调用经过端到端实测验证的模型。看 AGENT 列:
mafdet models list --agent
未验证的模型会被直接拒绝而不是先试再说,免得你为一次跑到一半失败的任务付钱。
mafdet models show <id> 会说明某个模型属于哪种情况。
凭据
Key 只从 MAFDET_API_KEY 读取。刻意不提供 --api-key 参数——那会把 Key 写进
shell 历史和进程列表。Key 不会被写入任何配置文件,也不会完整出现在任何输出里,
只以 sk-mafdet-live-<redacted> 这样的指纹形式展示。
项目可以放一个 .mafdet.json,但只允许 model 一项。
里面出现凭据或端点会直接报错:克隆一个仓库绝不该改变你的 Key 发往哪里。
mafdet account ... 需要 Key 带 account:read scope(在
API Keys 里创建)。没有它其他命令照常可用。
退出码
脚本可以据此分支。
| 码 | 含义 |
|---|---|
| 0 | 成功 |
| 1 | 一般失败(含 doctor 有检查项未通过) |
| 2 | 命令行或配置错误 |
| 3 | 认证或权限失败 |
| 4 | 模型或 API 不可用 |
| 5 | 本地权限被拒绝 |
| 6 | 用户取消 |
| 7 | 达到费用、时间或轮次上限 |
结果与机器可读的 JSON 走 stdout;进度、警告、摘要、审批提示走 stderr。
所以 mafdet chat ... > answer.txt 只会拿到答案本身,而
mafdet models list --json | jq 永远能解析。
保存下来的会话
交互式会话会保存在这台电脑上,也只在这台电脑上。它们不会上传,Mafdet 没有副本。
这是关于存档的说法,不是关于模型的。你发送的消息仍然会送到 API 去作答, 仍然出现在你的用量记录里;留在本地的是那份保存下来的副本。
| 平台 | 路径 |
|---|---|
| Linux / WSL | ${XDG_STATE_HOME:-~/.local/state}/mafdet/sessions |
| macOS | ~/Library/Application Support/mafdet/sessions |
| Windows | %LOCALAPPDATA%\mafdet\sessions |
这些文件是明文。一份存档包含你的消息、模型的回复,以及 agent 工作时读过的任何源码,
所以请把会话目录当作它所对应的那个项目本身来对待。API Key 是唯一的例外:
所有内容在写盘前都会过一遍脱敏,你粘进提示词里的 Key 会以 <redacted> 的形式存下来。
Agent 读不到这些目录——即使你在家目录里运行 mafdet、存档实际落在工作区内也一样。
mafdet --no-history # 这一次运行完全不记录
mafdet chat "..." --save # 一次性对话只有明确要求时才保存
mafdet sessions list # 已保存的会话;没有时会告诉你路径
mafdet sessions delete <id> --yes
一次 mafdet chat 不是有人会去恢复的对话,所以不带 --save 就不保存。
--no-history 仍然压过 --save;被 Ctrl+C 取消的对话完全不保存。
删除会移除本地消息和这个会话的用量映射。它不会移除 API 用量、账单记录或扣费—— 那些属于 API Key,不属于存档。而且它只是一次普通的文件删除,不是安全擦除: 备份、快照和文件系统本身仍可能保有副本。
对账:这次会话到底花了多少
mafdet sessions usage <id> 从本地记录累加一次会话的用量。那些金额是估算,
算法与网关一致,但是在你的机器上算的。
--refresh 会按会话时间窗口和游标查询当前 API Key 的用量事件;request ID 只留在本地,
用于匹配账本返回的记录。它不发送消息、标题、工作区路径或 session ID。由另一把 API Key
支付的请求会被跳过并如实告知,好让你知道该换那把 Key 再跑一次。
账本还没结算的请求保持 pending,从未拿到 ID 的请求保持 unknown。
两者都不会显示为 0——0 读起来像「免费」。
费用
chat 会在 stderr 打印 token 数与预估费用,算法与网关计费一致,
但以钱包为准——参见用量与计费。
Ctrl+C 会关闭连接。实测中被取消的流式请求没有产生费用,但这是一次观察结果、
不是保证:如果上游已经生成完毕,仍可能产生扣费。因此取消后的摘要标注为
partial:。
已知限制
以下限制是主动写出来的,不是等你去发现的:
- macOS 与 Windows 尚未验收。 已在真实终端验过的是 Linux、WSL、tmux、SSH 以及 SSH + tmux,Node 20 和 22 都过。
- Windows 上的命令超时终止:已实现,但未验证。 POSIX 走进程组信号,Windows 走
taskkill /T;该调用的形状有测试,但从未在真 Windows 上执行过, 所以它是否真的能杀到每一个孙子进程属于未知。只影响--allow-command。 /compact是截断历史,不是生成摘要。长时间运行在接近上下文上限时也会自动压缩, 丢掉最早的若干次工具往返——只影响发出去的内容,本地存档不受影响。--json形状与退出码的兼容承诺自 1.0.0 起正式生效;当前是 0.x, 按 semver 次版本号仍允许破坏性变更。
下一步
- MCP Server —— 给 MCP 客户端的只读账户工具
- 权限与模型范围
- 错误码参考