Bifurcating Claude API Consumption: Subscription UI for Interactive Work, Cheap API for Farmed Tasks

The Problem

Running multiple Claude workflows—interactive development via claude.ai, programmatic API calls for CI/CD and tooling, and experimental batch work—creates a credential management nightmare. More critically, it creates a cost nightmare. When you're spending $1,500/month on Claude API tokens but need to cut that by 90%, you can't afford to run every workload at the same tier.

The conflict: your shell had ANTHROPIC_API_KEY globally exported, which meant claude command invocations (intended for the subscription web UI) were silently falling back to API key auth, burning tokens. Meanwhile, legitimate programmatic work needed the API key but couldn't distinguish between "use cheap Haiku for this atomized subtask" and "use the full model for this critical path."

The solution required surgical separation: keep the subscription token (OAuth via Claude Code credentials) active for interactive shell work, confine the API key to explicit farm-out paths, and route sufficiently-decomposed tasks to a cheaper inference tier running on an existing EC2 instance.

Authentication Architecture: The Current State

Before making changes, we mapped the actual auth mechanisms:

  • Claude Code credentials store: OAuth token persisted in ~/.claude/code-credentials (macOS Keychain integration, account `cb`). This is already present and unused in your shell environment.
  • API key location: ~/projects/repos.env, exported globally in ~/.zshrc via source ~/projects/repos.env.
  • Claude CLI precedence: When ANTHROPIC_API_KEY is in the environment, the claude command uses API key auth exclusively, bypassing the stored OAuth token.
  • EC2 farm-out box: Lightsail instance at 34.239.233.28 (Ubuntu, internal hostname ip-172-26-6-34), running jada-agent.service daemon. SSH auth via ~/.ssh/LightsailDefaultKey-us-west-2.pem, passwordless.

The jada-agent.service daemon accepts Claude API calls with model and key injected per-invocation, not baked into the login shell. This is critical: the farm-out wrapper must explicitly pass credentials.

The Fix: Three-Layer Shell Environment

Layer 1: Interactive Shell (No API Key)

Remove the global ANTHROPIC_API_KEY export from ~/.zshrc. The exact change:

# BEFORE (in ~/.zshrc)
source ~/projects/repos.env  # exports ANTHROPIC_API_KEY globally

# AFTER (in ~/.zshrc)
# Do not source repos.env globally. Load it explicitly where needed.

With ANTHROPIC_API_KEY absent from the interactive shell environment, invoking claude will fall back to the keychain OAuth token—the intended behavior for subscription-tier interactive work.

Layer 2: Programmatic Scripts (Scoped API Key)

For scripts that genuinely need the API key—CI/CD pipelines, automation, background jobs—they explicitly source ~/projects/repos.env in their execution context. This is your existing convention, now enforced by necessity:

#!/bin/bash
# Example: ci-integration.sh

source ~/projects/repos.env  # Loads ANTHROPIC_API_KEY locally only

# Now ANTHROPIC_API_KEY is available only within this script's subshell
claude API call here...

Scripts follow this pattern consistently. The API key is never ambient; it's explicitly loaded where it's consumed.

Layer 3: Farm-Out Wrapper (Cheap Tier on EC2)

For tasks that have been sufficiently decomposed into atomic pieces (unit tests, validation, synthesis of small documents, etc.), a wrapper function routes them to the cheaper Haiku tier running on the EC2 box:

#!/bin/bash
# Function to add to ~/.zshrc (after removing global repos.env)

claude-cheap() {
  # Route to EC2 farm-out box for cheap inference
  # Requires: SSH key at ~/.ssh/LightsailDefaultKey-us-west-2.pem
  # EC2 box runs jada-agent.service (daemon injecting API key per call)
  
  local prompt="$*"
  
  # SSH to Lightsail instance, invoke claude on the box with Haiku model
  ssh -i ~/.ssh/LightsailDefaultKey-us-west-2.pem \
      ubuntu@34.239.233.28 \
      "ANTHROPIC_MODEL=claude-3-5-haiku-20241022 \
       /usr/bin/claude '$prompt'"
}

# Usage example:
# claude-cheap "Lint this Python function and report issues"

Why this architecture? Once a problem is broken down (by you, or by the subscription tier), verification, formatting, and validation can run on cheaper inference without quality loss. The Haiku model handles well-scoped tasks effectively and costs roughly 1/20th of Claude 3.5 Sonnet.

Infrastructure Details

  • EC2 Instance: AWS Lightsail, Ubuntu 22.04 LTS, 34.239.233.28.
  • Service: jada-agent.service running as a systemd daemon. Status verified with ssh ubuntu@34.239.233.28 systemctl status jada-agent.service.
  • Claude binary: /usr/bin/claude present on the box. The daemon handles API key injection per-invocation (not stored in the box's shell environment).
  • SSH key: ~/.ssh/LightsailDefaultKey-us-west-2.pem (2048-bit RSA, Lightsail-generated). Passwordless auth verified via ssh -i with BatchMode yes.
  • Network: Lightsail firewall rules must allow inbound SSH on port 22 from your development machine's IP (or 0.0.0.0/0 if acceptable). Verify with aws lightsail get-instance-access-details --instance-name farm-out-box --region us-west-2.

Cost Impact

The target: reduce API spend from ~$1,500/month to $75–150/month.

  • Interactive work: Uses subscription tier (fixed $20/month). No token burn for claude shell invocations.
  • Critical programmatic work: Still uses API key with Sonnet tier where accuracy is essential. Estimated 20% of current API volume.
  • Decomposed/atomized tasks: Route to Haiku via farm-out wrapper. Estimated 80% of current API volume, now at 1/20th cost. Savings: ~$1,200/month.
  • EC2 Lightsail instance: ~$5/month for the small instance (minimal resource footprint for daemon).

Key Decisions & Rationale