# Updating Openrouter Free Models

> Use when needing to fetch, test, and update OpenRouter free model lists in Claude Code or OpenClaw configurations

- Skill: `lord1egypt/updating-openrouter-free-models` (Agent Skill)
- Install (CLI): `npx skillmds@latest add lord1egypt/updating-openrouter-free-models`
- Raw SKILL.md: https://api.skillmd.com/api/skills/lord1egypt/updating-openrouter-free-models/raw
- Safety review: pending (external: skill-scanner PASS, skillspector CAUTION)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: Lord1Egypt (https://skillmd.com/u/lord1egypt)
- Updated: 2026-09-08
- Page: https://skillmd.com/skills/lord1egypt/updating-openrouter-free-models

---


# Updating OpenRouter Free Models

## Overview
A systematic, test-driven process for updating OpenRouter free models that ensures only verified working models are added to configuration files. Combines automated fetching, batch testing, and multi-config synchronization.

## When to Use

**Use when:**
- Adding new OpenRouter free models to configurations
- Syncing model lists between Claude Code and OpenClaw
- need to verify model availability before adding
- Managing model fallbacks and availability allowlists

**Do NOT use for:**
- Single model additions (manual edit is faster)
- Paid model configurations (different testing criteria)
- Other provider types (Anthropic, OpenAI direct)

## Core Workflow

```mermaid
graph LR
    A[Fetch models from OpenRouter API] --> B[Batch test each model];
    B --> C{Pass test?};
    C -->|Yes| D[Add to verified list];
    C -->|No| E[Skip + log reason];
    D --> F[Update configurations];
    F --> G[Validate JSON syntax];
    G --> H[Self-test updated config];
    H --> I[Restart OpenClaw service];
```

## Quick Reference

| Step | Command | Purpose |
|------|---------|---------|
| 1 | `python3 fetch_models.py` | Fetch all free models |
| 2 | `python3 test_models.py` | Batch test availability |
| 3 | `node apply_updates_openclaw.js` | Update OpenClaw config |
| 4 | `./restart_openclaw.sh` | Restart service |
| 5 | Validate JSON | Prevent syntax errors |

## Implementation

### Step 1: Fetch Free Models from OpenRouter API

```bash
# Use the provided fetcher script which implements comprehensive free model detection
python3 fetch_models.py
```

**Free Model Detection:** The script identifies free models by:
- ID containing `:free` suffix, **OR**
- All pricing fields (`prompt`, `completion`, `request`) equaling `0` or `"0"`

This captures models like `openrouter/hunter-alpha` that have zero pricing but lack the `:free` tag.

### Step 2: Batch Test Availability

```bash
# Test each fetched model via API
python3 test_models.py
```

The script will:
- Read models from `/tmp/free_models.txt`
- Test each with a short API call
- Save verified models to `/tmp/verified_models.txt`
- Save failed models to `/tmp/failed_models.txt` with error reasons

**Note:** The script supports multiple token sources:
- `ANTHROPIC_AUTH_TOKEN` (Claude Code compatibility)
- `OPENROUTER_API_KEY` (OpenRouter direct)
- OpenClaw config (`~/.openclaw/openclaw.json` → `models.providers.openrouter.apiKey`)

### Step 3: Update Claude Code Settings

```bash
# Generate JSON array for availableModels
cat > /tmp/availableModels.json << 'EOF'
$(python3 -c "
models = open('/tmp/verified_models.txt').read().strip().split('\n')
print('  \"availableModels\": [')
for i, m in enumerate(models):
    comma = ',' if i < len(models)-1 else ''
    print(f'    \"{m}\"{comma}')
print('  ],')
")
```

Then manually or programmatically insert into `~/.claude/settings.json`.

### Step 4: Update OpenClaw Configuration

```python
import json
from pathlib import Path

# Read existing config
with open(Path.home() / '.openclaw' / 'openclaw.json', 'r') as f:
    config = json.load(f)

# Update provider models
verified = open('/tmp/verified_models.txt').read().strip().split('\n')
provider_models = []
fallbacks = []

for i, model_id in enumerate(verified):
    provider_models.append({
        "id": model_id,
        "name": model_id.split('/')[-1],
        "api": "openai-completions"
    })
    if i > 0:  # Skip primary (stepfun) from fallbacks
        fallbacks.append(f"openrouter/{model_id}")

config['models']['providers']['openrouter']['models'] = provider_models
config['agents']['defaults']['model']['fallbacks'] = fallbacks

# Add to agents.defaults.models
for model_id in verified:
    key = f"openrouter/{model_id}"
    if key not in config['agents']['defaults']['models']:
        config['agents']['defaults']['models'][key] = {}

# Save
with open(Path.home() / '.openclaw' / 'openclaw.json', 'w') as f:
    json.dump(config, f, indent=2)

print(f"Updated OpenClaw config with {len(verified)} models")
```

### Step 5: Validate and Self-Test

```bash
# Validate JSON syntax
python3 -m json.tool ~/.claude/settings.json > /dev/null && echo "✓ Claude settings valid"
python3 -m json.tool ~/.openclaw/openclaw.json > /dev/null && echo "✓ OpenClaw config valid"

# Self-test: verify models field exists and is array
python3 -c "
import json
with open('~/.claude/settings.json') as f:
    cfg = json.load(f)
    assert 'availableModels' in cfg
    assert isinstance(cfg['availableModels'], list)
    print(f'✅ Claude: {len(cfg[\"availableModels\"])} models available')
"
```

## Common Pitfalls

| Pitfall | Symptom | Fix |
|---------|---------|-----|
| Missing rate limiting | API errors/timeouts | Add `time.sleep(0.5)` between tests |
| Not filtering duplicates | Same model twice | Use `set()` on results |
| Forgetting fallbacks array | Only primary works | Update both `models` and `fallbacks` |
| Invalid JSON after edit | Config won't load | Run `python3 -m json.tool` to validate |
| Skipping self-test | Broken config deployed | Always run validation commands |

## Real-World Example

**Before:** Manually copying models from website → errors, outdated models, missing configs

**After:** Automated fetch + test → only verified models, synchronized configs, repeatable process

## Anti-Patterns

### ❌ Add All Models Without Testing
```python
# BAD: Just grab list and add everything
models = fetch_all()
# Problem: Some models may be rate-limited, deprecated, or region-blocked
```

### ❌ One Configuration Only
```python
# BAD: Only update Claude settings, forget OpenClaw
update_claude_settings(verified_models)
# Problem: OpenClaw still has old list → inconsistent behavior
```

### ❌ No Self-Test
```python
# BAD: Write file and assume it's correct
with open('settings.json', 'w') as f:
    json.dump(config, f)
# Problem: Syntax error breaks entire application
```

## Testing Checklist

- [ ] Fetch produces non-empty model list
- [ ] All verified models pass API test in batch
- [ ] Claude settings JSON is valid
- [ ] OpenClaw JSON is valid
- [ ] `availableModels` exists and is array
- [ ] OpenClaw `models.providers.openrouter.models` updated
- [ ] OpenClaw `agents.defaults.model.fallbacks` includes all except primary
- [ ] OpenClaw `agents.defaults.models` has entries for all
- [ ] Actual API call works with at least one model from new list

## Maintenance

**When to rerun this skill:**
- Monthly (OpenRouter adds/removes free models regularly)
- After API error indicates specific model unavailable
- Adding new configuration targets (e.g., new tool that uses OpenRouter)

**What to update if API changes:**
- Model filter logic (free detection criteria may change - see `is_free_model()` in `fetch_models.py`)
- Test request format (API endpoint may version)
- Rate limits (adjust sleep duration)

## OpenClaw-Specific Notes

### OpenClaw Scripts

This skill includes OpenClaw-specific scripts in the workspace:

| Script | Purpose |
|--------|---------|
| `test_models.py` | Batch test models (same as Claude Code version) |
| `apply_updates_openclaw.js` | Node.js version for OpenClaw config updates |
| `restart_openclaw.sh` | Restart OpenClaw gateway service after update |

### Full OpenClaw Workflow

```bash
# 1. Fetch free models
python3 fetch_models.py

# 2. Test availability
python3 test_models.py

# 3. Apply to OpenClaw config
node apply_updates_openclaw.js

# 4. Restart OpenClaw service (required for config changes)
./restart_openclaw.sh

# 5. Verify
openclaw --version  # or test with a model
```

**Why restart?** OpenClaw loads configuration at startup. Changes to `openclaw.json` require restart to take effect.

### Restart Methods

`restart_openclaw.sh` tries multiple methods:
1. `launchctl` (if running as macOS service)
2. `pkill` + `nohup` (manual restart)
3. Reports errors if both fail

Logs: `/tmp/openclaw-gateway.log`

### Testing After Update

```bash
# Check gateway is running
pgrep -f "openclaw.*gateway"

# Test model fallback (send a test message via your OpenClaw channel)
# If primary fails, it should automatically fall back to next model
```

## See Also

- **OpenRouter API docs**: https://openrouter.ai/docs
- **Claude Code settings schema**: `~/.claude/settings.json` structure
- **OpenClaw configuration**: `~/.openclaw/openclaw.json` model sections
- **OpenClaw gateway docs**: `openclaw gateway --help`


