radian is one Rust binary. It starts with no runtime to boot and spends context on the lines a task needs. Its headless command prints every step as a JSON line and exits with a code that says how it ended. radian 是一个 Rust 二进制。启动不用先拉起运行时,上下文只花在任务需要的那几行上;无头命令把每一步按 JSON 逐行输出,退出码说明它是怎么结束的。
$ brew install hisea/tap/radianOpen source under MIT or Apache-2.0: github.com/hisea/radian.开源,MIT 或 Apache-2.0 协议:github.com/hisea/radian。
❯ finish ADR 0037 slice 3 and show me the diff ▾ thinking · 3.2s │ Checking the inbox lanes first. │ │ The job notice must not lower the turn's source: observe_input_source only ever lowers the source, so an inject │ from a System job would turn a human turn into a non-human one. │ │ - followup wakes a new turn, so the source is set fresh │ - inject lands mid-turn and lowers it │ │ So the completion should arrive as a notice with a System source, never as a user turn. • shell $ cargo test -p radian-host --locked · exit 0 · 12.4s ✓ │ running 41 tests │ test job_notify::settled_job_wakes_the_idle_model ... ok │ test job_notify::a_waited_job_sends_no_notice ... ok │ test result: ok. 41 passed; 0 failed; 0 ignored • read crates/radian-host/src/job_notify.rs 100-160 · 0.01s ✓ • patch crates/radian-host/src/job_notify.rs · +5 −2 · 0.03s ✓ │ @@ -120,9 +120,12 @@ impl JobNotify { │ 120 fn notice(&self, job: &Settled) -> Message { │ 121 - let source = InputSource::User; │ 121 + // ADR 0037: a notice is low-trust data, never a user turn. │ 122 + let source = InputSource::System; │ 123 let mut meta = MessageMeta::default(); │ 124 meta.source = Some(source); │ 124 - Message::user(format!("job {} done", job.id)).with_meta(meta) │ 125 + let body = format!("<job id={} exit={} />", job.id, job.exit); │ 126 + Message::user(body).with_meta(meta) │ 127 } ╭─ ask ───────────────────────────────────────────────────────────────────────────────────────────────────────────────── │ How should the UI extension be loaded? │ ◉ External process plugins │ ↳ a separate program, JSON-RPC over stdio │ ○ Built-in Rust components ╰── ▸ thinking · 3.2s · 8 lines ● What I did 1. Added background: true to the shell tool and a job registry in radian-host. 2. Ran the Verify commands; cargo test --workspace --locked passed with 0 warnings. ╭─ rust ──────────────────────────────────────────────────────────────────────────────────────────────────────────────── │ fn notice(&self, job: &Settled) -> Message { │ Message::user(body).with_meta(meta) // never a user turn │ } ╰── ┌─────────────────────────────────┬────────────────┐ │ Command │ Result │ ├─────────────────────────────────┼────────────────┤ │ cargo clippy --workspace │ ok, 0 warnings │ ├─────────────────────────────────┼────────────────┤ │ cargo test --workspace --locked │ 412 passed │ └─────────────────────────────────┴────────────────┘ ── context compacted (rev 2, 148k → 61k) ── * background job bg-2 finished · cargo test -p radian-host · exit 0 · 38s ! background job bg-3 has printed nothing for 6m ── ◜ Working · 12s · esc to interrupt ───────────────────────────────────────────────────────────────────────────────── ❯ explain the inbox lanes Usage: 5h: 80% · 7d: 19% · 30d: 40% · 5h ↺1h35m glm-5.3-flash · radian · notice-source +2 · render-study ▣ ━━━━━━━━──────── 41% ◐ high ↑15M ↓2.6M R1962M $14.510 41.3%/1.0M theme: built-in light
❯ finish ADR 0037 slice 3 and show me the diff ▾ thinking · 3.2s │ Checking the inbox lanes first. │ │ The job notice must not lower the turn's source: observe_input_source only ever lowers the source, so an inject │ from a System job would turn a human turn into a non-human one. │ │ - followup wakes a new turn, so the source is set fresh │ - inject lands mid-turn and lowers it │ │ So the completion should arrive as a notice with a System source, never as a user turn. • shell $ cargo test -p radian-host --locked · exit 0 · 12.4s ✓ │ running 41 tests │ test job_notify::settled_job_wakes_the_idle_model ... ok │ test job_notify::a_waited_job_sends_no_notice ... ok │ test result: ok. 41 passed; 0 failed; 0 ignored • read crates/radian-host/src/job_notify.rs 100-160 · 0.01s ✓ • patch crates/radian-host/src/job_notify.rs · +5 −2 · 0.03s ✓ │ @@ -120,9 +120,12 @@ impl JobNotify { │ 120 fn notice(&self, job: &Settled) -> Message { │ 121 - let source = InputSource::User; │ 121 + // ADR 0037: a notice is low-trust data, never a user turn. │ 122 + let source = InputSource::System; │ 123 let mut meta = MessageMeta::default(); │ 124 meta.source = Some(source); │ 124 - Message::user(format!("job {} done", job.id)).with_meta(meta) │ 125 + let body = format!("<job id={} exit={} />", job.id, job.exit); │ 126 + Message::user(body).with_meta(meta) │ 127 } ╭─ ask ───────────────────────────────────────────────────────────────────────────────────────────────────────────────── │ How should the UI extension be loaded? │ ◉ External process plugins │ ↳ a separate program, JSON-RPC over stdio │ ○ Built-in Rust components ╰── ▸ thinking · 3.2s · 8 lines ● What I did 1. Added background: true to the shell tool and a job registry in radian-host. 2. Ran the Verify commands; cargo test --workspace --locked passed with 0 warnings. ╭─ rust ──────────────────────────────────────────────────────────────────────────────────────────────────────────────── │ fn notice(&self, job: &Settled) -> Message { │ Message::user(body).with_meta(meta) // never a user turn │ } ╰── ┌─────────────────────────────────┬────────────────┐ │ Command │ Result │ ├─────────────────────────────────┼────────────────┤ │ cargo clippy --workspace │ ok, 0 warnings │ ├─────────────────────────────────┼────────────────┤ │ cargo test --workspace --locked │ 412 passed │ └─────────────────────────────────┴────────────────┘ ── context compacted (rev 2, 148k → 61k) ── * background job bg-2 finished · cargo test -p radian-host · exit 0 · 38s ! background job bg-3 has printed nothing for 6m ── ◜ Working · 12s · esc to interrupt ───────────────────────────────────────────────────────────────────────────────── ❯ explain the inbox lanes Usage: 5h: 80% · 7d: 19% · 30d: 40% · 5h ↺1h35m glm-5.3-flash · radian · notice-source +2 · render-study ▣ ━━━━━━━━──────── 41% ◐ high ↑15M ↓2.6M R1962M $14.510 41.3%/1.0M theme: built-in dark
A native binary with no runtime to boot. A foreground command never moves to the background on its own: only background: true starts a job, and a finished job's notice reaches the model, so it keeps working.原生二进制,不用先拉起一个运行时。前台命令不会自己转到后台:只有 background: true 才会起一个 job,跑完的通知会送到模型那里,模型不用干等。
Reads take line ranges. A budget guard watches the window and compacts before it overflows. The footer shows tokens and cost as you go.读文件按行号范围读。预算守卫盯着上下文窗口,快满之前先压缩。footer 里随时看得到 token 和费用。
radian runs no outside agents; it is built to be run by them. One prompt in through radian exec, every step out as a JSON line, and an exit code that tells completed from failed from out of budget. Inside herdr it reports working, idle or blocked by itself, and radian attach watches any session read-only. Parallel work stays inside one reply: several subagent calls run side by side.radian 不调度外部 agent,它是为了被调度而做的。一句话从 radian exec 进去,每一步按 JSON 逐行出来,退出码分得清完成、失败和超出预算。在 herdr 里它自己报告 working、idle、blocked;radian attach 可以只读地看任何一个会话。并行只发生在一条回复之内:几个 subagent 调用同时跑。
Under all three: every step goes to a journal you can resume and fork, the sandbox is a switch (one flag, or saved per project, and it can only narrow), and only you can approve. 三者底下:每一步都写进可恢复、可 fork 的会话日志,沙箱是一个开关(一个参数,或按项目保存,只能收窄),审批只能由你来给。
One prompt in, the journal out: a JSON line per step and the outcome on the last line. It is the same session file, so a script can stop halfway and you pick it up in the full-screen app.一句话进,journal 出:每一步一行 JSON,最后一行是结局。同一个会话文件,脚本跑到一半,可以在全屏界面里接着跑。
Inside herdr, radian reports working, idle and blocked by itself, and nothing about commands, paths or content.在 herdr 里,radian 自己报告 working、idle、blocked,不报命令、路径和内容。
Instruction files, skills, MCP servers and themes carry over.指令文件、skills、MCP server 和主题可以直接带过来。
AGENTS.md · CLAUDE.mdRead from the workspace up to the repo root, with @path imports.从工作区一路读到仓库根,支持 @path 导入。skills~/.agents/skills/<name>/SKILL.md, the directory pi, Codex and opencode share.~/.agents/skills/<name>/SKILL.md,和 pi、Codex、opencode 共用的目录。MCPmcpServers config, ${VAR} expansion, stdio servers.mcpServers 格式的配置,支持 ${VAR} 展开,stdio server。hooksThe Claude / Codex JSON subset: PreToolUse, PostToolUse, Stop.Claude / Codex 的 JSON 子集:PreToolUse、PostToolUse、Stop。themespi theme files, imported once with radian theme import.pi 的主题文件,用 radian theme import 一次性导入。memoryGlobal and project scopes. The agent cannot edit the records you wrote.全局和项目两层。agent 改不了你自己写的记录。Homebrew on macOS and Linux, a release tarball, or Cargo from source.macOS 和 Linux 都能用 Homebrew,也可以下载 release 安装包,或者用 Cargo 从源码装。
$ brew install hisea/tap/radian$ cargo install --git https://github.com/hisea/radian radian-tuigithub.com/hisea/radian/releases signed macOS and static Linux tarballs签名的 macOS 包和静态 Linux 包
radian: homebrew-core already has a rad formula. The tarball and Cargo also give you the rad alias.Homebrew 只链接 radian,因为 homebrew-core 里已经有一个叫 rad 的包;安装包和 Cargo 还会带上 rad 这个别名。workspace profile needs bubblewrap.Linux 上 workspace 等级需要先装 bubblewrap。radian login and radian. Full steps: quickstart.装好后运行 radian login,再运行 radian。完整步骤见快速开始。Full screen at the keyboard. Headless for scripts, CI and other orchestrators.坐在键盘前用全屏界面;脚本、CI 和别的编排器用无头命令。
The full-screen terminal app.全屏终端界面。
radian
# sandbox# 沙箱
radian --profile workspace
One prompt in, the steps out as JSON lines.一句话进,每一步按 JSON 逐行出。
radian exec --resume demo \
--output jsonl \
-p "now read docs/"
/login stores the key in ~/.radian/credentials/auth.json.模型来源:Anthropic、OpenAI、ChatGPT(浏览器 OAuth 登录)、opencode-go,以及任何兼容 OpenAI 的端点。/login 把凭据存进 ~/.radian/credentials/auth.json。One radian is the angle where the arc is exactly as long as the radius.一弧度,就是弧长正好等于半径时的那个角。