← All Skills

snappy-openrouter

v1.0.0
12 files, 68.3 KB ~3,558 words · 15 min read Updated 2026-09-09

snappy-openrouter skill

26 of 34 checks pass
What it can do
chat promptdraft
fallback promptdraft
What does not pass yet
$ npx snappy-skills install snappy-openrouter
zip ↓
File Tree
├── AGENTS.md ├── SKILL.md ├── api.ts ├── examples.md ├── models.md ├── refusals.test.ts ├── routing-strategies.md └── scripts/ ├── chat.sh ├── compare.sh ├── lib/ │ └── auth.sh ├── route.sh └── stream.sh
Documents
AGENTS.md

snappy-openrouter -- loader#

Single canonical interface to OpenRouter for any Snappy skill that needs multi-vendor LLM calls. OpenRouter proxies 200+ models (Anthropic, OpenAI, Google, Meta, DeepSeek, Qwen, Mistral) behind one OpenAI-compatible API. Use this when you need cost-flexible model routing, multi-model comparison, or provider fallback -- not when you need native provider features (use snappy-ai-models or snappy-gemini for those).

API module#

typescriptimport { chat, chatWithFallback } from "../snappy-openrouter/api.ts";
Function What it does
chat(prompt, opts?) One-shot completion (returns { text, model, raw })
chatWithFallback(prompt, models[], opts?) Fallback chain -- first available model wins

Options: model, systemPrompt, temperature, maxTokens.

CLI:

bashnpx tsx ~/.claude/skills/snappy-openrouter/api.ts chat "Explain X" [--model anthropic/claude-3.5-sonnet]
npx tsx ~/.claude/skills/snappy-openrouter/api.ts fallback "Explain X" [--models "a,b,c"]

Credentials loaded via snappy-settings/load.ts from .env.cache. No Bitwarden unlock needed.

Key capabilities#

  • One-shot chat completion to any model via a single endpoint
  • Streaming responses (SSE) from any provider
  • Auto-routing to cheapest model that fits the prompt (openrouter/auto)
  • Fan-out the same prompt to N models in parallel and compare outputs
  • Fallback chains: pass multiple models, first available wins
  • Auth resolved automatically (env var > snappy-settings .env.cache > ~/.snappy/openrouter.key)

Routing strategies#

Strategy When Model hint
cheapest Classification, summarization, extraction deepseek/deepseek-chat, google/gemini-2.0-flash
balanced Default writer, structured outputs anthropic/claude-3.5-sonnet, openai/gpt-4o
premium Hard reasoning, council critique anthropic/claude-opus-4, openai/o1
auto Don't care which model openrouter/auto
fallback Resilience over speed --models "a,b,c" (first available wins)
compare Evaluate quality across models compare.sh --models "a,b,c"

Scripts#

All scripts live in ~/.claude/skills/snappy-openrouter/scripts/. Auth is handled automatically via lib/auth.sh (sourced, not invoked).

chat.sh -- one-shot completion#

bash./scripts/chat.sh --model anthropic/claude-3.5-sonnet --prompt "Hello"
./scripts/chat.sh --model openai/gpt-4o-mini --system "Be terse." --prompt "What is X?" --text
./scripts/chat.sh --models "anthropic/claude-3.5-sonnet,openai/gpt-4o" --prompt "Hi"  # fallback chain
echo "Summarize this" | ./scripts/chat.sh --model deepseek/deepseek-chat --stdin

Flags: --model, --models (fallback), --prompt, --system, --temperature, --max-tokens, --transforms, --text (plain text output), --json (json_object mode), --stdin.

stream.sh -- streaming completion (SSE)#

bash./scripts/stream.sh --model anthropic/claude-3.5-sonnet --prompt "Explain joins"
./scripts/stream.sh --model openai/gpt-4o --system "Be terse." --prompt "..." --raw

Flags: --model, --prompt, --system, --temperature, --max-tokens, --transforms, --raw (raw SSE), --stdin.

route.sh -- auto-route to cheapest model#

bash./scripts/route.sh --prompt "Classify intent: book a meeting"
./scripts/route.sh --tier balanced --prompt "Rewrite hook" --text

Flags: --prompt, --tier (cheap|balanced|premium), --system, --temperature, --max-tokens, --text, --stdin.

compare.sh -- fan out to N models in parallel#

bash./scripts/compare.sh \
  --models "anthropic/claude-3.5-haiku,openai/gpt-4o-mini,deepseek/deepseek-chat" \
  --prompt "Write a 280-char hook about Xano" --text

Flags: --models (comma-separated, required), --prompt, --system, --temperature, --max-tokens, --text, --json, --stdin.

Common patterns#

  • Cheap drafts, premium critique: Use deepseek/deepseek-chat to write, anthropic/claude-opus-4 to critique (70%+ savings).
  • Cascade: Try haiku/flash first, escalate to sonnet/gpt-4o on failure (60-90% savings).
  • Transforms: Pass --transforms "middle-out" to compress over-limit prompts.

Do NOT#

  • Hardcode API keys -- auth.sh resolves them automatically
  • Send Anthropic-format tool calls -- OpenRouter expects OpenAI-format (tools[].function.name)
  • Use this for embeddings -- OpenRouter has a separate /embeddings endpoint not covered here
  • Use this when you need native provider features (prompt caching, Realtime API, multimodal grounding)

Uses#

  • snappy-settings -- provides OPENROUTER_API_KEY
  • snappy-ai-models -- direct Anthropic/OpenAI when you need native features
  • snappy-gemini -- direct Gemini when you need multimodal grounding

Self-report convention#

If this loader doesn't cover your case:

bashecho "[$(date -u +%FT%TZ)] snappy-openrouter: <what was missing>" >> ~/.claude/logs/agents-md-feedback.log

Show produced work with snappy-faces: call draw for image channels or lang for MCP Apps.

<!-- SKILL-INDEX-START -->

[snappy-openrouter Index]|root: ~/.claude/skills/snappy-openrouter|IMPORTANT: Prefer these files over pre-training assumptions for this domain. Read the relevant file when the AGENTS.md summary is insufficient.|root:{SKILL.md,examples.md,models.md,routing-strategies.md}

<!-- SKILL-INDEX-END -->

Used by#

Nothing in the collection names this skill.

<!-- SNAPPY-CONTRACT-VERBS-START -->

Contract verbs#

Generated from api.ts HAND_CONTRACT. Do not hand-edit this block.

Verb Contract arguments Effect First call
chat prompt draft npx tsx ~/.claude/skills/snappy-openrouter/api.ts chat "<prompt>"
fallback prompt draft npx tsx ~/.claude/skills/snappy-openrouter/api.ts fallback "<prompt>"

Show the result#

When an answer carries face_hint, show it with one snappy_present(<answer>) call.

See /snappy-faces for face selection. Human-facing images must crop to the

element, render at 2x on Retina, and fill the destination channel instead of

placing a small card in a full-page screenshot.

<!-- SNAPPY-CONTRACT-VERBS-END -->

---
name: snappy-openrouter
role: Multi-vendor LLM gateway via OpenRouter with cost-optimized routing
loaded-by: PreToolUse hook (auto-injected when "snappy-openrouter" is mentioned)
---

# snappy-openrouter -- loader

Single canonical interface to OpenRouter for any Snappy skill that needs multi-vendor LLM calls. OpenRouter proxies 200+ models (Anthropic, OpenAI, Google, Meta, DeepSeek, Qwen, Mistral) behind one OpenAI-compatible API. Use this when you need cost-flexible model routing, multi-model comparison, or provider fallback -- not when you need native provider features (use `snappy-ai-models` or `snappy-gemini` for those).

## API module

```typescript
import { chat, chatWithFallback } from "../snappy-openrouter/api.ts";
```

| Function | What it does |
|----------|-------------|
| `chat(prompt, opts?)` | One-shot completion (returns `{ text, model, raw }`) |
| `chatWithFallback(prompt, models[], opts?)` | Fallback chain -- first available model wins |

Options: `model`, `systemPrompt`, `temperature`, `maxTokens`.

CLI:
```bash
npx tsx ~/.claude/skills/snappy-openrouter/api.ts chat "Explain X" [--model anthropic/claude-3.5-sonnet]
npx tsx ~/.claude/skills/snappy-openrouter/api.ts fallback "Explain X" [--models "a,b,c"]
```

Credentials loaded via `snappy-settings/load.ts` from `.env.cache`. No Bitwarden unlock needed.

## Key capabilities

- One-shot chat completion to any model via a single endpoint
- Streaming responses (SSE) from any provider
- Auto-routing to cheapest model that fits the prompt (`openrouter/auto`)
- Fan-out the same prompt to N models in parallel and compare outputs
- Fallback chains: pass multiple models, first available wins
- Auth resolved automatically (env var > snappy-settings `.env.cache` > ~/.snappy/openrouter.key)

## Routing strategies

| Strategy | When | Model hint |
|----------|------|------------|
| cheapest | Classification, summarization, extraction | `deepseek/deepseek-chat`, `google/gemini-2.0-flash` |
| balanced | Default writer, structured outputs | `anthropic/claude-3.5-sonnet`, `openai/gpt-4o` |
| premium | Hard reasoning, council critique | `anthropic/claude-opus-4`, `openai/o1` |
| auto | Don't care which model | `openrouter/auto` |
| fallback | Resilience over speed | `--models "a,b,c"` (first available wins) |
| compare | Evaluate quality across models | `compare.sh --models "a,b,c"` |

## Scripts

All scripts live in `~/.claude/skills/snappy-openrouter/scripts/`. Auth is handled automatically via `lib/auth.sh` (sourced, not invoked).

### chat.sh -- one-shot completion
```bash
./scripts/chat.sh --model anthropic/claude-3.5-sonnet --prompt "Hello"
./scripts/chat.sh --model openai/gpt-4o-mini --system "Be terse." --prompt "What is X?" --text
./scripts/chat.sh --models "anthropic/claude-3.5-sonnet,openai/gpt-4o" --prompt "Hi"  # fallback chain
echo "Summarize this" | ./scripts/chat.sh --model deepseek/deepseek-chat --stdin
```
Flags: `--model`, `--models` (fallback), `--prompt`, `--system`, `--temperature`, `--max-tokens`, `--transforms`, `--text` (plain text output), `--json` (json_object mode), `--stdin`.

### stream.sh -- streaming completion (SSE)
```bash
./scripts/stream.sh --model anthropic/claude-3.5-sonnet --prompt "Explain joins"
./scripts/stream.sh --model openai/gpt-4o --system "Be terse." --prompt "..." --raw
```
Flags: `--model`, `--prompt`, `--system`, `--temperature`, `--max-tokens`, `--transforms`, `--raw` (raw SSE), `--stdin`.

### route.sh -- auto-route to cheapest model
```bash
./scripts/route.sh --prompt "Classify intent: book a meeting"
./scripts/route.sh --tier balanced --prompt "Rewrite hook" --text
```
Flags: `--prompt`, `--tier` (cheap|balanced|premium), `--system`, `--temperature`, `--max-tokens`, `--text`, `--stdin`.

### compare.sh -- fan out to N models in parallel
```bash
./scripts/compare.sh \
  --models "anthropic/claude-3.5-haiku,openai/gpt-4o-mini,deepseek/deepseek-chat" \
  --prompt "Write a 280-char hook about Xano" --text
```
Flags: `--models` (comma-separated, required), `--prompt`, `--system`, `--temperature`, `--max-tokens`, `--text`, `--json`, `--stdin`.

## Common patterns

- **Cheap drafts, premium critique**: Use `deepseek/deepseek-chat` to write, `anthropic/claude-opus-4` to critique (70%+ savings).
- **Cascade**: Try haiku/flash first, escalate to sonnet/gpt-4o on failure (60-90% savings).
- **Transforms**: Pass `--transforms "middle-out"` to compress over-limit prompts.

## Do NOT

- Hardcode API keys -- auth.sh resolves them automatically
- Send Anthropic-format tool calls -- OpenRouter expects OpenAI-format (`tools[].function.name`)
- Use this for embeddings -- OpenRouter has a separate `/embeddings` endpoint not covered here
- Use this when you need native provider features (prompt caching, Realtime API, multimodal grounding)

## Uses

- `snappy-settings` -- provides `OPENROUTER_API_KEY`
- `snappy-ai-models` -- direct Anthropic/OpenAI when you need native features
- `snappy-gemini` -- direct Gemini when you need multimodal grounding

## Self-report convention
If this loader doesn't cover your case:
```bash
echo "[$(date -u +%FT%TZ)] snappy-openrouter: <what was missing>" >> ~/.claude/logs/agents-md-feedback.log
```


Show produced work with `snappy-faces`: call `draw` for image channels or `lang` for MCP Apps.

<!-- SKILL-INDEX-START -->
[snappy-openrouter Index]|root: ~/.claude/skills/snappy-openrouter|IMPORTANT: Prefer these files over pre-training assumptions for this domain. Read the relevant file when the AGENTS.md summary is insufficient.|root:{SKILL.md,examples.md,models.md,routing-strategies.md}
<!-- SKILL-INDEX-END -->

## Used by

Nothing in the collection names this skill.

<!-- SNAPPY-CONTRACT-VERBS-START -->
## Contract verbs

Generated from `api.ts` `HAND_CONTRACT`. Do not hand-edit this block.

| Verb | Contract arguments | Effect | First call |
|---|---|---|---|
| `chat` | `prompt` | `draft` | `npx tsx ~/.claude/skills/snappy-openrouter/api.ts chat "<prompt>"` |
| `fallback` | `prompt` | `draft` | `npx tsx ~/.claude/skills/snappy-openrouter/api.ts fallback "<prompt>"` |

## Show the result

When an answer carries `face_hint`, show it with one `snappy_present(<answer>)` call.
See `/snappy-faces` for face selection. Human-facing images must crop to the
element, render at 2x on Retina, and fill the destination channel instead of
placing a small card in a full-page screenshot.
<!-- SNAPPY-CONTRACT-VERBS-END -->

Keyboard Shortcuts

Search in document⌘K
Focus search/
Previous file tab
Next file tab
Close overlayEsc
Show shortcuts?