关于 wyd
wyd 是面向 macOS 和 Linux 编码 Agent 用户的本地运行时溯源工具。它将开发进程关联到 Agent 会话和项目,解释遗留进程,并可监督有时限的命令运行。
主要功能
- 01追踪进程所属的 Agent 会话和项目
- 02根据证据解释进程归属
- 03查看会话与受管理的运行
- 04监督命令并限制时长、保留日志
- 05通过 MCP 提供只读运行时查询
适用场景
- 01查明哪个 Agent 会话启动了进程
- 02识别遗留的浏览器或开发服务器
- 03为测试设置超时并保留输出
MCP 相关
wyd 通过 stdio 提供 MCP 服务。客户端可查询会话、进程归属、运行、输出和容量;启动或取消运行需使用 `--allow-run`。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
wyd
wyd? — 你在做什么?
查看你的编码 Agent 留下了哪些仍在运行的程序。
编码 Agent 会启动 MCP 服务、无头浏览器、开发服务器、工作进程和数据库。
ps 会告诉你正在运行什么。wyd 会告诉你为什么——哪个会话启动了它、它属于哪个项目,以及它是否是遗留进程。
OpenCode
└─ chrome-devtools-mcp
└─ Chromium ×8 1.2 GB
Agent exited 47m ago
⚠ leftover
本地运行,支持 macOS 和 Linux。无需账户、网络或遥测。
curl -fsSL https://wyd.sh/install.sh | sh
# or
brew install oxyplay/tap/wyd
# or
cargo install wyd
wyd
wyd upgrade # brew or cargo, matching the install
wyd --demo # deterministic synthetic dataset — screenshots/demos, no host scan
每个带标签的发行版本都会将 crate 发布到 crates.io,并自动更新
oxyplay/homebrew-tap 中的
Formula/wyd.rb,因此 wyd upgrade 始终保持最新,无需手动操作。如果
公式更新有所延迟,wyd upgrade 仍会打印提示。
二进制文件:GitHub 发布版本。从克隆仓库安装:cargo install --path .

系统守护进程会隐藏。桌面版 Chrome 会隐藏。由 Agent 启动的 Chromium 不会隐藏。
为什么选择 wyd
ps / 活动监视器 | Docker Desktop | wyd | |
|---|---|---|---|
| 所有进程 | 是 | 仅容器 | 仅开发运行时 |
| 启动者 | 否 | compose 标签 | Agent → MCP → 浏览器 |
| 所属项目 | 否 | 有时 | 当前工作目录 / git 根目录 |
| 是否为遗留进程? | 否 | 由你猜 | 评分并说明原因 |
| 安全终止 | 只能祈祷 | stop/rm | PID + 启动时间,按 y 确认 |
| 卷 | — | 很容易误删 | 未使用 ≠ 垃圾;需要按 D |
专为整天运行编码 Agent、之后又会问 那个会话留下了什么? 的人打造。
运行时归属
除了实时视图,wyd 还会追踪编码 Agent 运行时会话——某个会话启动了哪些
资源,并以 boot_id + pid + start_time 为键,因此即使进程被重新托管或 Wyd
重启,来源信息也能保留下来。即使确切的进程祖先关系已不可用,确定性解析器
也会通过可解释的评分将资源归属于某个会话。
- TUI 中的 Sessions 视图(顶层):Agent · 项目 · 状态 · 时长 · ID,并带有详情面板。
wyd why <pid>——哪个会话拥有某个进程,以及相关证据。如果没有 Agent 会话拥有它,则会指出系统来源(systemd 单元、launchd、cron、tmux、ssh、snap、flatpak 或交互式 shell),并显示祖先链。退出码:0表示明确归属,1表示遗留或未归属,2表示未运行,5表示内部错误。wyd --json sessions——以 JSON 格式显示已记录的会话。wyd serve——通过 Unix 套接字(wyd.sock,模式 0600,单实例)运行本地守护进程。它会保持来源信息为最新,并响应只读查询;供应商可以通过session_start/session_end注册会话(其 ID 会作为别名映射到 Wyd 会话)。wyd mcp——通过 stdio 运行 Model Context Protocol 服务,让编码 Agent 查询 wyd 的会话、PID 的归属者以及由它管理的运行任务(--allow-run会启用主机执行)。
MCP
wyd 也支持通过 stdio 使用 Model Context Protocol,因此编码 Agent
可以询问机器有哪些程序是它自己或其他 Agent 留下的。
wyd mcp # read-only
wyd mcp --allow-run # also allows starting and cancelling runs
启动本地 MCP 服务。始终提供读取工具:
list_sessions(已记录的 Agent 会话)、explain(按 PID 查询进程所属会话)、
list_runs、get_run、read_run_output 和
get_capacity。--allow-run 只会为当前连接添加 start_run 和
cancel_run;未启用时,这些调用会被拒绝,并提示使用 --allow-run 重启。
无需网络或账户——答案来自本地来源信息存储。
已在 MCP Registry 注册:
- MCP Registry 名称:
mcp-name: io.github.oxyplay/wyd
受管理的运行任务
wyd run 会在本地监督器下启动命令,让 Agent 获得截止时间、由 wyd 管理的进程组,
以及有大小限制的日志,而不是卡住的 shell。
wyd run --timeout 120s -- npm test
该命令使用 argv,而不是 shell — &&、管道和 glob 都需要显式使用
sh -c。--timeout 默认为 10m,--grace(从软停止到强制停止的宽限时间)默认为
3s,且 --cwd 必须是绝对路径。--json 会输出结构化结果,而不是捕获的输出;在 24 小时内重复使用同一个
--request-id 会复用该次运行,而不会启动第二次运行;同一个 ID 搭配不同命令则会被拒绝。
所有运行共享同一份准入预算,因此同一台机器上的多个 Agent 不会同时全部启动。
wyd run 接受每次运行的资源请求:
wyd run --memory 512 --enforce monitored --queue-timeout 60s -- npm test
| 标志 | 含义 |
|---|---|
--memory <MiB> | 从运行预算中预留的内存;搭配 --enforce monitored 时,也作为停止阈值。 |
--enforce none|monitored|hard | 默认值为 none。monitored 会在观测到的用量超过 --memory 时停止运行;hard 是内核限制,如果后端无法提供,则会在启动进程前拒绝请求 — 绝不会静默降级。 |
--queue-timeout <dur> | 请求等待可用槽位的最长时间;仅对本次运行覆盖 queue_timeout_secs。与 --timeout 相互独立,后者只在进程启动时开始计时。排队请求等待超时后会以 timed_out 结束,并附带队列超时详情;等待时间不会计入执行超时时间。 |
--cpu <millicores> | CPU 请求。仅供参考:目前没有后端会强制执行此项。 |
--processes <n> | 进程数请求。仅供参考:目前没有后端会强制执行此项。 |
因监控内存阈值而停止的运行会以 outcome=resource_limit 结束,
并以 137 退出,同时附带指出观测数值的 limit_event。
预留量是预算,不是实测内存。 reserved_memory_bytes 是已准入运行预留量的总和,并非它们的实际用量。
实测用量会单独报告为 observed_memory_bytes;在 macOS 上,该值是每 200 毫秒采样一次的运行进程组内 RSS 总和。
共享页面可能被重复计数,短暂的峰值也可能被漏掉,因此这只是观测值,不是保证值。
macOS 不提供硬内存限制:aggregate_memory_limit 为
monitored,并且在创建运行之前就会拒绝 --enforce hard,而不是将其降级。在 Linux 上,硬限制来自委派的 cgroup v2
子树(memory.max、memory.swap.max、cpu.max、pids.max),因此只要存在可用值,
aggregate_memory_limit、cpu_quota 和 process_limit 就会报告 available。没有委派时,它们会报告 unavailable,且 hard
请求会被拒绝 — wyd 不会请求 root 权限,也不会改写你的 systemd 单元。将监督程序放入带有
Delegate=yes 的单元,或将 WYD_CGROUP_ROOT 指向委派子树中你拥有的目录,然后
重启监督程序(其能力在启动时固定)。由于 cgroup 成员身份会由所有后代进程继承,即使通过 setsid 脱离进程组的子进程仍处于该运行的 cgroup 中,并会随其一起终止。所有运行也处于同一个聚合 cgroup 下,其 memory.max 即为运行预算,因此
预算是对总量的内核限制,而不只是准入规则;
wyd capacity --set memory_budget_mb=… 会更新该限制。可在 [runs] 中设置
cpu_budget_millicores 和/或 pids_budget,以同样方式限制所有运行的 CPU 总量和进程数(wyd capacity 会报告这些值,运行时更改也会更新内核限制)。
之后可检查或停止它:
wyd runs # recent runs: state, outcome, cleanup, duration
wyd runs --json # full RunView records
wyd logs <id> --follow # retained stdout (--stream stderr for the other)
wyd cancel <id> # idempotent
wyd capacity 会显示准入限制和当前用量;--json 会附加能力状态(monitored、available 或 unavailable):
wyd capacity # slots, queue, reservations
wyd capacity --json # the full Capacity record, incl. capabilities
wyd capacity --set max_parallel=2 --set queue_timeout_secs=30
--set 可重复使用,接受任意 [runs] 键对应的 key=value:
| Key | Default | Meaning |
|---|---|---|
max_parallel | 4 | 同时获准运行的任务数。 |
max_parallel_per_project | 2 | 每个项目根目录同时获准运行的任务数。 |
max_queued | 32 | 队列长度;超出此长度的请求会被拒绝,而不会一直挂起。 |
queue_timeout_secs | 600 | 请求等待可用名额的最长时间。 |
memory_budget_mb | 8192 | 正在运行的任务可预留的总内存。 |
default_run_memory_mb | 512 | 未指定内存量的任务所预留的内存。 |
starvation_after_secs | 60 | 被跳过这么久的请求将优先获得下一个名额。 |
更改限制后,新限制仅适用于之后的准入;不会因此终止正在运行的任务。
如果新上限低于已准入的任务数,系统会报告临时超限状态
over_parallel_limit,而不会将其隐藏。相同的键也位于
~/.config/wyd/config.toml 的 [runs] 下。
TUI 以只读方式显示相同的任务:在 Overview 窗格中选择 Runs,
按 enter 打开任务详情。Runs 窗格还会显示已配置的限制
(实时计数在此处标记为不可用,因为 TUI 读取的是存储,而不是
supervisor 套接字),对于排队中的任务,还会显示其位置、等待时间和原因。
Web 仪表板提供相同的视图,并额外显示实时容量面板;两者都不能
更改限制或启动命令。
supervisor 拥有任务,而不是启动任务的客户端:如果 CLI 或 MCP
连接断开,任务仍会运行至截止时间,之后仍可查看其结果和日志。读取操作持久且无需守护进程——wyd runs、
wyd logs 和 MCP list_runs/get_run/read_run_output 会读取存储
和保留的日志文件,因此即使没有运行中的 supervisor 也能正常工作。wyd capacity 和 Web 仪表板的容量面板在没有运行中的 supervisor 时,会报告已配置的 [runs]
限制和空队列,而不会启动 supervisor;MCP get_capacity 工具会向 supervisor 发送请求,并按需启动它,
与 start_run 一样。启动或取消任务需要 supervisor;它会按需启动,并在空闲五分钟后退出;下次运行 wyd run 或
wyd mcp --allow-run 会重新启动它。向 supervisor 发送
SIGTERM/SIGINT 时,它会先停止正在运行的任务(最多等待 10s),而不是将其遗弃。
退出代码:命令退出时使用其自身的代码;收到信号时使用 128+signal;超时时使用 124;取消时使用 130;无法启动命令时使用 125;资源限制导致命令停止时使用 137。具体原因始终记录在 JSON 中(outcome、exit_code、signal、cleanup、detail、
limit_event)。
每个流的输出上限为 10 MiB,所有保留任务的总输出上限为 250 MiB——保留开头部分,并报告截断情况
(JSON 中的 stdout_truncated/stderr_truncated,以及
wyd logs 输出中 stderr 上的标记)。达到上限后,管道仍会持续排空,因此输出量大的测试不会卡住 supervisor。已完成的任务及其日志保留 7 天。
这不是什么
托管运行仅是在 macOS 和 Linux 上运行的本地进程,仅此而已:
- 清理仅涵盖运行自身的进程组。若命令脱离该进程组运行 —
setsid、双重 fork、外部守护进程 — 不会默默声称已涵盖:cleanup会报告incomplete或unknown,而不是complete。 TMPDIR、TMP和TEMP指向运行专属目录。这只是 便利功能,不是沙箱:命令仍可写入你有权限访问的任何位置。- 不隔离文件系统、网络或机密,也不控制软件包安装。请在容器或虚拟机中运行 不受信任的代码,而不是在这里运行。
- 受监控的内存限制是一项策略,而非保证:两次间隔 200 ms 的采样之间出现的短暂峰值会被漏掉,共享页面也可能被重复计数。硬性
内存、CPU 和进程数限制取决于后端:macOS 仅进行监控;Linux 会在有可用的委派式 cgroup v2 子树时通过它强制执行限制 — 否则该功能会报告
unavailable,并会拒绝hard请求,而不是用近似方式替代。macOS 上的硬性限制需要 Linux 执行后端(容器/虚拟机);在此功能实现之前,请在容器中运行 受资源限制的命令。关于此项功能以及真正的暂停/恢复测试,计划中的下一步见 docs/managed-runs-plan.md → «后续计划»。 - 预留额度是预算,并非测得的 RAM:
reserved_memory_bytes表示允许运行使用的内存,observed_memory_bytes表示观察到某次运行使用的内存。
MCP 配置:wyd mcp 为只读模式。wyd mcp --allow-run 会为该连接启用 start_run 和 cancel_run;start_run 被描述为主机执行,wyd 绝不会将其放在沙箱中运行。
WebMCP
试用托管演示:https://demo.wyd.sh
wyd 提供十一种 WebMCP 工具,让浏览器 Agent 能够在与人类所见相同的界面中调查遗留项:list_sessions、get_session、
list_leftovers、explain_process、focus_resource、propose_cleanup,以及托管运行读取工具 list_runs、get_run、read_run_output、get_capacity 和仅用于提议的 propose_cancel_run。工具调用不会终止任何进程 — 清理须由人类确认,取消运行也会经过相同的确认提议流程。网页可以读取限制和队列状态,但无法更改限制或启动命令。
wyd web # local runtime (loopback)
wyd web --demo # synthetic dataset, no host data
快速测试
将以下内容粘贴到 演示 中的浏览器 Agent(或本地 wyd web):
Find an ended OpenCode session, show me what it left running, explain Chromium PID 4102, and prepare a cleanup proposal. Do not execute cleanup.
WebMCP 支持是在 OpenAI WebMCP Challenge 期间,基于现有的 wyd CLI/TUI 运行时检查器添加的。
参见 docs/webmcp.md。
按键
| 按键 | 操作 |
|---|---|
← → / h l | 概览 / 列表 |
↑ ↓ / j k | 移动(滚动详情弹窗) |
Tab | 聚焦概览 / 列表 |
backspace | 返回(清除筛选 / 项目 / 区域,绝不退出) |
enter | 打开详情弹窗;在项目上按下时,将该项目固定 |
space | 标记多个项目 |
x / K | 终止 / 强制结束(按 y 确认) |
s | 停止正在运行的 Docker 容器(运行中的容器优先排列) |
c | 清理 Docker(按 y;卷需要按 D) |
P | 清理未使用的匿名卷(确认;保留命名数据) |
o | 以 HTTP 方式打开选中的监听器(o try HTTP — 这是明确的假设;监听器显示为套接字,而非 URL) |
p | 项目 |
/ | 筛选 |
r | 刷新 |
? | 帮助 |
esc | 关闭弹窗,然后清除筛选 / 项目,最后退出 |
q | 退出 |
终止操作只向项目自身的 PID 发送信号(按 PID + 启动时间重新检查)。命名卷绝不会被视为垃圾 — 只有未附加的匿名卷(P)才会列为可清理对象,并且需要确认。底部提示行会根据上下文变化:它会显示适用于当前所选行的操作。
脚本
与 TUI 中的快照相同——适用于 Agent 完成任务后:
wyd --json leftovers
wyd --plain mcp
wyd --json project myapp
wyd --json sessions # recorded agent sessions
wyd why <pid> # which session owns a process, and the evidence
wyd why <pid> --tree # full ancestry tree: path + children, target marked
wyd ports # listening ports: process on each + what started it
wyd ports --json # same, machine-readable
wyd serve # local daemon: Unix-socket API + keeps provenance fresh
wyd mcp # MCP server over stdio (for coding agents)
wyd prune --dry-run # list anonymous volumes that would be deleted
wyd prune # confirm, then delete them
筛选项:leftovers、mcp、agents、docker、project、sessions(仅 JSON)。
wyd why <pid> 在进程由活跃会话正常管理时退出码为 0;进程为残留进程或没有记录的所有者时退出码为 1(此时会显示系统来源);pid 未运行时退出码为 2;发生内部错误时退出码为 5——因此,wyd why <pid> && … 或 case $? 可用于脚本和 CI。
wyd why <pid> --tree 会打印完整的祖先树,而非文字说明:从 pid 1(或最高的可见祖先)到目标进程(以 ◀ 标记)的路径,以及目标进程的子进程(最多显示 10 个,超出时会显示 … (+N more) 行)。这只是结构视图——无需来源信息。
wyd ports 会列出每个监听套接字的 address:port、对应进程及其启动来源——如果来源信息已知,则显示所属的 Agent 会话(session opencode (active));否则显示系统来源(systemd (postgresql.service)、launchd、cron 等)。--json 会为每个条目返回 {address, port, pid, process, owner_agent, owner_session, owner_state, source},并省略不适用的字段。
{
"runtime": [{ "type": "mcp", "name": "chrome-devtools-mcp", "pid": 94148, "status": "leftover", "reasons": ["owning agent missing"] }],
"docker": [{ "type": "dangling-image", "name": "abcdef012345", "status": "dangling", "size_bytes": 1400000000 }]
}
字段名称在主版本升级前保持稳定。空的 ports / reasons / children / project 会被省略。
配置
~/.config/wyd/config.toml——文件不存在也没关系。
[leftovers]
server_age_hours = 8
[runs]
max_parallel = 4
max_parallel_per_project = 2
max_queued = 32
queue_timeout_secs = 600
memory_budget_mb = 8192
default_run_memory_mb = 512
starvation_after_secs = 60
[persistent]
commands = ["postgres", "redis-server"]
[projects]
roots = ["~/Work"]
[keys]
quit = "q"
kill = "x"
force_kill = "K"
clean = "c"
stop = "s"
prune = "P"
help = "?"
refresh = "r"
[[signature]]
category = "agent"
names = ["myagent"]
contains = ["my-company-agent"]
display = "myagent"
许可证
Apache-2.0。Copyright 2026 Maksym Nevinchanyy。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。