npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

muse-openrouter

v0.1.0

Published

A transparent compatibility gateway that lets the native Muse Code harness use OpenRouter Contributor without changing Muse semantics.

Readme

muse-openrouter

A transparent compatibility gateway that lets the native Muse Code harness use OpenRouter Contributor without changing Muse semantics.

Muse Code
  → localhost compatibility gateway (127.0.0.1:9911)
  → OpenRouter
  → meta/muse-spark-1.2-contributor

Muse continues to think it talks to:

  • provider: meta
  • model: muse-spark-1.2
  • profile: tbh

Only the top-level model name is rewritten for the upstream transport to meta/muse-spark-1.2-contributor. No silent fallback to meta/muse-spark-1.2 or any other model.

Requirements

  • Node.js >=24
  • Muse Code installed separately (muse --version should show 0.2.1)
  • OpenRouter account and API key (sk-or-v1-...)

Install

npm install -g muse-openrouter

Verify:

muse-or --help
muse-or-proxy --help
muse-or doctor

The original muse binary is never replaced.

Setup

Run once:

muse-or setup

This will:

  • find the real muse binary in your PATH
  • show the detected Muse version
  • ask for your OpenRouter API key (input hidden)
  • save it securely to ~/.config/muse-openrouter/config.json with 0600 permissions
  • prepare an isolated Muse config at ~/.config/muse-openrouter/xdg/muse/settings.json
  • verify the setup

Setup is idempotent. Re-running it keeps existing settings unless you pass --force.

If you prefer env-based automation, OPENROUTER_API_KEY can override the stored key at runtime, but normal use is the persisted config.

Usage

Terminal 1 – gateway (foreground, Ctrl+C to stop):

muse-or-proxy

Startup summary:

Muse OpenRouter Gateway
Listen      127.0.0.1:9911
Upstream    OpenRouter
Model       meta/muse-spark-1.2-contributor
Bridge      namespace
Normalizer  schema-aware
Status      ready

Health: http://127.0.0.1:9911/health

Terminal 2 – Muse:

cd ~/your-project
muse-or --reasoning-effort xhigh
muse-or resume SESSION_ID

All native Muse arguments are forwarded unchanged, including --reasoning-effort. The reasoning request object is passed through untouched.

If the gateway is not running, muse-or fails fast:

gateway is not running on 127.0.0.1:9911
run: muse-or-proxy

No automatic fallback to direct Meta and no background daemon.

How it works

Muse Code 0.2.1 sends tools as a Responses type: "namespace" container (muse with nested read_file, bash, subagent tools, etc.). Some OpenAI-compatible gateways are more reliable with flat function tools, so the gateway:

  1. Flatten – converts the muse namespace into ordinary top-level function tools for the OpenRouter transport.
  2. Forward – rewrites only the top-level model to meta/muse-spark-1.2-contributor and proxies POST /v1/responses to https://openrouter.ai/api/v1/responses.
  3. Restore – on the response path, restores namespace: "muse" and normalizes tool arguments before Muse sees them.
  4. Normalize – schema-aware, conservative coercion of tool arguments (e.g. "100" → 100, "false" → false) based on the exact JSON Schemas Muse sent, including $ref, anyOf/oneOf/allOf. Never invents missing required arguments.

Other routes (/muse-code/models, /muse-code/config, /health) are served locally.

Philosophy / non-goals

This is not a new Muse client and does not try to improve Muse.

The gateway is deliberately minimal:

  • Native Muse stays native – tool semantics, prompts, catalog/profile (tbh), limits (1,048,576 ctx / 131,072 out) remain unchanged.
  • No daemon/service – muse-or-proxy is always foreground. No systemd, no background manager.
  • No silent fallback – if the gateway is down or OpenRouter errors, the error is surfaced.
  • No semantic reinterpretation – subagent_send_message interrupt:true returning invalid_input is native Muse behavior and is not “fixed” by the adapter.
  • No prompt or reasoning management – Muse owns reasoning configuration.
  • No auto-launch – muse-or never starts the proxy automatically.
  • No hidden rewrites – /bin/bash → /bin/sh is not done (opt-in only if ever needed, default off).

If Muse returns an error, the gateway passes it through.

Configuration

Persistent config lives at:

~/.config/muse-openrouter/config.json
# or $XDG_CONFIG_HOME/muse-openrouter/config.json

Defaults:

{
  "host": "127.0.0.1",
  "port": 9911,
  "upstream_model": "meta/muse-spark-1.2-contributor",
  "openrouter_base_url": "https://openrouter.ai/api/v1/",
  "api_key": "sk-or-v1-..."
}

Isolated Muse settings:

~/.config/muse-openrouter/xdg/muse/settings.json

You can inspect it:

jq '{provider,model,endpoint_transport,model_catalog}' ~/.config/muse-openrouter/xdg/muse/settings.json

Manage config:

muse-or config show
muse-or config set port 9912
muse-or config edit

Permissions are set to 0700 for directories and 0600 for files.

Doctor

muse-or doctor

Checks:

  • Node version >=24
  • real muse binary and version
  • config existence/validity and permissions
  • API key configured
  • isolated Muse profile (meta/muse-spark-1.2/tbh, limits)
  • expected Contributor model
  • namespace bridge and normalizer enabled
  • gateway liveness via /health (if running)

The API key is never printed.

Proxy options

muse-or-proxy --verbose
muse-or-proxy --debug-tools
muse-or-proxy --debug-schemas subagent_send_message,subagent_cancel
muse-or-proxy --capture /tmp/capture
muse-or-proxy --host 127.0.0.1 --port 9911

For backwards compatibility, env vars still work:

DEBUG=1 TOOL_DEBUG=1 TOOL_CAPTURE_DIR=/tmp/capture OPENROUTER_API_KEY=sk-or-v1-... muse-or-proxy

Normal mode logs compact request lines. --verbose enables detailed logs.

Health endpoint:

curl -s http://127.0.0.1:9911/health | jq

Troubleshooting

gateway is not running on 127.0.0.1:9911 – start muse-or-proxy in another terminal.

muse: command not found – install Muse Code separately and ensure muse is in PATH. muse-or doctor shows the resolved binary.

OPENROUTER_API_KEY is required – run muse-or setup or set OPENROUTER_API_KEY env for automation.

EADDRINUSE / port occupied – another muse-or-proxy is running or the port is taken. Use muse-or config set port 9912 or muse-or-proxy --port 9912.

Auth failure / 401 from OpenRouter – verify the key at https://openrouter.ai/keys. The gateway never logs the key; check /health confirms the model but not the secret.

NixOS /bin/bash missing – the gateway does not rewrite /bin/bash to /bin/sh by default. Muse tool semantics are preserved. An explicit opt-in shim could be added if needed, but is off by default.

Tool decoding errors – run with diagnostics:

muse-or-proxy --debug-tools --capture /tmp/muse-capture
# or
DEBUG=1 TOOL_DEBUG=1 TOOL_DEBUG_ARGS=1 TOOL_CAPTURE_DIR=/tmp/capture muse-or-proxy

Captures contain r0001-request-tools.json and r0001-tool-events.ndjson (tool-related SSE only).

subagent_send_message interrupt:true → invalid_input – this is native Muse Code 0.2.1 behavior despite a permissive schema. The gateway does not reinterpret it.

Security

  • The API key is stored only in ~/.config/muse-openrouter/config.json (0600).
  • It is never logged, never committed to the repo, never written to the isolated Muse settings, and never forwarded to Muse.
  • All diagnostics redact sk-or-... and Bearer ....
  • Use muse-or doctor to verify permissions without revealing the secret.

Tests

npm test

Covers namespace flatten/restore, collisions, streaming SSE, argument normalization, malformed inputs, model rewrite, reasoning preservation, health, launcher forwarding, and CLI behavior.

License

MIT – see LICENSE if present in the repo.