소스 정보
- 저장소
- publieople/hermes-config-kit
- 최근 소스 활동
- 2026년 7월 26일 00:46
- 감지된 SKILL.md 언어
- 영어
- 스타
- 0
- 포크
- 0
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/publieople/hermes-config-kit --skill omniroute-gateway명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | omniroute-gateway |
| description | OmniRoute install, MCP, Hermes on WSL. Load on issues. |
| version | 1.0.0 |
| author | Hermes Agent + Publieople |
| license | MIT |
| metadata | {"hermes":{"tags":["omniroute","gateway","mcp","providers","llm-router","wsl","systemd"],"related_skills":["hermes-agent","hermes-bootstrap"]}} |
OmniRoute is a local AI gateway: a Node.js HTTP server (http://localhost:20128) exposing an OpenAI-compatible API at /v1 that proxies to 290+ upstream AI providers with auto-failover, 12-factor scoring, and 15-95% token compression. Goal: replace direct provider API calls with one local endpoint so any AI coding tool (Claude Code, Codex, Cursor, OpenCode, Hermes, etc.) gains provider-agnostic resilience.
This skill captures the operational knowledge needed to install OmniRoute, expose its MCP server to external agents (Hermes), and integrate it as a model provider — knowledge that repeats every time someone sets this up fresh.
PUT /api/settings/compressionGET /api/settings/compression to see languageConfig# 1. Install (background — ~5 min, 1176 packages)
npm install -g omniroute
# 2. CRITICAL: re-install with native-binding scripts allowed.
# Without this, better-sqlite3/sharp/onnxruntime-node are silently skipped
# and the CLI launches but every endpoint returns HTTP 500 ("better-sqlite3
# native binary was not found"). The full allow-scripts CSV:
npm install -g --allow-scripts=omniroute,better-sqlite3,keytar,tls-client-node,onnxruntime-node,sharp,core-js,esbuild,@parcel/watcher,@swc/core,protobufjs,koffi omniroute
# 3. Verify native binary
omniroute doctor
# → "OK Native binary: better-sqlite3 native binary is compatible"
# 4. systemd unit at ~/.config/systemd/user/omniroute.service
# ⚠️ MUST have ProtectHome=false AND ProtectSystem=false.
# The default templates ship with ProtectHome=read-only, which makes SQLite
# writes silently fail (storage.sqlite created at install but never
# updated post-startup) → /v1/models and /api/health return HTTP 500 with
# no log error. The "OmniRoute is running!" banner lies — it only proves
# the HTTP server bound the port, not that requests work. Verify with curl:
curl http://localhost:20128/v1/models
# → 200 + JSON catalog. If 500, fix ProtectHome/ProtectSystem and restart.
# 5. Enable + start
systemctl --user daemon-reload
systemctl --user enable --now omniroute.service
# 6. Wait ~8s for "OmniRoute is running!" then verify with curl.
# 7. Add providers via Dashboard (http://localhost:20128) — or use the
# OmniRoute Agent Skills catalog at /api/agent-skills for automation.
Reference systemd unit (tested, works):
[Unit]
Description=OmniRoute AI Gateway
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=/home/po
ExecStart=/home/po/.npm-global/bin/omniroute
Restart=on-failure
RestartSec=5
TimeoutStartSec=30
# CRITICAL: these two must be false for OmniRoute to write ~/.omniroute/
ProtectSystem=false
ProtectHome=false
PrivateTmp=true
[Install]
WantedBy=default.target
omniroute-bin)omniroute-bin (AUR) packages the OmniRoute Electron AppImage at /opt/omniroute-bin/OmniRoute.AppImage and a 68-byte /usr/bin/omniroute wrapper (exec /opt/omniroute-bin/OmniRoute.AppImage "$@"). The package ships no systemd unit and no AppArmor/systemd integration, so you must author your own — and on WSL you must also work around three defects the npm build path does not expose (see Pitfall 8 and references/or-appimage-wsl-quirks.md):
[Unit]
Description=OmniRoute AI Gateway (AppImage)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=/home/po
# Electron app needs a display server; xvfb-run resolves the ozone/x11 crash.
# AppRun locates APPDIR by readlink-ing itself, so we run it from the
# extracted dir, NOT directly (FUSE unavailable on WSL2).
ExecStart=/usr/bin/xvfb-run -a /home/po/squashfs-root/AppRun
Restart=on-failure
RestartSec=5
TimeoutStartSec=30
ProtectSystem=false
ProtectHome=false
PrivateTmp=true
[Install]
WantedBy=default.target
To seed the squashfs-root/ directory:
cd /home/po # AppImage must write somewhere user-writable
/opt/omniroute-bin/OmniRoute.AppImage --appimage-extract
Default mcpEnabled: false and mcpTransport unset. External agents (Hermes, Claude Desktop) hitting /api/mcp/stream will get {"error":"MCP server is disabled. Enable it from the Endpoints page."} until all four are set:
/api/auth/login with the initial admin password from logs):
curl -X PATCH http://localhost:20128/api/settings \
-H "Content-Type: application/json" \
-H "Cookie: auth_token=$COOKIE" \
-d '{"mcpEnabled":true,"mcpTransport":"streamable-http","a2aEnabled":true}'
curl -X POST http://localhost:20128/api/keys \
-H "Content-Type: application/json" -H "Cookie: auth_token=$COOKIE" \
-d '{"name":"hermes-mcp","scopes":["admin"]}'
→ returns {"key":"sk-XX...YY","id":"..."}. sk-… value is masked on the wire (response shape {"key":"sk-41a4c****37f1",…}); the reveal endpoint is disabled in v3.8.49 by default ({"error":"API key reveal is disabled"}). The full key is shown exactly once, only when the operator clicks "copy" in the Dashboard. CLI/API users cannot recover it. Plan: ask the user to create the key in Dashboard and paste it; do not rely on the API as the source of full keys. See or-compression-config.md § "API key creation returns masked value". manage scope is sufficient for PUT /api/settings/compression; only /api/keys admin and /api/auth/login revocation need admin.Authorization: Bearer <key> header works for both chat completions and MCP if the key has admin scope. No cookie needed from external clients.initialize returns Mcp-Session-Id response header → pass it as Mcp-Session-Id on every subsequent tools/list / tools/call within the same session. Server returns SSE format (event: message\ndata: {json}\n\n).Verify with hermes mcp test omniroute → should show ✓ Connected (~500ms) and ✓ Tools discovered: 99.
Hermes supports any OpenAI-compatible endpoint via provider: custom (NOT provider: openai — that errors at startup with Unknown provider 'openai'):
hermes config set model.default "minimax-cn/MiniMax-M3" # or auto/coding
hermes config set model.provider "custom"
hermes config set model.base_url "http://localhost:20128/v1"
hermes config set model.api_key "sk-..." # the OR gateway key from step 2
hermes config set model.context_length 1048576 # match the model's context window
hermes chat -q "test" # verify end-to-end
The auto/* virtual models (no combo creation needed) make Hermes pick the best model across all providers OR has connected — auto/coding, auto/fast, auto/cheap, auto/coding:fast, auto/reasoning:pro etc. Validated against GET /v1/models; the combo owned_by group in that list IS the auto catalog.
Each provider has an alias field in src/shared/constants/providers.ts (or registry files). The model ID format is <alias>/<model-id>:
| Provider | Prefix | Example |
|---|---|---|
minimax-cn (China, Token Plan) | minimax-cn/ | minimax-cn/MiniMax-M3 |
minimax (Global) | minimax/ | — |
github (Copilot OAuth) | gh/ or github/ | github/claude-sonnet-5 |
auggie | aug/ | aug/claude-sonnet-4.6 |
opencode (free tier) | oc/ | oc/minimax-m3-free |
duckduckgo-web | ddgw/ | ddgw/gpt-5-mini |
theoldllm | tllm/ | tllm/CLAUDE_4_6_OPUS |
veoaifree-web | veo-free/ | veo-free/veo |
mimocode (Xiaomi) | mcode/ | mcode/mimo-auto |
chipotle | pepper/ | pepper/pepper-1 |
To verify what each provider exposes: curl http://localhost:20128/v1/models -H "Authorization: Bearer $KEY" | python3 -c "import sys,json; d=json.load(sys.stdin); [print(m['owned_by'], m['id']) for m in d['data']]".
Banner shows "running" but /v1/models and /api/health return HTTP 500 with no log error. Root cause: ProtectHome=read-only in systemd unit blocking SQLite writes. Fix: edit the unit to set ProtectHome=false ProtectSystem=false, then systemctl --user daemon-reload && systemctl --user restart omniroute. Verify with stat -c '%y' ~/.omniroute/storage.sqlite — mtime should advance past the service restart time after the first request.
npm install succeeds but native binary was not foundPEP 668-like mechanism silently blocked 12 native-binding install scripts (better-sqlite3, sharp, onnxruntime-node, koffi, esbuild, @parcel/watcher, @swc/core, keytar, tls-client-node, core-js, protobufjs, omniroute itself). Re-install with the explicit --allow-scripts CSV above. Applies to ANY npm package using node-gyp (electron tools, SQLite drivers, ONNX, image-processing CLIs).
mcpEnabled is false by default. Fix requires PATCH /api/settings (not just toggling in UI if API-only). Confirms MCP is exposed: curl -X POST http://localhost:20128/api/mcp/stream should return event: message\ndata: {"result":{"serverInfo":{"name":"omniroute"}}}, not the disabled error.
Unknown provider 'openai'model.provider is the dispatcher name, not the upstream API name. For ANY OpenAI-compatible endpoint (OmniRoute, LiteLLM, vLLM, Ollama, LM Studio), use provider: custom. The skill-level fix is in SKILL.md at ## Providers → add an explicit note. (Bundled skill; cannot edit. Carry the rule in this skill.)
OmniRoute's src/lib/cli-helper/tool-detector.ts uses getCachedLoginShellPath() which returns null on any non-darwin platform (line 60: if (platform !== "darwin") return null). On Linux/WSL, detector only sees systemd's truncated PATH (typically /usr/local/bin:/usr/bin), missing ~/.npm-global/bin/ and ~/.local/bin/. Hermes installs to ~/.local/bin/hermes (Python venv wrapper). Workaround: symlink to a path in the truncated PATH:
ln -sf /home/po/.local/bin/hermes /home/po/.npm-global/bin/hermes
OR detector checks for binary in PATH (not config dir). If you only deleted ~/.openclaw/ config but didn't run npm uninstall -g openclaw, the binary is still in /home/po/.npm-global/bin/ and detector reports "installed". Fix: npm uninstall -g openclaw. Detector then returns installed=false.
OmniRoute's minimax-cn provider hardcodes https://api.minimaxi.com/anthropic/v1/messages as the base URL (Anthropic-compatible surface), NOT the /v1/coding_plan/... path used by the mmx CLI. The same API key works for both — Token Plan quota IS consumed when calling through OmniRoute's minimax-cn/MiniMax-M3 (verified by x-mm-request-id response header in the request back to minimaxi.com). If the user wants the dedicated Token Plan endpoint instead, that requires an OmniRoute provider plugin (custom baseUrl).
omniroute-bin (AppImage) on WSL — three stacked defectsThe AUR package works on native Linux but fails on WSL across three layers; each layer masks the next, so users typically only see HTTP 500 on /v1/models and assume it's a config bug. All three fixes are needed.
No systemd unit. omniroute-bin ships only /usr/bin/omniroute (AppImage launcher) and /opt/omniroute-bin/OmniRoute.AppImage. There is no unit file. An orphan user unit pointing at the old npm path (/home/po/.npm-global/bin/omniroute) will silently keep restarting with status=203/EXEC ("no such file"). Symptom: Restart counter is at N, port 20128 never opens.
FUSE unavailable in WSL2 kernel. Running /opt/omniroute-bin/OmniRoute.AppImage directly fails: Cannot mount AppImage, please check your FUSE setup. WSL2's kernel is sealed/signed-readonly; userspace apt install fuse only gives userspace helpers, not fuse.ko. AppImage itself has a fallback: AppImage --appimage-extract writes squashfs-root/ to cwd and exits. Then point systemd at <extracted>/AppRun.
Electron ozone/x11 crash under systemd. Even after extraction, ./AppRun runs Electron directly. Without $DISPLAY, Chromium-ozone dies: Missing X server or $DISPLAY → The platform failed to initialize. Exiting → SIGSEGV. systemd user manager does not export $DISPLAY. Wrap with xvfb-run -a: it spawns a background Xvfb :99 and provides $DISPLAY=:99 to AppRun. xvfb-run is normally already installed (/usr/bin/xvfb-run).
After wrapping with xvfb-run, OmniRoute starts and binds 20128 — but a fourth issue then surfaces:
better-sqlite3 native binary via --allow-scripts. The AUR/AppImage build skips that, the embedded Electron Node is 22.2.10 (≤22.4), so node:sqlite (≥22.5 stdlib) is also unavailable. Only sql.js WASM remains, and its lazy warmUpRuntimes() may not finish before the first HTTP request lands, yielding [DB] Nenhum driver SQLite disponível ... sql.js WASM ainda não foi pré-inicializado on every /v1/* call. This is a packaging defect in omniroute-bin, not a misconfiguration. The recommended fix is to revert to the npm install path on WSL; the AUR/AppImage install should be considered unsupportable on WSL2 until upstream bundles a portable SQLite layer.Decision matrix:
| Choice | SQL guaranteed? | WSL2 cost | Recommended for |
|---|---|---|---|
npm i -g omniroute --allow-scripts=... | ✅ bundled better-sqlite3 | low | Yes — default |
yay -S omniroute-bin + AppImage + xvfb | ⚠️ only sql.js, may 500 | medium | Native Arch on bare metal |
| Docker | ✅ | low | Hermetic / cross-machine |
Source build (git clone && npm i) | ✅ | high | Customization / patch dev |
Bottom line: on WSL stay on the npm install path. The AUR/AppImage install is not viable there without upstream changes.
→ Full reproduction transcript + exact logs at references/or-appimage-wsl-quirks.md.
hermes mcp test omniroute should report 99 tools. The notable ones for agent automation:
omniroute_get_health — uptime, memory, circuit breakers, cache statsomniroute_list_combos — all configured combosomniroute_route_request — send a chat completion through OR routingomniroute_simulate_route — predict routing without firing requestomniroute_check_quota — remaining quota per provideromniroute_cost_report — cost by period (session/day/week/month)omniroute_list_models_catalog — all available modelsomniroute_set_routing_strategy — change routing strategy at runtimeomniroute_set_resilience_profile — aggressive/balanced/conservativeomniroute_set_budget_guard — USD cap per sessionomniroute_test_combo — live-fire all providers in a comboomniroute_compression_status — RTK/Caveman engine stateomniroute_cache_stats — semantic + prompt cache hit rateomniroute_sync_pricing — refresh pricing from LiteLLMomniroute_db_health_check — repair broken combo referencesomniroute_pick_fastest_model — best latency combo across providersomniroute_set_compression_engine — switch RTK/Caveman/Lite/stacked/etc.omniroute_agent_skills_list / _get / _coverage — 42 SKILL.md catalogomniroute_web_search / omniroute_web_fetch — web gateway toolsomniroute_oneproxy_* — proxy pool managementomniroute_omniroute_skills_* — agent skills discoveryPlus per-feature clusters: memory, eval, a2a, gamification, webhooks.
auto/* model IDsOmniRoute's 12-factor scoring (health 0.20, quota 0.15, costInv 0.15, latencyInv 0.12, taskFit 0.08, etc.) means Tier 1 subscription (cost = 0) wins over Tier 2 API key over Tier 3 free. With Token Plan minimax-cn connected, auto/coding defaults to M3. Pre-defined weight profiles override: X-OmniRoute-Mode: fast|cheap|quality|reliable|offline.
Per-request controls:
curl -X POST http://localhost:20128/v1/chat/completions \
-H "X-OmniRoute-Mode: fast" \
-H "X-OmniRoute-Budget: 0.05" \
-H "X-OmniRoute-Budget-Fallback: strict" \
-d '{"model":"auto",...}'
Compression has two orthogonal persist surfaces; setting either alone gives a half-configured pipeline. See references/or-compression-config.md for the full three-surface table.
| Surface | Persists via | What it writes |
|---|---|---|
| Engine pipeline (which engines + intensities) | MCP omniroute_set_compression_engine, or in the PUT /api/settings/compression body | stackedPipeline, engines.*.enabled, rtkConfig, cavemanConfig |
| Trigger layer (when, how much, hard guards) | MCP omniroute_compression_configure, or in the PUT /api/settings/compression body | defaultMode, autoTriggerMode, autoTriggerTokens, strategy, targetRatio, preserveSystemPrompt, languageConfig |
Rule of thumb: call engine first (decides WHAT pipeline runs), then trigger (decides WHEN + HOW MUCH). Doing only one yields half-configured compression that may or may not fire.
PATCH /api/settings (i.e. the root settings endpoint) accepts the body, returns 200, and silently drops every compression-namespace key — including languageConfig. That's why dashboard toggles survive a refresh but PATCH scripts have no effect. Real entrypoint is PUT /api/settings/compression (Zod-validated schema compressionSettingsUpdateSchema).
MCP omniroute_compression_status returns the trigger state but not languageConfig. To see / change languageConfig you must use GET/PUT /api/settings/compression.
Language packs in v3.8.49: ["en","zh","pt-BR","es","de","fr","ja","id"] (8 installed). The wiki Compression-Language-Packs page lists only 6 — outdated; zh (16 rules) and id exist but are missing from the docs. To enable:
curl -X PUT http://localhost:20128/api/settings/compression \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"languageConfig":{"enabled":true,"enabledPacks":["en","zh"],"defaultLanguage":"zh","autoDetect":true}}'
When a system prompt enumerates external SKILL.md directories (e.g. ~/.hermes/skills/devops/omniroute-agents/ containing all 44 OR agent-skill files), Hermes's loader (agent/prompt_builder.py:1514 build_skills_system_prompt) parses the YAML frontmatter of each one and emits exactly one index line per skill:
- omni-inference: The core OpenAI-compatible inference endpoints: chat completions, embeddings, …
It does not emit the SKILL.md body. The body is only loaded when the model explicitly calls skill_view(name='omni-inference'). So the 44 SKILL.md files (avg ~10 KB body each) cost roughly 2 K tokens / 8.5 KB in the system prompt — average description length is ~172 chars. This is small enough to install them all at once (option B is acceptable) rather than cherry-picking. Confirmed by frontmatter scan, not estimated.
→ If the model needs full skill prose, ask it to call skill_view(name='omni-inference') first rather than guessing from the description line.
# Service alive
curl -sS -o /dev/null -w "%{http_code}\n" http://localhost:20128/v1/models # → 200
# Provider active
curl -sS -X POST http://localhost:20128/v1/chat/completions \
-H "Authorization: Bearer $KEY" \
-d '{"model":"minimax-cn/MiniMax-M3","messages":[{"role":"user","content":"1+1"}],"max_tokens":10}'
# → 200 with x-mm-request-id header (proves minimaxi.com was called)
# MCP for external agents
hermes mcp test omniroute
# → ✓ Connected + ✓ Tools discovered: 99
# Auto routing
curl -sS -X POST http://localhost:20128/v1/chat/completions \
-H "Authorization: Bearer $KEY" \
-d '{"model":"auto/coding","messages":[{"role":"user","content":"hi"}],"max_tokens":10}'
# → 200, model field shows which provider won
hermes-agent skill — Hermes configuration, MCP server commands, providersreferences/or-provider-prefix-table.md — verified alias/model-id mapping for OR 3.8.xreferences/or-mcp-curl-smoke.sh — reproducible smoke test for MCP enable + 99-tool discoveryreferences/or-appimage-wsl-quirks.md — full transcript of the 4-layer failure chain when running omniroute-bin on WSL2 (FUSE → xvfb → SQLite) and why the npm path is the only stable onereferences/or-compression-config.md — the three persistence surfaces (PATCH /api/settings vs PUT /api/settings/compression vs MCP compression_configure), the 8 actually-installed language packs (incl. zh/id, not 6 like the wiki claims), the verified "standard" recipe, and the API key reveal gotcha"