Hacker News AI · 10/20/2026, 23:00:34
SIwithin Launches: Run Claude Code Unattended in a Sandboxed Budget Fence
Open-source tool SIwithin enables unattended execution of Claude Code or OpenAI Codex within strict file-system fences and dollar budgets. By intercepting API calls via a local proxy to enforce cost caps and generating single audit records per run, it addresses critical safety and budget control issues for autonomous agents.
SOURCE COVERAGEFull Original Report
Contents4 sections
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)