From 2c078854ec180cda97f04154a1815fcbaaa7f796 Mon Sep 17 00:00:00 2001 From: octo-patch Date: Thu, 9 Jul 2026 07:47:19 +0000 Subject: [PATCH 1/2] feat: support Anthropic-compatible base URL override Allow Ralph users to point Claude Code at custom Anthropic-compatible endpoints while preserving environment-over-.ralphrc precedence. Co-Authored-By: Claude Opus 4.7 --- README.md | 3 +++ ralph_loop.sh | 8 ++++++ templates/ralphrc.template | 4 +++ tests/unit/test_cli_modern.bats | 45 ++++++++++++++++++++++++++++++++- 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f151eaac..0269d573 100644 --- a/README.md +++ b/README.md @@ -681,6 +681,9 @@ PROJECT_TYPE="typescript" CLAUDE_CODE_CMD="claude" # CLAUDE_CODE_CMD="npx @anthropic-ai/claude-code" # Alternative: use npx +# Optional Anthropic-compatible API base URL override +# CLAUDE_ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic/v1" + # Shell init file — source before running claude (useful for zsh/fish users # whose PATH or env vars are only set in their shell's init file) #RALPH_SHELL_INIT_FILE="~/.zshrc" diff --git a/ralph_loop.sh b/ralph_loop.sh index a7c2f1e0..260bdab2 100755 --- a/ralph_loop.sh +++ b/ralph_loop.sh @@ -78,6 +78,7 @@ _env_CLAUDE_CODE_CMD="${CLAUDE_CODE_CMD:-}" _env_CLAUDE_AUTO_UPDATE="${CLAUDE_AUTO_UPDATE:-}" _env_CLAUDE_MODEL="${CLAUDE_MODEL:-}" _env_CLAUDE_EFFORT="${CLAUDE_EFFORT:-}" +_env_CLAUDE_ANTHROPIC_BASE_URL="${CLAUDE_ANTHROPIC_BASE_URL:-}" _env_RALPH_SHELL_INIT_FILE="${RALPH_SHELL_INIT_FILE:-}" _env_ENABLE_NOTIFICATIONS="${ENABLE_NOTIFICATIONS:-}" _env_ENABLE_BACKUP="${ENABLE_BACKUP:-}" @@ -113,6 +114,7 @@ CLAUDE_AUTO_UPDATE="${CLAUDE_AUTO_UPDATE:-true}" # Auto-update Claude CLI at st CLAUDE_CODE_CMD="${CLAUDE_CODE_CMD:-claude}" # Claude Code CLI command (default: global install) CLAUDE_MODEL="${CLAUDE_MODEL:-}" # Model override (e.g. claude-sonnet-4-6); empty = CLI default CLAUDE_EFFORT="${CLAUDE_EFFORT:-}" # Effort level override (e.g. high, low); empty = CLI default +CLAUDE_ANTHROPIC_BASE_URL="${CLAUDE_ANTHROPIC_BASE_URL:-}" # Anthropic-compatible API base URL override; empty = CLI default RALPH_SHELL_INIT_FILE="${RALPH_SHELL_INIT_FILE:-}" # Shell init file to source before running claude (e.g. ~/.zshrc) DRY_RUN="${DRY_RUN:-false}" # Simulate loop without making actual Claude API calls ENABLE_NOTIFICATIONS="${ENABLE_NOTIFICATIONS:-false}" # Enable desktop notifications; set true or use --notify flag @@ -328,6 +330,7 @@ load_ralphrc() { [[ -n "$_env_CLAUDE_AUTO_UPDATE" ]] && CLAUDE_AUTO_UPDATE="$_env_CLAUDE_AUTO_UPDATE" [[ -n "$_env_CLAUDE_MODEL" ]] && CLAUDE_MODEL="$_env_CLAUDE_MODEL" [[ -n "$_env_CLAUDE_EFFORT" ]] && CLAUDE_EFFORT="$_env_CLAUDE_EFFORT" + [[ -n "$_env_CLAUDE_ANTHROPIC_BASE_URL" ]] && CLAUDE_ANTHROPIC_BASE_URL="$_env_CLAUDE_ANTHROPIC_BASE_URL" [[ -n "$_env_RALPH_SHELL_INIT_FILE" ]] && RALPH_SHELL_INIT_FILE="$_env_RALPH_SHELL_INIT_FILE" [[ -n "$_env_ENABLE_NOTIFICATIONS" ]] && ENABLE_NOTIFICATIONS="$_env_ENABLE_NOTIFICATIONS" [[ -n "$_env_ENABLE_BACKUP" ]] && ENABLE_BACKUP="$_env_ENABLE_BACKUP" @@ -1559,6 +1562,11 @@ build_claude_command() { CLAUDE_CMD_ARGS+=("--effort" "$CLAUDE_EFFORT") fi + # Add Anthropic-compatible API base URL override (for custom providers) + if [[ -n "${CLAUDE_ANTHROPIC_BASE_URL:-}" ]]; then + CLAUDE_CMD_ARGS+=("--anthropic-base-url" "$CLAUDE_ANTHROPIC_BASE_URL") + fi + # Add output format flag if [[ "$CLAUDE_OUTPUT_FORMAT" == "json" ]]; then CLAUDE_CMD_ARGS+=("--output-format" "json") diff --git a/templates/ralphrc.template b/templates/ralphrc.template index 9f1baed1..875016b3 100644 --- a/templates/ralphrc.template +++ b/templates/ralphrc.template @@ -103,6 +103,10 @@ CLAUDE_AUTO_UPDATE=true # Minimum Claude CLI version required CLAUDE_MIN_VERSION="2.0.76" +# Optional Anthropic-compatible API base URL override for custom providers +# Example: MiniMax Claude-compatible endpoint +# CLAUDE_ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic/v1" + # Enable verbose logging RALPH_VERBOSE=false diff --git a/tests/unit/test_cli_modern.bats b/tests/unit/test_cli_modern.bats index d3228a3e..a0029ee4 100644 --- a/tests/unit/test_cli_modern.bats +++ b/tests/unit/test_cli_modern.bats @@ -192,6 +192,7 @@ setup() { _env_CLAUDE_CODE_CMD="${CLAUDE_CODE_CMD:-}" _env_CLAUDE_MODEL="${CLAUDE_MODEL:-}" _env_CLAUDE_EFFORT="${CLAUDE_EFFORT:-}" + _env_CLAUDE_ANTHROPIC_BASE_URL="${CLAUDE_ANTHROPIC_BASE_URL:-}" _env_RALPH_SHELL_INIT_FILE="${RALPH_SHELL_INIT_FILE:-}" load_ralphrc() { @@ -202,6 +203,7 @@ setup() { [[ -n "$_env_CLAUDE_CODE_CMD" ]] && CLAUDE_CODE_CMD="$_env_CLAUDE_CODE_CMD" [[ -n "$_env_CLAUDE_MODEL" ]] && CLAUDE_MODEL="$_env_CLAUDE_MODEL" [[ -n "$_env_CLAUDE_EFFORT" ]] && CLAUDE_EFFORT="$_env_CLAUDE_EFFORT" + [[ -n "$_env_CLAUDE_ANTHROPIC_BASE_URL" ]] && CLAUDE_ANTHROPIC_BASE_URL="$_env_CLAUDE_ANTHROPIC_BASE_URL" [[ -n "$_env_RALPH_SHELL_INIT_FILE" ]] && RALPH_SHELL_INIT_FILE="$_env_RALPH_SHELL_INIT_FILE" RALPHRC_LOADED=true return 0 @@ -548,6 +550,11 @@ build_claude_command() { CLAUDE_CMD_ARGS+=("--effort" "$CLAUDE_EFFORT") fi + # Add Anthropic-compatible API base URL override + if [[ -n "${CLAUDE_ANTHROPIC_BASE_URL:-}" ]]; then + CLAUDE_CMD_ARGS+=("--anthropic-base-url" "$CLAUDE_ANTHROPIC_BASE_URL") + fi + # Add output format flag if [[ "$CLAUDE_OUTPUT_FORMAT" == "json" ]]; then CLAUDE_CMD_ARGS+=("--output-format" "json") @@ -1937,6 +1944,17 @@ EOF assert_equal "$CLAUDE_EFFORT" "high" } +@test "CLAUDE_ANTHROPIC_BASE_URL from .ralphrc is loaded correctly" { + cat > "$TEST_DIR/.ralphrc" << 'EOF' +CLAUDE_ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic/v1" +EOF + _env_CLAUDE_ANTHROPIC_BASE_URL="" + CLAUDE_ANTHROPIC_BASE_URL="" + + load_ralphrc + assert_equal "$CLAUDE_ANTHROPIC_BASE_URL" "https://api.minimax.io/anthropic/v1" +} + @test "CLAUDE_MODEL env var takes precedence over .ralphrc" { cat > "$TEST_DIR/.ralphrc" << 'EOF' CLAUDE_MODEL="claude-sonnet-4-6" @@ -1959,6 +1977,17 @@ EOF assert_equal "$CLAUDE_EFFORT" "high" } +@test "CLAUDE_ANTHROPIC_BASE_URL env var takes precedence over .ralphrc" { + cat > "$TEST_DIR/.ralphrc" << 'EOF' +CLAUDE_ANTHROPIC_BASE_URL="https://api.example.com/anthropic/v1" +EOF + _env_CLAUDE_ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic/v1" + CLAUDE_ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic/v1" + + load_ralphrc + assert_equal "$CLAUDE_ANTHROPIC_BASE_URL" "https://api.minimax.io/anthropic/v1" +} + @test "build_claude_command includes --model flag when CLAUDE_MODEL is set" { CLAUDE_MODEL="claude-sonnet-4-6" CLAUDE_EFFORT="" @@ -1981,15 +2010,29 @@ EOF [[ "${CLAUDE_CMD_ARGS[*]}" == *"high"* ]] } -@test "build_claude_command omits --model and --effort when not configured" { +@test "build_claude_command includes --anthropic-base-url flag when CLAUDE_ANTHROPIC_BASE_URL is set" { + CLAUDE_MODEL="" + CLAUDE_EFFORT="" + CLAUDE_ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic/v1" + echo "test prompt" > "$TEST_DIR/PROMPT.md" + + build_claude_command "$TEST_DIR/PROMPT.md" "" "" + + [[ "${CLAUDE_CMD_ARGS[*]}" == *"--anthropic-base-url"* ]] + [[ "${CLAUDE_CMD_ARGS[*]}" == *"https://api.minimax.io/anthropic/v1"* ]] +} + +@test "build_claude_command omits --model, --effort, and --anthropic-base-url when not configured" { CLAUDE_MODEL="" CLAUDE_EFFORT="" + CLAUDE_ANTHROPIC_BASE_URL="" echo "test prompt" > "$TEST_DIR/PROMPT.md" build_claude_command "$TEST_DIR/PROMPT.md" "" "" [[ "${CLAUDE_CMD_ARGS[*]}" != *"--model"* ]] [[ "${CLAUDE_CMD_ARGS[*]}" != *"--effort"* ]] + [[ "${CLAUDE_CMD_ARGS[*]}" != *"--anthropic-base-url"* ]] } # ============================================================================== From 5a33fa7fd4bf481d6527675120e9563859a1a6f3 Mon Sep 17 00:00:00 2001 From: octo-patch <266937838+octo-patch@users.noreply.github.com> Date: Sun, 12 Jul 2026 17:08:17 +0800 Subject: [PATCH 2/2] fix: correct MiniMax Anthropic base URL --- README.md | 2 +- templates/ralphrc.template | 2 +- tests/unit/test_cli_modern.bats | 16 ++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 0269d573..862ff919 100644 --- a/README.md +++ b/README.md @@ -682,7 +682,7 @@ CLAUDE_CODE_CMD="claude" # CLAUDE_CODE_CMD="npx @anthropic-ai/claude-code" # Alternative: use npx # Optional Anthropic-compatible API base URL override -# CLAUDE_ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic/v1" +# CLAUDE_ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic" # Shell init file — source before running claude (useful for zsh/fish users # whose PATH or env vars are only set in their shell's init file) diff --git a/templates/ralphrc.template b/templates/ralphrc.template index 875016b3..baa66155 100644 --- a/templates/ralphrc.template +++ b/templates/ralphrc.template @@ -105,7 +105,7 @@ CLAUDE_MIN_VERSION="2.0.76" # Optional Anthropic-compatible API base URL override for custom providers # Example: MiniMax Claude-compatible endpoint -# CLAUDE_ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic/v1" +# CLAUDE_ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic" # Enable verbose logging RALPH_VERBOSE=false diff --git a/tests/unit/test_cli_modern.bats b/tests/unit/test_cli_modern.bats index a0029ee4..05fbeb63 100644 --- a/tests/unit/test_cli_modern.bats +++ b/tests/unit/test_cli_modern.bats @@ -1946,13 +1946,13 @@ EOF @test "CLAUDE_ANTHROPIC_BASE_URL from .ralphrc is loaded correctly" { cat > "$TEST_DIR/.ralphrc" << 'EOF' -CLAUDE_ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic/v1" +CLAUDE_ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic" EOF _env_CLAUDE_ANTHROPIC_BASE_URL="" CLAUDE_ANTHROPIC_BASE_URL="" load_ralphrc - assert_equal "$CLAUDE_ANTHROPIC_BASE_URL" "https://api.minimax.io/anthropic/v1" + assert_equal "$CLAUDE_ANTHROPIC_BASE_URL" "https://api.minimax.io/anthropic" } @test "CLAUDE_MODEL env var takes precedence over .ralphrc" { @@ -1979,13 +1979,13 @@ EOF @test "CLAUDE_ANTHROPIC_BASE_URL env var takes precedence over .ralphrc" { cat > "$TEST_DIR/.ralphrc" << 'EOF' -CLAUDE_ANTHROPIC_BASE_URL="https://api.example.com/anthropic/v1" +CLAUDE_ANTHROPIC_BASE_URL="https://api.example.com/anthropic" EOF - _env_CLAUDE_ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic/v1" - CLAUDE_ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic/v1" + _env_CLAUDE_ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic" + CLAUDE_ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic" load_ralphrc - assert_equal "$CLAUDE_ANTHROPIC_BASE_URL" "https://api.minimax.io/anthropic/v1" + assert_equal "$CLAUDE_ANTHROPIC_BASE_URL" "https://api.minimax.io/anthropic" } @test "build_claude_command includes --model flag when CLAUDE_MODEL is set" { @@ -2013,13 +2013,13 @@ EOF @test "build_claude_command includes --anthropic-base-url flag when CLAUDE_ANTHROPIC_BASE_URL is set" { CLAUDE_MODEL="" CLAUDE_EFFORT="" - CLAUDE_ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic/v1" + CLAUDE_ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic" echo "test prompt" > "$TEST_DIR/PROMPT.md" build_claude_command "$TEST_DIR/PROMPT.md" "" "" [[ "${CLAUDE_CMD_ARGS[*]}" == *"--anthropic-base-url"* ]] - [[ "${CLAUDE_CMD_ARGS[*]}" == *"https://api.minimax.io/anthropic/v1"* ]] + [[ "${CLAUDE_CMD_ARGS[*]}" == *"https://api.minimax.io/anthropic"* ]] } @test "build_claude_command omits --model, --effort, and --anthropic-base-url when not configured" {