PRs welcome. This doc covers local development, layout, and the test suite.
app.rb Sinatra app + endpoints
bin/install One-shot installer (clone, setup-token, compose up)
lib/prompt_extractor.rb Anthropic/OpenAI request → (prompt, system) extraction
lib/token_manager.rb OAuth access + refresh token lifecycle
lib/cli_dispatcher.rb Subprocess spawn, concurrency limiter, timeout
lib/direct_dispatcher.rb Opt-in direct API client (experimental)
test/ Minitest suite (see Testing)
Dockerfile node:22-slim + Ruby + Claude Code CLI + Bundler
docker-compose.yml ./data volume for token state
Requires Ruby 3.1+ and the claude CLI on PATH:
bundle install
CLAUDE_OAUTH_TOKEN=... \
CLAUDE_OAUTH_REFRESH_TOKEN=... \
TOKEN_STATE_FILE=./token_state.json \
CLI_WORKDIR=./workdir \
bundle exec ruby app.rbSee CONFIGURATION.md for all available variables.
bundle install
bin/test # full suite (~2s)
bin/test test/endpoints_test.rb # one file
SKIP_INTEGRATION=1 bin/test # skip anything that spawns the real Claude CLIThe suite has two kinds of tests:
- Unit —
prompt_extractor_test.rb,token_manager_test.rb,cli_dispatcher_test.rb,endpoints_test.rb. Pure Ruby. No subprocess, no network. The endpoint tests stub$dispatcher.callwith canned responses. - Integration —
integration_test.rb. Starts aMockAnthropicWEBrick server on a random port, exportsANTHROPIC_BASE_URLto point at it, and makes real HTTP requests through Sinatra. Theclaude --printsubprocess actually spawns and talks to the mock — so the whole pipeline (HTTP in → prompt extraction → subprocess → response reshape → HTTP out) is exercised without credentials or network.
You can run the full test suite without a Claude subscription or login. You need the claude CLI installed (free download from Anthropic), but no account is required to run bin/test — the integration tests talk to a local mock server instead of the real Anthropic API. This is deliberate: the mock exists partly for test determinism and partly to lower the barrier to contribution.