YuShan(嵛山)是一座中国海岛的名字。
一个用 Rust 写的 agent 运行时。
23 MiB 内存,10 MB 一个文件,没有 Node,没有 JVM,没有 Python。
说人话:它只负责让一个 AI 会干活的那部分——叫模型、记对话、让模型调工具、把过程用事件流吐出来。
它不自带一个完整产品该有的全部东西。沙箱、权限、审批、多租户安全由上层负责 (本项目配套的是 seabox)。
同类工具都在往「大而全」走:语音、代码模式、插件市场、IDE 集成。本项目反着走:
只做骨架,把重量留给别人。但仓库里有一个能直接用的命令行 agent,叫 ys-coding-agent——
有 TUI,能读写文件、跑 shell、联网搜索,能开子 agent,能装 skill。
不是 Demo,是日常真能拿来干活的工具。本项目已经使用 ys-coding-agent 开发.
$ ys-coding-agent # 交互界面
$ ys-coding-agent -p "解释这个仓库" # 一次性输出
$ ys-coding-agent --json "跑一遍测试" # 事件流,给别的程序吃内存现在很贵。手机、平板、边缘盒子常见就是 4 GB / 8 GB,还要分给系统、相机、浏览器。 一个 agent 开局就吃掉 300 MiB,意味着在这类设备上它只能当个备选项,不能当常备工具。
同一个机器上,各家 CLI 启动到空闲界面之后常住多少(RSS 合计,含子进程,不含模型调用):
| 项目 | 常驻 | 是 YuShan 的 | 进程数 | 技术栈 |
|---|---|---|---|---|
| YuShan | 23 MiB | 1× | 1 | Rust |
| codewhale | 132–169 MiB | 6–7× | 3 | Rust |
| Pi | 142–145 MiB | 6× | 1 | TypeScript |
| Claude Code | 262–263 MiB | 11× | 1 | TypeScript |
| Codex CLI | 349–357 MiB | 15× | 4–5 | Rust + Node |
| OpenCode | 820–849 MiB | 36–37× | 1 | TypeScript |
最省的那个,也是本项目的 5 倍以上。
怎么测的(点开看,可以自己复现)
同一台机器(Ryzen 9 7945HX,Linux 7.0),每个 CLI 在伪终端里起来,等 6 秒,
按进程名把相关进程的 VmRSS 加起来,每种跑 3 遍取范围。
脚本在 scripts/ram-compare.py,一遍不到 10 秒:
$ python3 scripts/ram-compare.py --rounds 3 -v两个容易被测错的地方,脚本里都处理了:
- 辅助进程会脱离进程树。Codex 起一个
app-server常驻后台(200 MiB 左右), 这个进程会挂到 systemd 下——只看父子关系会漏掉它,数字少一半。 - 匹配要带边界。
pi这个裸词会撞上pipewire。
这不是公平比赛。 它们比本项目多很多东西(语音、代码模式、IDE 集成、插件市场)。 这张表只说一件事:光跑一个 agent 循环,不需要几百兆内存。
- 小。 单文件 10 MB,跑起来 23 MiB。不需要装 Node、JVM、Python 任何运行时—— 所以能塞进手机、平板这类设备。
- 干净。 十来个 crate,每个只做一件事,依赖只能从上往下走。
渲染层(
ys-tui-coding)根本不认识Agent——这条靠Cargo.toml卡住,写错了编译不过,不靠自觉。 - 能换。 模型后端、工具集、界面都是可插拔的 crate。接自己的模型?写个
Model实现。 不想要 TUI?用--json直接吃事件流,自己画。 - 不做安全。 不是疏忽,是分工。沙箱那层交给我的另一个项目 seabox—— Landlock + seccomp + namespace 的 OS 级限制,同样不需要 Docker。 YuShan 负责「能干活」,seabox 负责「越界就拦住」。
分层图
flowchart TB
L0["ys-core<br/>Message / Usage / StopReason"] --> L1
subgraph L1["契约层"]
EVENT[ys-event] --- PROTO["ys-protocol<br/>零 tokio"]
TOOL[ys-tool] --- MODEL[ys-model] --- SESSION[ys-session]
end
L1 --> L2
subgraph L2["运行时"]
COMP[ys-component] --> LOOP[ys-loop] --> RT[ys-runtime]
end
L2 --> L3
subgraph L3["可选适配器"]
OAI[model-openai-compatible] --- TB[tools-basic] --- TW[tools-web]
end
L3 --> L4
subgraph L4["产品层"]
TUI["ys-tui-coding<br/>不认识 Agent"] --- CA[coding-agent]
end
依赖只能向下,不能向上。唯一的跨层通话是 ys-protocol 的纯数据类型和三条有界信道。
需要 Rust 1.88+(edition 2024)。Ubuntu 另需 build-essential pkg-config libssl-dev:
$ git clone https://github.com/zsdfbb/YuShan.git && cd YuShan
$ ./scripts/install.sh # 构建 release,装到 ~/.local/bin
$ ys-coding-agent脚本会先查一遍工具链,缺什么就打印对应的 apt-get / rustup 命令,不代跑。
--with-skills 顺带装仓库自带的 skill,--dry-run 只看计划,--uninstall 只删二进制、
不动 ~/.yushan;升级就是 git pull && ./scripts/install.sh。
不想装到 ~/.local/bin,或者只想跑一下不安装:
$ ./scripts/install.sh --dest ~/bin # 换安装目录(或 YUSHAN_INSTALL_DIR)
$ ./scripts/cargo-build.sh build --release && ./target/release/ys-coding-agent首次启动在界面里输入 /login 选 provider 并填入 key(deepseek / minimax /
opencode-go / glm / glm-coding / mimo 已内置端点,custom 这类没内置 base 的
会再问一句 base URL)。登录后直接说话即可。
不想开界面:
$ ys-coding-agent -p "这个项目是做什么的"模型
- 多 provider:
/login登录、/logout登出、/model运行中换模型 - 思考档位可调(minimal → max)
- 拉不到模型列表时也能降级启动,不会卡住
干活
- 12 个工具:9 个基础(
readwriteeditbashgrepfindlswebsearchwebfetch)bash_bg+subagent_async+subagent_send(后三者追加在末位,顺序即契约)
- 搜索后端可配多个(SearXNG / DeepSeek / Tavily / Bocha / Firecrawl),配了哪个用哪个
- 子 agent:派一个出去干子任务,父回合不等它、继续干自己的,结果回来时自动起一轮接着处理
- Skill:把
SKILL.md丢进.yushan/skills,模型需要时才读正文——不占上下文 - git worktree:一个需求一棵树,
worktree create / attach / list / remove
用起来
- 三种模式:TUI /
-p整回合跑完再输出 /--json事件流 - 会话:默认开新的,
--resume恢复旧的,/new再开一个,/compact压上下文,/export导出 - TUI:滚轮、拖选、输入历史、命令和 skill 补全
- 结构化日志默认开着,
--stats能看背压
已经写好设计、只差实现的:
- 追问 —— 让系统能在回合结束后自己接着说话。协议槽已留好
- 长程 todo —— agent 自己维护跨回合的任务清单,配合上面那个追问才跑得起来
- 子 agent 分角色 —— 现在子 agent 的工具和父 agent 一模一样,应该按角色给不同的表
- 跨会话输入历史 —— 现在
↑只能翻当前这次会话,退出就没了
有意不做的:
- PTC(让模型写代码调工具) —— 唯一能大幅减少对话轮数的办法,但需要执行边界。等上层给出边界再说
- 动态插件热插拔 —— 第一版不做,静态组装够用
- 沙箱、权限、审批 —— 不归这里管,见 seabox
crates/ 运行时核心,10 个 ys-* crate
adapters/ 可选的模型和工具实现
apps/ 可执行程序(coding-agent)
skills/ 仓库自带的 skill
docs/ 设计、决策记录、现状文档
$ ./scripts/install-hooks.sh # 装 pre-push 钩子(clone 后跑一次;推送前自动跑测试)
$ ./scripts/cargo-build.sh # 构建(别直接用 cargo build,有增量垃圾清理)
$ ./scripts/par-test.sh # 跑全部测试,约 7 秒
$ ./scripts/verify.sh # 完整门:测试 + 变异测试(发版 / 改关键逻辑前)
$ cargo clippy --all-targets && cargo fmt想深入了解:
| 想看什么 | 去哪 |
|---|---|
怎么用 ys-coding-agent(CLI / 内置命令 / 键位) |
apps/coding-agent/README.md |
| 约定和硬性约束 | AGENTS.md |
| 架构图(分层 / 信道 / 时序 / 数据流) | docs/architecture.md |
| 现在实际是什么样(含与设计的分歧) | docs/design-final/ |
| 每个决策为什么这么定 | docs/adr/ |
| 还没做什么 | docs/TODO.md |
| 怎么贡献 | CONTRIBUTING.md |
仓库自带 5 个开发用 skill(架构探索 / 设计 / 校验、诊断、顺序工作流),外加 pdf-analysis 示例。
clone 后跑 ./scripts/install-skills.sh 即可在 agent 里通过 / 调用 —— 这个项目本身就是用它们迭代的,
哪种任务用哪个、在本 runtime 下怎么落地(无 plan mode)见
CONTRIBUTING.md。
v0.0.1,接口还会动。核心循环和 CLI 已经能日常使用,其余按 docs/TODO.md 推进。
配套的沙箱 seabox 同为 v0.0.1。