Agents & Automation

shellroute run wraps any command with a proxy session. The session starts, your command runs with all HTTP traffic routed through the exit IP, and the session ends when the command exits. No interactive shell needed.

The core pattern

terminal
# Country as positional arg — simplest form
shellroute run US -- curl -s https://httpbin.org/ip

# Datacenter IP (cheaper, $1/GB instead of $3/GB)
shellroute run --iptype datacenter DE -- python check_api.py

# Target a specific city
shellroute run --country US --city "New York" -- node verify.js

# Keep same IP if connection drops (long tasks)
shellroute run --sticky GB -- python monitor.py

# Clean output for piping (no session summary)
shellroute run --no-stat JP -- curl -s https://ipinfo.io/ip
Key property: the wrapped command inherits proxy env vars automatically. curl, wget, Python requests, Node fetch, Go http.Client — all route through the exit. No code changes in the agent.

Authentication for agents

Three ways to authenticate agents and scripts:

Direct login (non-interactive)

Same OTP flow as shellroute login, but with flags instead of prompts. The agent requests the code, a human provides it, the agent verifies and stores the key.

direct login
# Step 1: agent requests code
shellroute login --email [email protected] --request-code

# Step 2: check email for the code

# Step 3: verify the code
shellroute login --email [email protected] --verify-code 847291

# Step 4: get the key for env var / CI secrets
shellroute reveal-key

Env var

Set once, all commands use it. Get the key with shellroute reveal-key from any logged-in machine.

env var
export SHELLROUTE_API_KEY=pk_29f6a...
shellroute run US -- python step1.py
shellroute run DE -- python step2.py

Inline flag

Per-invocation, nothing stored on disk.

inline
shellroute --api-key pk_29f6a... run US -- curl https://httpbin.org/ip

Why agents need scoped proxy access

Per-task isolation

Each shellroute run gets its own session and exit IP. Multiple agents run in parallel without interfering with each other or the host.

No system-wide changes

Only the wrapped command is proxied. The orchestrator, databases, APIs, and other processes keep their direct connections.

Automatic cleanup

Session ends when the command exits. Orphaned sessions are cleaned up after 5 minutes if the process crashes.

Kill switch

If the tunnel drops, requests fail (connection refused) instead of leaking to the host IP.

Examples

Browser automation (Playwright)

terminal
# Test from London, datacenter IP
shellroute run --country GB --city London --iptype datacenter -- \
  npx playwright test geo-check.spec.ts

Multi-country comparison

compare.sh
# Compare pricing from three countries, clean output
shellroute run --no-stat US -- python check_price.py --market us
shellroute run --no-stat DE -- python check_price.py --market de
shellroute run --no-stat JP -- python check_price.py --market jp

Long-running with sticky IP

terminal
# Keep same IP across reconnects for session consistency
shellroute run --sticky --country US --city "New York" -- \
  python long_running_monitor.py

Parallel agents

bash
shellroute run US -- python agent.py --region us &
shellroute run --iptype datacenter DE -- python agent.py --region de &
shellroute run --country JP --city Tokyo -- python agent.py --region jp &
wait

Pipe proxy output to local processing

bash
# Fetch through proxy, process locally
US_IP=$(shellroute run --no-stat US -- curl -s https://ipinfo.io/ip)
echo "US exit: $US_IP"

# Multi-step: proxy → direct → proxy
shellroute run US -- python fetch_data.py
python process_locally.py           # no proxy
shellroute run DE -- python upload_results.py

Python integration

Call shellroute run as a subprocess. The agent code doesn't need to know about proxies.

orchestrator.py
import subprocess

def run_proxied(country, cmd, city=None, iptype=None):
    args = ["shellroute", "run", "--no-stat"]
    if city:
        args += ["--city", city]
    if iptype:
        args += ["--iptype", iptype]
    args += [country, "--"] + cmd
    return subprocess.run(args, capture_output=True, text=True)

# Residential from New York
r = run_proxied("US", ["curl", "-s", "https://httpbin.org/ip"], city="NYC")

# Datacenter from Germany
r = run_proxied("DE", ["python", "check.py"], iptype="datacenter")

CI/CD pipelines

shellroute needs one environment variable: SHELLROUTE_API_KEY. Get the key from any machine where you've logged in with shellroute reveal-key, then add it as a secret in your CI provider.

GitHub Actions

github-actions.yml
env:
  SHELLROUTE_API_KEY: ${{ secrets.SHELLROUTE_API_KEY }}

steps:
  - run: npm install -g shellroute

  - name: Geo test from US (residential)
    run: shellroute run US -- npm run test:geo

  - name: Geo test from DE (datacenter)
    run: shellroute run --iptype datacenter DE -- npm run test:geo

  - name: Capture US IP
    run: |
      echo "US_IP=$(shellroute run --no-stat US -- curl -s https://ipinfo.io/ip)" >> $GITHUB_ENV

Any CI (GitLab, CircleCI, etc.)

shell
# Set in your CI's secret/env config, then:
npm install -g shellroute  # or: brew install shellroute/tap/shellroute
shellroute run US -- your-test-command

# Or pass the key inline (no env var needed)
shellroute --api-key $SHELLROUTE_API_KEY run US -- your-test-command

Next steps