Hacker News AI · 2026/10/20 23:00:34
SIwithin 发布:在沙箱与预算限制下无人值守运行 Claude Code
开源工具 SIwithin 允许用户在严格的文件系统隔离和美元预算上限下,无人值守地运行 Claude Code 或 OpenAI Codex。它通过本地代理拦截 API 请求以强制实施成本控制,并确保每次运行仅留下单一审计记录,解决了 Agent 自主执行时的安全与成本失控痛点。
报道全文原始报道全文
本文目录4 个章节
SIwithin
SIwithin runs an agent CLI unattended on a brief, inside a fence around the folders you give it and under a dollar budget, and leaves one record per run. It keeps three promises with a tool and not with hope:
- The run touches only the folders it was given. Your home folder is refused, for reading and writing, and the run's folders are allowed back.
- The run cannot spend more than the dollars it was given. A budget per run, a cap across all runs, a timer on every run, and, for the Claude adapter, a loopback proxy that is the one door to the API: the run holds a per-run token and not your key, and every request it makes, however it makes it, is metered there and refused past the budget. Where a CLI cannot be stopped mid-run, the tool refuses it unless you say you accept that (see "The ledger" and "The Codex adapter").
- Every run leaves one line saying what it cost and whether it was done.
Works with the Claude Code and OpenAI Codex command-line tools. SIwithin is an independent project; it is not made, endorsed or sponsored by Anthropic or OpenAI. Claude, Claude Code, OpenAI and Codex are the names of their owners, used here only to say which programs SIwithin can drive. You remain bound by each vendor's terms of service and usage policies when you use their CLIs through SIwithin; SIwithin changes none of them.
SIwithin runs on macOS only. On Linux and Windows it refuses to run, in one line, rather than run without a fence.
Install
SIwithin is one file, Python 3.10 or newer, standard library only. It makes no network calls of its own and sends no telemetry; the proxy it starts for a run listens on a loopback port and talks only to the API host you configure.
git clone <this repository> && cd siwithin
python3 siwithin.py --version
# optional: put it on your PATH
install -m 755 siwithin.py ~/.local/bin/siwithinYou also need the CLI you want to drive, installed and on your PATH, and an API key for it (see "Auth").
The smoke test (python3 tests/smoke.py) passes on the Python it was written on, 3.9.6. 3.10 is the supported floor and the code avoids newer syntax, but it has not been run on 3.10 or newer.
Quick start, Claude Code
mkdir -p ~/.config/siwithin && echo 20 > ~/.config/siwithin/cap # all runs together may spend $20
export ANTHROPIC_API_KEY=... # see "Auth"; the tool reads it once, outside the fence, and the run gets a per-run token in its place
python3 siwithin.py --dir ~/work/proj --model sonnet --dry-run < brief.md # print everything, run nothing
python3 siwithin.py --dir ~/work/proj --model sonnet --budget 2 \
--done "ALL TESTS PASS" --out notes.md < brief.md--dir is the run's folder: the CLI works in it and may write in it (--readonly makes it read-only). --read <folder> adds folders the run may read. --model takes an id or an alias (haiku, sonnet, opus).
Quick start, Codex
mkdir -p ~/.config/siwithin && echo 20 > ~/.config/siwithin/cap
export CODEX_API_KEY=...
python3 siwithin.py --adapter codex --model gpt-5.3-codex --soft-budget --network open --dir ~/work/proj --dry-run < brief.md
python3 siwithin.py --adapter codex --model gpt-5.3-codex --soft-budget --network open --budget 2 --dir ~/work/proj < brief.mdTwo flags are required for this adapter, for reasons in "The Codex adapter": --model (the CLI reports tokens and no cost, so a run is priced by model id) and --soft-budget (the CLI reports usage only when a turn ends). This adapter was built from documentation and has not been run against a live CLI. It runs with auth = "env": the key is in the run's environment (see "Auth"), and since there is no proxy there is no port for the network wall to allow, so it needs --network open, or network = "open" under [fence] in config.toml; under the default the run is refused rather than run with no network (see "The fence").
Auth
SIwithin never parses, stores, prints or logs a key, and writes one into no file, log line or error message. How the key reaches the API depends on the adapter's auth field.
The Claude adapter, auth = "proxy" (the default from 0.3.0). Before launch, outside the fence, the runner reads the key once: from ANTHROPIC_API_KEY in its own environment, or else from the first line printed by [auth] key_command in config.toml, a command of yours that prints the key (a keychain lookup, for example). It keeps the key and starts a small HTTP server on a loopback port of its own, standard library only. The run's environment holds ANTHROPIC_API_KEY=siwithin-<32 characters>, a token new for every run and worth nothing elsewhere, and ANTHROPIC_BASE_URL=http://127.0.0.1:<port>. Every request the run makes, by the CLI, by hand or by a second CLI it starts, passes that door: the proxy takes only the run's token (anything else gets 401 and goes nowhere), forwards only the paths on [auth] paths (/v1/messages and /v1/messages/count_tokens by default; any other path gets 403 and the real key is never attached), adds the real key, relays the response as it streams, and prices each /v1/messages response at the [prices] rates from its usage. Once the total reaches the budget every later /v1/messages request gets 402, the first refusal kills the run's processes as the streamed stop does, and the proxy keeps refusing until the runner exits. When the run ends the proxy is sealed, its log closed and its server shut, so the token is worth nothing. One line per request goes to proxy.jsonl in the run's folder (path, model, status, usage, cost, the running total, the client's port, why it was refused; never a body, a key or the token). A settings.json in the run's config directory that names apiKeyHelper is refused before launch, since the CLI would run the helper inside the fence where the run can read it: put the helper's command in [auth] key_command instead, which the runner runs outside the fence. --dry-run prints auth: proxy 127.0.0.1:<port> and starts nothing.
auth = "env" copies the key's variable into the run by name, as 0.2.1 did. It is the Codex adapter's only mode and an opt-in for the Claude adapter (the checks warn). In this mode the key is in the run's environment and inherited by every command the run starts, and the network wall cannot be raised, since there is no proxy port to allow: the run is refused under the default [fence] network = "proxy" and
(注:更多技术实现细节与完整 API 文档请查阅原项目 README)