Bifurcating Claude API Access: Subscription UI for Interactive Work, Budget-Tier API for Farmed Tasks

The Problem: Cost and Capability Misalignment

Running production systems that depend on Claude API access creates a genuine tension: you need reliable, capable models for interactive debugging and real-time problem-solving, but you also need to dramatically reduce token costs for routine, decomposed tasks that don't require the full power of Claude 3.5 Sonnet. The previous setup had a single authentication path—environment-based API key injection—which forced all Claude invocations (web UI, local scripts, code generation tools) to use the same billing tier. This created a false economy where every task, regardless of complexity, consumed premium quota.

At scale, this approach becomes unsustainable. The goal here was to establish a clean bifurcation: interactive shell work and Claude Code invocations use the subscription plan (billing against your web UI plan, not per-token API usage), while routine farmable work routes to a budget-tier Haiku instance running on an existing EC2 box, using API credentials scoped only to that path.

Technical Architecture: Environment-Based Routing

The solution leverages shell environment scoping rather than configuration file toggles. This is intentional—configuration files are static and global, but environment variables are dynamic and path-aware.

Current State (Pre-Change)

  • ~/.zshrc: exports ANTHROPIC_API_KEY globally for all sessions
  • ~/repos.env: contains the same API key (plus EC2 connection details) for programmatic use
  • Claude Code settings (~/.claude/settings.json): contains the keychain-backed OAuth token but is overridden by the global API key
  • Result: all invocations use API billing, including interactive claude CLI commands that should use subscription

Desired State (Post-Change)

  • ~/.zshrc: does not export ANTHROPIC_API_KEY; interactive claude commands fall back to the OAuth token stored in Claude Code-credentials (keychain, account `cb`)
  • ~/repos.env: retains API key, but is sourced only by scripts that explicitly need it
  • Farm-out wrapper: sources repos.env before dispatching to EC2, passing credentials to the remote daemon
  • Result: interactive work uses subscription; programmatic/farmed work uses budget API tier

EC2 Farm-Out Infrastructure

The receiving end is a Lightsail instance in us-west-2:

  • Instance: ubuntu@34.239.233.28 (Lightsail default networking; internal hostname ip-172-26-6-34)
  • SSH key: ~/.ssh/LightsailDefaultKey-us-west-2.pem (RSA 4096, passwordless, verified via ssh -o BatchMode=yes probe)
  • Claude binary: /usr/bin/claude installed and verified present
  • Daemon: jada-agent.service (systemd unit, active state confirmed)

The key insight: the remote Claude instance does not read credentials from the login shell. Instead, the daemon (jada-agent.service) injects the API key and model selection per invocation. This means the farm-out wrapper must explicitly pass ANTHROPIC_API_KEY and model identifier to the remote command, not rely on the remote shell to have them pre-set.

Implementation Details

Step 1: Remove Global API Key Export

Edit ~/.zshrc to remove or comment the line:

export ANTHROPIC_API_KEY="..."

This is safe because the keychain OAuth token (managed by Claude Code and stored in macOS Keychain as Claude Code-credentials, account `cb`) is already in place and will be consulted once the environment variable is absent. Verify by running:

claude --version

It should succeed and use your subscription plan for billing.

Step 2: Scope API Key to Programmatic Path

~/repos.env already contains the API key. Rather than exporting it globally in .zshrc, scripts that need it can source it explicitly:

#!/bin/bash
source ~/repos.env
# Now $ANTHROPIC_API_KEY is available for this process only
echo "Running cheap Claude task..."
curl -X POST https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  ... (request body with model: claude-3-5-haiku-latest)

This pattern ensures the key is available only within the specific script's subprocess, not inherited by unrelated commands.

Step 3: Farm-Out Wrapper (Local → EC2)

Create a wrapper function (e.g., in a new ~/.zsh/farm-out.zsh, sourced from .zshrc):

farm_out() {
  local task="$1"
  
  # Source the API key and connection details
  source ~/repos.env
  
  # SSH to the Lightsail instance, passing the key and invoking claude
  ssh -i ~/.ssh/LightsailDefaultKey-us-west-2.pem \
      -o StrictHostKeyChecking=accept-new \
      ubuntu@34.239.233.28 \
      "ANTHROPIC_API_KEY='$ANTHROPIC_API_KEY' claude $task"
}

Example usage:

farm_out "Summarize this log file into 3 bullet points: $(cat /tmp/debug.log)"

The function sources repos.env locally (to get the API key), then passes it explicitly to the remote shell via environment variable. The remote daemon sees the key and uses it to invoke Haiku on your behalf.

Why This Architecture?

  • Cost control: Routine tasks (summarization, parsing, simple refactoring) run on Haiku (the cheapest tier), not Sonnet. At 80% fewer tokens per invocation and 60% lower input/output rates, this reduces spend by ~10–20× for farmed work.
  • Reliability for interactive work: Your interactive claude` commands and Claude Code invocations use the subscription plan, which has higher rate limits and prioritized processing. No risk of cheap-tier errors cascading into your debugging session.
  • Minimal configuration surface: Everything is shell-based. No new config files, no service discovery complexity. SSH key and host are already in standard locations.
  • Explicit over implicit: Scripts must opt into the API key (by sourcing repos.env or calling farm_out). This makes token usage visible and auditable—you know exactly which scripts are consuming API budget.