ESSAY // 01
·
AI-NATIVE SOFTWARE DELIVERY
只留一行 git clone:把最后一公里交给你的 Agent
今天读到 Steven Lynn 写的一篇文章,聊到软件工程里一个困扰了开发者几十年的乘法题:
几个基础的操作系统和运行场景,和具有几类不同使用习惯的用户:有人用 macOS、有人用 Arch Linux、有人挂 Surge TUN、有人用 Clash HTTP 代理、有人写 Rust、有人需要跨终端同步剪贴板。这两个正交的维度一旦组合,立刻就会裂变出几千种具体的需求。
过去的开源作者往往只有两条路可走:要么把所有跨平台兼容逻辑、配置开关和边缘情况全塞进代码库,最后写出一个谁都觉得重、谁都调不通的超大仓库;要么只服务最大公约数,任何环境稍微偏离预设轨道的用户只能提 Issue 漫长等待。
但站在今天,「每个人电脑上都常驻着一个趁手的编程 Agent」已经成了一个默认成立的前提。当用户的终端拥有了就地理解代码、排查环境和动手改造软件的能力,我们交付软件的终点其实已经变了:开发者不再需要替远端成千上万个素未谋面的用户穷举所有组合,而是应该交付一套「技术选型明确、能力高度原子化、工程架构透明可读」的标准件,把最后一公里交给用户本机的 Agent。
这恰恰是我设计和开源 Blackhole 时的全部想法。
为什么要做 Blackhole?
用过 Claude Code 的人大概都有过这种割裂感:一方面,你希望它拥有足够高的自主权(甚至开启 --dangerously-skip-permissions),让它自己跑测试、装依赖、改代码;但另一方面,如果你直接在宿主机上裸跑,或者只是随手起一个普通 Docker 容器挂载目录,它实际上能看到你整台机器的底裤:
- 你的
$HOME 目录、~/.ssh、~/.gitconfig 和云厂商凭证;
- 宿主机环境变量里带出的硬件标识、系统语言、时区与账号指纹;
- 一旦你本机的代理软件意外闪退,容器流量会立刻降级为宿主机直连,在毫无察觉的情况下裸奔。
我想要的是一个像「黑洞」一样的隔离层:
- 宿主机零污染、零 fingerprint:宿主机上甚至不需要安装
@anthropic-ai/claude-code 或 Node.js。所有的硬件标识、网卡信息、$HOME 目录在边界处被彻底截断。
- 极速的工作区穿透:只有你当前所在的项目目录(
$PWD)和用于粘贴截图的临时目录($TMPDIR),通过 Apple Virtualization (vz) + virtiofs 穿透进容器,读写吞吐保持在 3.2 GB/s,1000 个小文件遍历只需 33.9 ms,跑 rg 和 git status 毫无体感延迟。
- Fail-Close 网络熔断:在虚拟机内核的
iptables DOCKER-USER 链上直接上锁。代理不在线,或者断流守护进程心跳超时,容器网络立刻物理锁死,绝不漏出一个直连数据包。
把沙箱做成「原子化标准件」,而不是大黑盒
如果按照传统软件的思路做这样一个工具,它大概率会变成一个带着复杂设置面板的桌面客户端,或者一个上千行配置的 YAML 引擎。
但在做 Blackhole 时,我严格遵循了「标准件」的三个原则:
1. 把最难的底层取舍敲死
在 macOS 上跑容器,最容易踩坑的就是文件挂载性能、容器内外 UID/GID 权限错乱、以及宿主机文件被意外写坏。Blackhole 在底座上的选择:
- 底层直接锁定
vz + virtiofs;
- 容器启动瞬间,通过
docker-entrypoint.sh 动态读取 /workspace 的宿主机 UID/GID,用 gosu 实时对齐容器内 node 用户的身份,宿主机永远不会出现 root 属主文件;
- 所有配置写入、注册表更新、会话导出和信号传递,全部强制采用同目录临时文件 +
mv 原子替换,杜绝并发竞态。
2. 把所有高阶能力拆成正交的原子能力
系统里所有功能都是独立的原子原语,按需拼装:
- 想要给不同客户或不同项目完全隔离的凭证与资源? 用
blackhole bind <profile> <dir>,把目录绑定到独立的虚拟机 Profile,子目录自动继承。
- 某个项目需要用
cargo、ffmpeg 或特定的 C++ 头文件? macOS 的 /opt/homebrew 二进制不能挂进 Linux 容器,你只需要在项目下放一个 .blackhole/Dockerfile,继承 blackhole-claude:latest 写两行 apt-get,Blackhole 会自动为这个项目构建专属派生镜像,既不污染全局,也不泄露项目源码到构建上下文。
- 想要让宿主机上的其他脚本或 Agent 与容器内的 Claude 协同? 用内置的
blackhole signal 原语做原子化的文件信号同步。
- 想要让宿主机的 Agent 读取某次长对话,或者实时备份、跨虚拟机迁移? 用
blackhole sessions、export-watch 和 resume。
3. 让工程规范本身成为给 Agent 读的蓝图
做官网的时候,我原本在页面上放了四五步安装和初始化命令。后来我想了想,把它们全删了,只留下了一行:
git clone https://github.com/tommy0103/blackhole.git
为什么敢只留一行 git clone?因为仓库根目录里有一份专门写给 AI 读的 AGENTS.md。
在这份 AGENTS.md 里,我把整个项目的运维手册(Part 1: Operator Playbook)和架构部分(Part 2: Developer Playbook)写得清清楚楚——甚至明确列出了哪 5 条核心安全不变量(比如禁止透传全量 env、只读探针必须加 --network none、所有落盘必须原子重命名)是绝对不能被破坏的。
当你把仓库克隆下来,你只需要对你电脑上的 Agent 说一句:
「读一下这个仓库的 README.md 和 AGENTS.md,帮我把 Blackhole 配好,并给我当前的项目配好代理断流保护。」
你本地的 Agent 会自己先跑只读状态检查,自己拉起环境、构建镜像、绑定目录。
如果你在用 Linux,或者不想用 Colima 呢?
这也是我觉得「把最后一公里交给用户本地 Agent」最迷人的地方。
目前 Blackhole 默认锁定的宿主机运行时是 macOS + Colima。放在以前,如果一位重度 Linux 用户,或者习惯了 OrbStack / Podman 的开发者看到这个项目,第一反应一定是:「不支持我的环境,提个 Issue 等作者做跨平台兼容吧。」
但如果你打开 Blackhole 的代码库,你会发现:
- 85% 的核心组件(整个容器层)已经是 100% 纯粹的 OCI / Linux 标准件:
Dockerfile、docker-entrypoint.sh(自动对齐宿主机 UID/GID 的逻辑在原生 Linux Docker 下反而更加刚需)、会话钩子 blackhole-session-hook.sh、注册表查询器 blackhole-registry.mjs、跨进程信号器 blackhole-signal.mjs,在 Linux、OrbStack 或 Podman 下一个字节都不用改。
- 宿主机脚本
bin/blackhole 里的平台耦合点,被严格收敛在 4 个独立的函数漏斗里:
docker_for():只用了一行 DOCKER_HOST="unix://${COLIMA_DIR}/${profile}/docker.sock" docker "$@" 来寻址守护进程;
ensure_vm():虚拟机状态检查;
net / net-watch:通过 colima ssh 操作 iptables 与检测 utun 网卡;
clipboard:调用 macOS osascript 提取剪贴板图片。
因为架构边界是透明的,而且 AGENTS.md 里已经画好了完整的文件地图与安全契约,你完全不需要等我在云端写出一个兼容所有 Linux 发行版和所有容器运行时的臃肿版本。
如果你在用 Arch Linux + Wayland + 原生 Docker,或者在 macOS 上用 OrbStack,你只需要把 Blackhole 克隆下来,对你的本地 Agent 说:
「阅读 AGENTS.md 里的架构说明和核心不变量,帮我把 bin/blackhole 适配到我当前的 Linux / OrbStack 环境,把剪贴板同步换成 wl-paste,同时保留所有隔离属性。」
几分钟后,跑在你电脑上的,就是一个完全贴合你个人系统环境、同时严格遵循 Blackhole 隔离契约的专属版本。
邀请你和你的 Agent 一起共创 Blackhole
我一直觉得,AI Native 时代的开源社区,不应该再是「作者在上面吭哧吭哧写兼容补丁,用户在下面排队提功能许愿单」的单向关系了。
当每个人手里都有强大的 Agent,每个人都是最懂自己本地环境的架构师。我把 Blackhole 的底座打磨到了最克制的状态,现在想邀请你——以及你电脑里的 Agent——一起来共创这个项目:
- 用你的 Agent 探索属于你的「最后一公里」
无论你是把 Blackhole 移植到了原生 Linux、OrbStack、Lima、Podman,还是为你的特定语言栈打造了趁手的 .blackhole/Dockerfile 模板,或者针对 Clash / Sing-box / WireGuard 写出了更巧妙的 net-watch 探针,都欢迎让你的 Agent 整理成 PR 或 Recipes 分享出来。
- 一起来压测与打磨
AGENTS.md
在 AI 交付时代,AGENTS.md 的质量直接决定了用户本地 Agent 接手和改造项目的丝滑程度。如果你的 Agent 在阅读 AGENTS.md 操作或改造 Blackhole 时遇到了任何歧义,欢迎直接让你的 Agent 提交 PR 修正这份蓝图。
- 验证与加固黑洞边界
如果你发现了任何潜在的宿主机指纹泄露路径、环境变量渗透或者更优雅的内核级隔离方案,欢迎一起让这个黑洞的视界更纯粹。
你可以先打开我们的交互演示页,直观看看 Blackhole 是怎么在宿主机与容器之间过滤数据的:
不需要复杂的安装指南,复制那一行 git clone,剩下的交给你的 Agent 就好。期待看到你和你的 Agent 拼出的 Blackhole。
ESSAY // 01
·
AI-NATIVE SOFTWARE DELIVERY
One git clone: Leaving the Last Mile to Your Agent
I recently read an essay by Steven Lynn about a multiplication problem that has haunted software engineering for decades:
Take a handful of operating systems and runtime environments, and multiply them by users with completely different habits — some on macOS, some on Arch Linux, some routing traffic through Surge TUN, others using Clash HTTP proxies, some building Rust toolchains, others needing cross-terminal clipboard sync. Once those two variables multiply, they fracture into thousands of distinct edge-case requirements.
Historically, open-source maintainers had only two choices: either stuff every cross-platform compatibility branch, config flag, and edge case into the codebase until it becomes a bloated monolith, or serve only the lowest common denominator and leave anyone with a slightly non-standard setup waiting in the issue tracker.
Today, however, a new foundational assumption holds true: almost every developer has a capable coding Agent living right on their machine. When the user's terminal can understand code, inspect local environment quirks, and adapt software in place, the finish line of software delivery changes: maintainers no longer need to pre-solve every permutation in the cloud. Instead, we should deliver deterministic, atomic standard parts with a machine-readable blueprint — and leave the last mile to the user's local Agent.
That exact philosophy shaped every design decision in Blackhole.
Why Build Blackhole?
Anyone who uses Claude Code seriously knows the tension: you want to give it full autonomy (even --dangerously-skip-permissions) so it can run tests, install packages, and refactor unimpeded; yet running it bare on your host — or inside a naive Docker container with broad mounts — exposes your entire machine:
- Your
$HOME directory, ~/.ssh, ~/.gitconfig, and cloud credentials;
- Host environment variables leaking hardware UUIDs, locale, timezone, and account identity;
- Silent direct-connection leaks the moment a local proxy crashes or restarts.
I wanted an isolation boundary that behaves like a black hole:
- Zero Host Pollution, Zero Fingerprint: Neither
@anthropic-ai/claude-code nor Node.js is installed on your host. Hardware identifiers, network interfaces, and home directories are severed at the event horizon.
- High-Velocity Workspace Slingshot: Only your current project directory (
$PWD) and temporary clipboard staging ($TMPDIR) cross into the container over Apple Virtualization (vz) + virtiofs, sustaining 3.2 GB/s reads and 33.9 ms metadata traversal across 1,000 files.
- Fail-Close Network Airgap: Enforced directly on the VM kernel's
iptables DOCKER-USER chain. If your proxy drops or the watchdog heartbeat ages out, container egress locks shut immediately.
Building Atomic Standard Parts Instead of a Black Box
Built the traditional way, a tool like this would become a heavy Electron GUI or a sprawling YAML engine. Instead, Blackhole follows three rules of atomic standard parts:
1. Lock Down the Hard Architectural Trade-Offs
- The base stack is pinned to
vz + virtiofs;
- On container startup,
docker-entrypoint.sh inspects the host UID/GID of /workspace and aligns the container node user via gosu, preventing root-owned files on the host;
- Every state file, registry update, exported transcript, and cross-agent signal uses same-directory temporary files + atomic
mv.
2. Decompose Advanced Capabilities into Orthogonal Primitives
- Per-client or per-project isolation? Run
blackhole bind <profile> <dir> to bind a directory tree to a dedicated VM profile and credential volume.
- Project-specific Linux packages like
cargo or ffmpeg? Drop a two-line .blackhole/Dockerfile extending blackhole-claude:latest into your project. Blackhole builds a derived image hashed to that directory without polluting the base image.
- Host-to-container agent coordination? Use
blackhole signal for atomic file-based signaling.
- Session discovery, live backup, or migration? Compose
blackhole sessions, export-watch, and resume.
3. Make the Engineering Blueprint Readable by Agents
When designing the landing page, I deleted the multi-step installation tutorial and left a single line:
git clone https://github.com/tommy0103/blackhole.git
Why? Because the repository root ships with a comprehensive AGENTS.md divided into Part 1: Operator Playbook and Part 2: Developer Playbook — complete with an architecture file map and 5 non-negotiable security invariants.
Once cloned, you simply tell your local Agent:
"Read README.md and AGENTS.md in this repo, set up Blackhole for my machine, and configure fail-close proxy protection for my current project."
What If You Use Linux, or Prefer OrbStack / Podman Over Colima?
This is where handing the last mile to the user's local Agent truly shines.
Out of the box, Blackhole targets macOS + Colima. In the old open-source model, a Linux or OrbStack user would file an issue and wait months for upstream cross-platform support. But if you inspect Blackhole's codebase:
- 85% of the project (the entire container layer) is already 100% pure OCI / Linux standard parts:
Dockerfile, docker-entrypoint.sh (whose dynamic UID/GID matching is even more vital on native Linux Docker), blackhole-session-hook.sh, blackhole-registry.mjs, and blackhole-signal.mjs require zero changes on Linux, OrbStack, or Podman.
- Host coupling inside
bin/blackhole is isolated to 4 small funnel functions:
docker_for(): a single DOCKER_HOST wrapper;
ensure_vm(): VM readiness check;
net / net-watch: iptables rules and utun interface checks;
clipboard: macOS osascript image extraction.
If you run Arch Linux + Wayland + native Docker, or OrbStack on macOS, just clone the repo and tell your Agent:
"Read the architecture map and core invariants in AGENTS.md, adapt bin/blackhole to my native Linux / OrbStack runtime, and swap clipboard syncing to wl-paste while preserving all isolation invariants."
Co-Create Blackhole With Your Agent
Open-source in the AI-native era no longer needs to be a one-way queue of feature requests. You — and your local Agent — are invited to co-create Blackhole:
- Explore Your Own Last Mile: Port Blackhole to native Linux, OrbStack, Lima, or Podman; craft language-specific
.blackhole/Dockerfile recipes; or build custom net-watch probes for Clash, Sing-box, or WireGuard, and have your Agent open a PR.
- Stress-Test and Refine
AGENTS.md: If your Agent hits any ambiguity while operating or modifying Blackhole, have it submit a PR to sharpen the blueprint.
- Harden the Event Horizon: Help audit and strengthen the isolation boundary against any subtle host fingerprint or environment leakage.