关于 vtai-agent
vtai-agent 是面向 opencode、Claude Code 和 pi 的系统自动化 MCP 服务,也可通过 vtai CLI 驱动。它以默认 dry-run、路径约束、命令沙箱和审计日志控制机器操作。
主要功能
- 01只读系统信息与磁盘审计
- 02受限 Shell 命令执行
- 03文件整理、备份与媒体转码
- 04委派编码任务并验证回滚
- 05自动化目标循环与应用检查
- 06干运行、预算限制及 SQLite 审计
适用场景
- 01查看机器资源和可回收磁盘空间
- 02在指定目录整理文件或同步备份
- 03在护栏下运行 Shell 或转码媒体
- 04委派编码任务并审查结果
MCP 相关
作为 MCP 服务向 opencode、Claude Code 和 pi 暴露受护栏保护的系统自动化工具。支持 stdio,也可通过 Streamable HTTP 提供相同工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
VT-AIAgent
面向你自己的机器的系统自动化 Agent,可作为 MCP 服务供 opencode / Claude Code / pi 使用,也可通过 vtai CLI 直接驱动。
工具
| 工具 | 功能 |
|---|---|
system_info | 只读机器快照(CPU、RAM、磁盘、负载、GPU),以及当前生效的配置和防护措施 |
run_shell | 执行允许列表中的 Shell 命令,并在沙箱中运行(见下文) |
organize_files | 在可写根目录内进行内容感知的目录清理 |
backup_sync | 使用 rsync 进行增量备份并验证;--delete 需主动启用 |
transcode_media | 使用 VAAPI 加速批量转码视频;绝不修改原文件 |
disk_audit | 只读扫描可回收的磁盘空间 |
delegate_coding | 将任务交给 opencode/claude/pi;创建 git 快照、验证并回滚;默认要求人工批准 |
auto_mode | 自主循环:将目标交给编码 CLI,审查回复并持续迭代,直到符合要求 |
inspect_application | 在防护措施下对应用进行 REA 驱动的静态分析:检查 deny-glob → 创建隔离副本 → 在最小环境中运行 → 将证据摘要写入审计记录 → 可选的评审环节(在配置中启用前默认关闭) |
安全模型
- 默认试运行(
guardrails.dry_run_default)——预览操作绝不触碰磁盘。 - 路径限制:只在
paths.writable_roots内写入;解析后的路径可防止../符号链接逃逸;guardrails.deny_globs用于保护机密信息。 - 默认拒绝的 Shell 沙箱:二进制文件必须是允许列表中的裸名称,并具有明确的读写策略;解析结果必须位于
trusted_bin_dirs内,不得携带启用执行的标志,且每个路径参数都必须通过相同的检查。 - 紧急停止开关:在
data_dir中放置KILL文件,即可中止正在执行的工具。 - 回声循环断路器:在一个时间窗口内发生 N 次相同的拒绝后,会升级拒绝响应,将循环模型无法忽略的
CIRCUIT BREAKER指令加入其中。 - 预算上限:当累计 Token 费用超过
budget_usd_per_run时,中止编排运行;每次运行的费用都会记录。 - 审计:所有允许和拒绝的操作都会记录到
data_dir中的 SQLite 数据库;每次调用(编排、MCP 或 CLI)都会关联到一个运行记录。
快速开始
前置条件
| 要求 | 备注 | |
|---|---|---|
| 操作系统 | Linux、macOS 或 Windows | 三个平台均在 CI 中运行(自 0.6.0 起为阻断性检查) |
| Python | 3.14+ | 由 .python-version 固定版本;uv 会为你获取 |
| uv | >= 0.13.1 | curl -LsSf https://astral.sh/uv/install.sh | sh |
| 规划器大模型 | 以下任选其一:Ollama、任意 OpenAI 兼容端点或云端密钥 | 参见选择模型 |
| rsync | 可选 | backup_sync 所需;缺少时该工具会默认拒绝执行 |
| ffmpeg | 可选 | transcode_media 和语音辅助工具所需 |
| Lemonade Server | 可选 | 为 agent-listen / agent-speak 提供语音输入/输出 |
1. 安装
git clone https://github.com/velsrocky/vtai-agent.git
cd vtai-agent
uv sync --dev
uv sync 需要 uv >= 0.13.1(锁文件使用 revision = 5;最低版本要求声明在 [tool.uv] required-version 中,因此较旧版本的 uv 会明确提示这一点,而不会在解析锁文件时失败)。
2. 配置
Agent 会读取一个 TOML 文件。具体读取哪个,按以下顺序确定:
$VT_CONFIG— 显式覆盖- 软件包旁边的
config/settings.toml(即你刚刚克隆的仓库) ~/.vtaiagent/settings.toml— 用户级文件
如果机器上没有任何配置文件,首次使用时会明确报错:内置默认值不会保护任何内容(shell_allowlist 为空),因此不会运行任何操作;vtai info 也会直截了当地说明(“此处没有配置文件”)。
vtai init 会写入一份初始配置;vtai init --doctor 会在写入后立即运行完整预检。
新克隆的仓库包含维护者的配置(他们的提供方、他们的可写根目录),因此请让 Agent 使用你自己的文件,而不要编辑已纳入版本控制的文件:
export VT_CONFIG="$HOME/.vtaiagent/settings.toml"
uv run vtai init # writes a starter config there + creates the dirs
将该 export 放入 shell 配置文件,这样之后的每条命令(以及 MCP 服务)都会读取它。
vtai init 会创建 ~/.vtaiagent(审计数据库 + 数据目录)、~/Downloads 和 ~/Documents/vt-data,并写入一份具有安全默认值的初始配置:dry_run_default = true、针对 ~/.ssh、~/.gnupg、~/.aws 和 **/.env 的 deny_globs,以及仅限于 ~/Downloads、~/Documents/vt-data 和 ~/.vtaiagent/tmp 的可写根目录。使用 vtai init --doctor 可在写入后立即运行预检。可以安全地重复运行。
查看最终使用的是哪份配置——vtai info 会显示文件名及其来源:
uv run vtai info
# config file : /Users/you/.vtaiagent/settings.toml (user-level)
替代方案:保留检出版本中的配置,并通过环境变量覆盖
工作目录中的 .env 文件(已被 git 忽略;从 .env.example 复制)会覆盖任何设置。变量使用 VT_ 前缀,嵌套层级用 __ 表示:
VT_LOCAL__BASE_URL=http://localhost:13305/api/v1
VT_LOCAL__MODEL=<a pulled chat model>
VT_ACTIVE_PROVIDER=local
如果机器上没有 Ollama,这种方式可以让 Agent 指向 Lemonade 服务。.env 文件会从当前工作目录读取,因此请在检出目录中运行 CLI,或在 shell 中导出这些变量。
选择模型
规划器/评判器模型由 active_provider 指定:
local— 任意兼容 OpenAI 的端点:Ollama(http://localhost:11434/v1)、llama.cpp、vLLM、LM Studio、Lemonade。无需 API 密钥。anthropic/openai— 云端模型;请将ANTHROPIC_API_KEY或OPENAI_API_KEY放入.env。
在提供方配置块中设置 cost_per_1k_input / cost_per_1k_output,才能让 budget_usd_per_run 生效;如果未设置,Agent 会使用模型的原生价格表。
3. 验证
先运行预检——它会检查 uv、配置、可写根目录、受保护的内容、可选工具、模型端点、MCP 注册,以及是否有等待审核的委托:
uv run vtai doctor
VT-AIAgent doctor — v0.6.2
✓ agent version 0.6.2
✓ uv 0.13.1
✓ config file /Users/you/.vtaiagent/settings.toml (user-level)
✓ config valid no issues
✓ writable roots 3 present
✓ protected paths 4 deny globs
✓ shell allowlist 22 binaries
✓ model endpoint http://localhost:11434/v1
! optional tools not installed: ffmpeg (for transcode_media, voice helpers)
✓ mcp registration opencode (global)
✓ pending approvals none
如果有需要修复的问题,命令会以非零状态码退出。然后可尝试以下功能:
uv run vtai info # config, provider, guardrails
uv run vtai tools # the registered tools
uv run vtai run system_info # a read-only call, no LLM involved
uv run vtai goal --dry-run "list my Downloads" # full loop with the model
4. 在 Agent CLI 中使用
scripts/register-mcp.sh # opencode (global), claude (user), pi (CLI)
opencode 的注册信息会写入 ~/.config/opencode/opencode.jsonc,并与现有提供方合并。脚本会特意注册 uv 的绝对路径:如果客户端从 PATH 精简的守护进程中启动服务,直接使用 uv 会因 NotFound: ChildProcess.spawn (uv ...) 而失败。
使用
uv sync # install
uv run vtai init # create/validate config, dirs, writable roots
uv run vtai info # show config
uv run vtai tools # list tools
uv run vtai run system_info # invoke a tool
uv run vtai run run_shell --params '{"command":"ls ~/Downloads","dry_run":true}'
scripts/register-mcp.sh # register with opencode / claude
若要在检出目录之外使用 vtai CLI,请将其安装为可编辑工具,使其跟踪你的工作副本:
uv tool install --editable /path/to/vtai-agent # -> ~/.local/bin/vtai
要将其作为依赖安装到另一个项目中,请使用 uv add git+https://github.com/velsrocky/[email protected];也可以用 docker build -t vtai-agent . 拉取镜像。
注册表与分发
PyPI:uv tool install vtai-agent(或 pipx install vtai-agent)——通过 Trusted Publishing 在 v* 标签上发布,并附带构建证明(参见 .github/workflows/publish.yml)。上方的 `` 注释是官方 MCP 注册表要求的 PyPI 软件包证明;server.json 包含注册表清单(io.github.velsrocky/vtai-agent,stdio),发布工作流中还设有元数据一致性检查。请仅从这些来源安装;相似的仓库名称并不能证明其来源可信。
PyPI 发布后,在官方 MCP 注册表中注册:
mcp-publisher auth --oauth2-github
mcp-publisher publish server.json
认证(vtai-cert)
安全声明是探测,不是描述:vtai certify 会运行可执行的防护合规测试套件(拒绝 glob 的限制、dotdot/符号链接逃逸、故障时拒绝执行的 shell、抵御注入的 argv、先试运行、终止开关、审计精确性、回显循环断路器,以及委托程序的先验证后信任循环,包含脚本化模拟回滚和审批门探测),并生成带摘要戳的证书;
退出码为 0 表示通过 CI 发布门禁。请参阅 docs/certification.md。
HTTP 传输
vtai serve --transport http --port 8765 --token $VT_HTTP_TOKEN 会通过 MCP StreamableHTTP 在 /mcp 暴露同一组受保护的工具。绑定到 localhost 以外的地址时必须提供 bearer 令牌;否则服务器会拒绝对外绑定。
开发
uv sync --dev
uv run pytest tests/ -v
uv run ruff check src/ tests/
uv run python scripts/generate_tool_catalog.py --check # tool-catalog doc drift
配置文件按 配置 中所述的顺序解析:$VT_CONFIG
→ 检出目录中的 config/settings.toml → ~/.vtaiagent/settings.toml。环境变量覆盖项使用 VT_ 前缀和 __ 嵌套(例如
VT_GUARDRAILS__DRY_RUN_DEFAULT=false)。配置会在启动时验证
(validate_settings)——deny_globs 模式无效或缺少可写根目录时,会立即失败,而不会等到运行中才失败。
Windows: shell 沙箱需要能够解析允许列表中的二进制文件,而全新的 Windows 运行器不会将 Git for Windows 的 coreutils 加入 PATH。请安装 Git for Windows,并将其 usr\bin 放在 PATH 前面(CI 也是如此):
Add-Content $env:GITHUB_PATH "C:\Program Files\Git\usr\bin" # CI
# locally: add "C:\Program Files\Git\usr\bin" to your PATH
其余所有内容(安装、配置、MCP 注册)在三个平台上都相同。
编排器
vtai goal 会运行一个有界的 ReAct 风格 Agent 循环。每一步中,模型要么发出一个 fenced-JSON 工具调用(解析、保护、执行,并将结果反馈回去),要么给出最终的自然语言答复。每一步都会强制执行边界:max_steps、终止开关和 budget_usd_per_run。若单独的 dry_run: true 文本块无法解析或缺少 tool 键,系统会附上纠正说明并重试,而不会以“成功”结束本次运行;运行模式具有权威性,模型无法覆盖;每次工具调用都会持久化为一条 Step 记录和审计条目。如果无法确定付费提供商的支出(未配置 cost_per_1k_* 且没有原生费用数据),运行会以失败关闭,而不是报告为免费。系统提示词会说明机器的实际操作系统。
我们有意采用文本协议,而非原生函数调用:这台设备上的本地 Ollama 模型即使收到原生工具模式,也会将工具调用作为原始 JSON 文本输出(已于 2026-10-03 使用 qwen2.5-coder:7b 验证),因此文本协议在本地和云端提供商之间的表现一致。
自动模式
auto_mode 会运行你描述的循环:将目标发送给编码 CLI(默认使用 opencode),使用配置的模型对照目标检查回复;如果回复不够充分,就引用评审意见发送后续提示词,最多执行 max_iterations 次。评审器只接受毫无保留的赞同:带保留的回复(OK, but ...)和提出异议的文字(OK. However, ...)始终不通过。对于首行明确写出 OK、但后续又作出解释的冗长评审器,会认可其赞同;如果文字表明存在缺陷(缺失/未经验证/错误……),则维持严格判定。这种倾向是刻意设计的——赞扬中出现保留措辞只会多触发一次检查,绝不会导致错误通过。设置 [auto_mode] judge_replicas = N(默认为 1)后,判定取 N 次独立评审调用的多数结果,可有效抵御单次调用的判定波动;评审器的开销由 guardrails.budget_usd_per_run 在各副本间共同限额,而不是限额乘以 N。所有开销都以相同方式计量,并计入运行的 spend 详情:
始终计入评审器自身的大模型调用;委托 CLI 能报告时也会计入——claude -p --output-format json 会提供 total_cost_usd,而具备费用报告能力的 CLI 若报告无法读取,则会安全地判定失败。opencode/pi 不报告无头模式开销(这是有文档记录的供应商行为,并非通过猜测解析事件流),因此它们的运行会标记为 "cli_usd": "unmeasured",且仅受 max_iterations/timeout 限制。在 opencode 或 Claude Code 中,使用 @vt-ai_automode_on 开头编写提示词:MCP 服务的指令会将其路由到该工具。
uv run vtai run auto_mode --params '{"goal":"add a unit test for parser.py","working_dir":".","max_iterations":3}'
委托编码
delegate_coding 会为目标仓库创建快照,在无头模式下运行所选 CLI,捕获差异;如果 verify_command 失败(或超时/退出码非零),则回滚。以下是三个值得了解的保护机制:
- 人工审批关卡:
require_approval默认为true。交互式运行会显示git diff --stat,并在保留更改前征求确认。非交互式运行(MCP、脚本化、编排运行)会将更改保留在工作树中,并标记为待审批——运行会报告失败,以便自动化循环停止——之后可通过vtai approve <id>(保留)或vtai approve <id> --rollback解决。在某个仓库存在待审批事项期间,delegate_coding会拒绝在该仓库开展新工作,即使设置了require_approval: false也不例外。只有人类已审核过的任务才传入require_approval: false。 pi需要凭据:如果没有已通过身份验证的提供商,pi -p会以退出码 0 结束,但只输出一个工具调用 JSON 块,不会应用任何更改。该工具现在会安全地判定失败并给出清晰说明。委托给 pi 之前,请运行pi auth check,或者优先选择opencode/claude。
Claude 委托会使用 --output-format json 运行,因此回复文本取自 result,调用的 total_cost_usd 会记录到工具详情中的 cli_cost_usd(并接受审计)。委托给 opencode/pi 时会报告 "cli_cost_usd": "unmeasured"。
uv run vtai approve # list pending delegate approvals
uv run vtai approve 7 # keep the pending diff
uv run vtai approve 7 --rollback
vtai info 会显示有多少项审批正在等待处理,避免为审核而保留的委托任务被遗忘。
检查应用(REA 能力)
inspect_application 集成了 REA,使
Agent 无需源代码即可静态说明本地应用的工作原理。
由于 REA 的检查能力很强,它完全在 vtai-agent 的防护措施内运行,且默认关闭:
[capabilities.rea]
enabled = true # enable only after install vetting
binary = "rea"
command_prefix = ["analyze-javascript-application"]
timeout = 1800.0
keep_copy = false
安全约定(按顺序执行):目标必须通过 deny_globs 检查;随后会将其
复制到 data_dir 下的隔离目录中(复制时会跳过被拒绝的条目和
超出策略范围的符号链接,因此 REA 永远不会读取你无法读取的路径);REA 会在副本上运行,使用最小化的子进程环境(不继承 API 密钥),并在
timeout 后终止;输出 JSON 会被解析,sha256 证据摘要以及 REA 的证据 ID 会写入审计
记录;可选的评审环节(使用与 auto_mode 相同的模型和失败时拒绝策略)会验证证据是否回答了目标,然后才报告成功。原始目标绝不会被修改,除非 keep_copy 为 true,否则隔离副本会被删除。已于 2026-10-21 使用真实 JS 应用,在真实的
rea 6.7.0 CLI 上完成实时验证——已确认进程启动、--json 信封和
证据数字;请参阅
docs/showcases/rea-live-validation.md。
uv run vtai run inspect_application \
--params '{"goal":"explain how Notes builds its CSV export header",
"target":"~/quarantine/Notes-app","dry_run":true}'
仅从官方来源安装 REA(github.com/morluto/rea 或 npm 上的
rea-agents 软件包——请验证来源),不要使用镜像站点。
审计日志
每次允许或拒绝都会记录在 ~/.vtaiagent/vtai.db 中。无需 SQL
客户端即可查询:
uv run vtai audit --limit 20
uv run vtai audit --denied --grep ssh
uv run vtai audit --action delegate --run-id 193
要端到端查看一次运行——目标、每次工具调用、允许或拒绝的内容以及 费用:
uv run vtai runs # list runs
uv run vtai runs --summary # aggregate: spend percentiles, tool counts, denial codes (JSON with --json)
uv run vtai show 193 # one run in full
语音控制(agent-listen / agent-speak)
这两个辅助工具会连接本地 Lemonade Server(Linux/macOS 上使用 TTS kokoro-v1、STT
Whisper-Tiny;Windows 默认使用 Moonshine-Tiny-Streaming,因为 whisper.cpp 配方在某些 AMD GPU 上运行异常),地址为
http://localhost:13305。在任何平台上,都可通过 LEMONADE_STT_MODEL 覆盖 STT 模型。使用 --seconds N 更改
录音时长,使用 --vad 在检测到静音时提前停止,使用 LEMONADE_BASE_URL 指定其他地址。
脚本在 scripts/ 中进行版本管理;使用以下命令安装:
uv run vtai voice-sync
voice-sync 会将两个辅助工具复制到 ~/.local/bin(使用 --dest 可覆盖目标目录),
为它们添加可执行权限,并逐个文件报告 installed / updated / unchanged。vtai voice-sync --check 只报告差异(不同步时退出码为 1)
——拉取脚本更新后,请在不带 --check 的情况下重新运行。设置
VTAI_SCRIPTS_DIR 可从其他检出目录同步。
跨平台说明(已在 macOS 27/ARM 上验证,2026-10-12):
支持 Linux + macOS + Windows —— 三个平台均在 CI 中运行(Linux 和 macOS 的推送检查受阻;套件实现跨平台后,Windows 在 0.6.0 中恢复支持,并将 Git Bash coreutils 提前加入 PATH,使 allowlist 沙盒能够解析实际二进制文件)。没有 rsync 的运行器会跳过依赖 rsync 的测试,并通过 fail-closed 反向测试补充验证。
- Linux 上使用
arecord录音;其他平台上的辅助工具会回退到ffmpeg(-f pulse/avfoundation),因此 macOS 和 Windows 也能正常工作。 --vad目前需要 Linux 上的arecord;其他平台请使用--seconds N。- macOS 麦克风选择:avfoundation 设备索引因机器而异——使用
ffmpeg -f avfoundation -list_devices true -i ""列出设备, 并通过AGENT_LISTEN_FF_INPUT覆盖(默认为仅音频的-f avfoundation -i ":0")。 没有内置麦克风的机器(许多迷你 PC)需要连接外置/USB 设备,否则录音将得到静音(退出码 6,未检测到语音)。 - 播放依次尝试
ffplay→afplay(macOS)→mpg123→aplay。 - 下方的 ALSA 麦克风音量修复和
vtai-audio-fixsystemd 单元仅适用于 Linux;Windows 和 macOS 通过“系统设置”处理此问题。 guardrails.trusted_bin_dirs根据操作系统设置默认值(C:\Windows\System32、/usr/bin, /bin, /usr/local/bin, /opt/homebrew/bin以及 Linux 路径集合); 当前机器上不存在的条目会被忽略(仅当一个条目都不存在时才会验证失败),因此同一配置可以同时列出 Linux 和 macOS 路径。system_info具有跨平台能力:通过sysctl/vm_stat获取内存信息,并在 macOS 上通过/、$HOME、/Volumes/*获取磁盘信息(Metal GPU 说明;macOS 上没有rocm-smi)。- 在 Linux 以外的平台上,
transcode_media默认使用libx264(VAAPI 仅适用于 Linux); 显式设置的"codec"仍会覆盖默认值。 - 在 macOS 上,
disk_audit还会测量~/Library/Caches、~/Library/Logs、/Library/Caches和~/.Trash;新安装的 macOS 会在初始 allowlist 中获得vm_stat(而不是仅适用于 Linux 的free/nproc)。
故障排查
设置与 MCP
opencode mcp list显示✗ vtai-agent failed: NotFound: ChildProcess.spawn (uv ...): 客户端使用精简的 PATH 启动了服务(守护进程的 PATH 为PATH=/usr/bin:/bin:...),因此无法解析裸命令uv。重新运行scripts/register-mcp.sh——它会注册uv的绝对路径——或者编辑 opencode 配置中的mcp.servers.vtai-agent.command数组,将其设为uv的完整路径(command -v uv)。opencode mcp list显示No MCP servers configured:注册是按项目进行的。 请在检出目录中运行该脚本,或使用全局注册;scripts/register-mcp.sh会将其写入~/.config/opencode/opencode.jsonc。- 显示 "config exists: …/config/settings.toml",且设置未生效:
检出目录中的配置优先于
~/.vtaiagent/settings.toml。设置VT_CONFIG="$HOME/.vtaiagent/settings.toml"并重新运行vtai init;vtai info会显示正在使用的文件及其来源。 uv sync失败,并提示Required uv version ... does not match:安装 uv 0.13.1 或更高版本(锁文件修订版本为 5)。
语音(Linux / PipeWire / ALSA)
-
麦克风没有声音,或转录内容失真、出现杂音:内置麦克风增益设得过高,导致输入削波。修复方法(每次登录时也会通过
~/.config/systemd/user/vtai-audio-fix.service应用):amixer -c 2 sset 'Internal Mic Boost' 0 amixer -c 2 sset 'Capture' 75% -
未检测到耳机插孔:内核报告组合端口没有插孔,因此耳机放大器保持关闭。检查
pw-cli enum-params 53 EnumRoute——在耳机牢固插入之前,analog-output-headphones路由会显示available: no。 如果检测不稳定,可使用wpctl set-route 38 1手动设置路由。 -
默认输入源不是所需的麦克风:使用
pw-cli enum-params 53 Route列出路由,并通过wpctl set-route 47 <index>选择 (0= 内置麦克风,1= 耳机麦克风)。 -
STT 返回
[BLANK_AUDIO]或包含杂音的转录内容:使用arecord -d 3 -f cd /tmp/t.wav检查音量并查看峰值;接近 0 表示所选路由没有信号,达到满量程表示发生削波(请调低增益)。
委托编码
- 通过
delegate_coding修改的文件仍留在代码库中:这表示修改正在等待审批——在运行vtai approve <id>保留修改,或使用--rollback放弃修改之前,它们会保留供你审查。只有对于已经由人工审查过的任务,才传入require_approval: false。
贡献
请参阅 CONTRIBUTING.md——其中介绍了设置、任何更改都必须遵守的防护规则,以及测试和 lint 命令。
安全
防护规则、漏洞的定义,以及如何私下报告漏洞: SECURITY.md。
许可证
MIT——请参阅 LICENSE。可使用、分叉,也可在自己的机器上运行。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。