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

@hyphen_solution/cli

v0.1.0

Published

Command line interface for the Hyphen AI gateway — chat, model list, agent setup, diagnostics and an MCP server.

Downloads

86

Readme

@hyphen_solution/cli

The command line for Hyphen — an OpenAI-compatible AI gateway at https://api.hyphen-solution.com/v1.

hyphen login                       # store and verify your key
hyphen chat "explain CRDTs"        # one-shot completion
hyphen setup claude-code --write   # wire up your coding agent
hyphen doctor                      # find out what's broken

Built for humans and for agents: every command that emits data supports --json with a documented, stable shape; every failure mode has its own exit code; and hyphen help --agent prints the whole surface on one screen for pasting into an LLM's context.

  • No telemetry. Nothing is ever sent anywhere except the gateway you point it at.
  • Your API key is never printed in full. Not in output, not in errors, not in logs.
  • Zero runtime dependencies. Node's builtins only.

Install

npm  install -g @hyphen_solution/cli
pnpm add    -g @hyphen_solution/cli
yarn global add @hyphen_solution/cli
bun  add    -g @hyphen_solution/cli

Or run it without installing:

npx @hyphen_solution/cli models
pnpm dlx @hyphen_solution/cli models
yarn dlx @hyphen_solution/cli models
bunx @hyphen_solution/cli models

Requires Node 20 or newer. Verify with hyphen --version. No runtime dependencies. All four package managers are tested against the packed tarball before release.

From a checkout:

npm install
npm run build
npm link          # puts `hyphen` on your PATH

Quickstart

# 1. Get a key at https://app.hyphen-solution.com -> Dashboard -> API Keys
hyphen login

# 2. Check everything works
hyphen doctor

# 3. See what you can call
hyphen models

# 4. Use it
hyphen chat "write a haiku about type systems" --stream

# 5. Point your coding agent at it
hyphen setup --list
hyphen setup claude-code --write --with-key

Configuration

Credentials live at ~/.hyphen/config.json, written 0600 inside a 0700 directory.

Key precedence, everywhere:

  1. --key flag
  2. HYPHEN_API_KEY environment variable
  3. ~/.hyphen/config.json

So CI never needs hyphen login — set HYPHEN_API_KEY and every command picks it up.

| Variable | Purpose | | ------------------- | -------------------------------------------------------------------- | | HYPHEN_API_KEY | API key. Overrides the stored config everywhere. | | HYPHEN_BASE_URL | Gateway base URL including /v1. Default https://api.hyphen-solution.com/v1. | | HYPHEN_MODEL | Default model for chat and mcp. Default minimax-m2.7. | | HYPHEN_CONFIG_DIR | Where config.json and state.json live. Default ~/.hyphen. | | NO_COLOR | Set to disable ANSI colour. |


Commands

Run hyphen <command> --help for the full reference on any of these.

hyphen login

Store an API key, after verifying it with GET /v1/models — a typo fails immediately rather than at your next request. With no --key, the key is read from an interactive prompt with echo disabled; when stdin is a pipe, the first line of stdin is used.

hyphen login
hyphen login --key sk-xxxxxxxx
echo "$MY_KEY" | hyphen login

hyphen logout

Delete ~/.hyphen/config.json. Warns if HYPHEN_API_KEY is still set in your environment, since that would keep working.

hyphen whoami

Show which key is in use (masked), where it came from, and whether the gateway accepts it.

$ hyphen whoami
key           sk-a1b2...f9e8  (from HYPHEN_API_KEY)
base url      https://api.hyphen-solution.com/v1  (default)
default model minimax-m2.7
status        authenticated  10 models available

hyphen models

List the catalog your key can reach, straight from GET /v1/models.

hyphen models
hyphen models --json | jq -r '.models[].id'

hyphen chat ["<prompt>"]

Interactive with no arguments, one-shot with a prompt.

hyphen chat                                        # interactive session
hyphen chat "explain the borrow checker in two sentences"
hyphen chat "give me an example" -c                # continue the last thread
hyphen chat "find the bug" --file src/a.ts,src/b.ts
hyphen chat "summarise this" < README.md
hyphen chat "write a haiku" --stream
hyphen chat "list three colours" --json | jq -r .content

In an interactive session: /model <id>, /system <text>, /reset, /save <file>, /tokens, /exit. The thread is saved on exit and -c resumes it.

Input comes from a prompt argument, or piped stdin when no argument is given, or both — the argument becomes the instruction and stdin is appended as context. --file adds file contents as labelled blocks.

| Flag | Default | Notes | | ------------------ | -------------- | ------------------------------------------- | | --model | minimax-m2.7 | Any ID from hyphen models. | | --max-tokens | 2000 | See the warning below. | | --system | — | System prompt. | | -c, --continue | off | Continue the saved conversation. | | --file | — | Comma-separated files to attach. | | --stream | off | SSE; tokens are printed as they arrive. | | --show-reasoning | off | Print internal <think> output on stderr. | | --json | off | One JSON document on stdout. |

Conversations live in ~/.hyphen/last-conversation.json. Only the transcript is stored, never your key.

hyphen explain [<file>...]

Explain code, or diagnose a failure. It picks the mode from the input and you can force it with --error or --code.

hyphen explain src/api.ts
npm test 2>&1 | hyphen explain
hyphen explain src/repl.ts --question "how is the thread saved?"

hyphen commit

Write a commit message from the staged diff. Prints it by default; --apply commits with it.

hyphen commit
hyphen commit --apply
hyphen commit --json | jq -r .message

Large diffs are trimmed before sending, so one enormous change cannot quietly cost a fortune.

hyphen review

Review changes before pushing. Working tree by default.

hyphen review
hyphen review --staged --stream
hyphen review --against main

A second opinion, not a gate. It misses things and is sometimes confidently wrong.

hyphen batch <file|->

Run a file of prompts concurrently and write JSONL. Built for unattended runs.

hyphen batch prompts.txt --output results.jsonl
hyphen batch titles.txt --template "Summarise: {{input}}" --concurrency 8
hyphen batch prompts.txt --output results.jsonl --resume

Input is one prompt per line, or JSONL with {"id","prompt"} plus optional system and model. Both forms can be mixed. Every output record carries its id, so results match back to inputs regardless of completion order.

| Flag | Default | Notes | | --------------- | ------- | ------------------------------------------------------------ | | --template | — | Applied to every line; {{input}} is the line. | | --concurrency | 4 | Requests in flight, max 32. | | --retries | 4 | Per prompt, with exponential backoff. | | --output | stdout | JSONL destination. | | --resume | off | Skip ids already succeeded in --output. Needs --output. |

Transient failures are retried. A single bad prompt is recorded and skipped. If the monthly budget runs out the whole run stops immediately, because every remaining request would fail the same way — exit code 5 says that happened, and --resume continues later.

max_tokens matters more than you'd expect. These are reasoning models: they spend tokens thinking before they answer, out of the same budget. A small max_tokens can be consumed entirely by internal reasoning and return empty content. The default is 2000, and the CLI warns you below 256.

Reply text goes to stdout. Token counts and warnings go to stderr, so hyphen chat ... > out.txt gives you exactly the reply.

hyphen setup <tool>

The important one. Prints — and with --write applies — the correct config for your coding tool, including the single mistake that most often breaks that particular tool.

hyphen setup --list                       # every supported tool
hyphen setup claude-code                  # print the config
hyphen setup claude-code --write --with-key
hyphen setup aider --model minimax-m3
hyphen setup zed --json | jq -r '.files[0].content'

| Tool | Config written | The gotcha it handles for you | | ------------- | ---------------------------------- | -------------------------------------------------------------------------- | | claude-code | ~/.claude/settings.json | Model tiers must be remapped, or every request 400s on the model name. | | codex | ~/.codex/config.toml | wire_api = "responses" — the only value Codex supports since Feb 2026. | | cursor | UI only | Base URL must end in /v1. | | cline | UI only | Needs output headroom or replies come back empty. | | aider | ~/.aider.conf.yml | openai/ model prefix and OPENAI_API_BASE, not OPENAI_BASE_URL. | | zed | ~/.config/zed/settings.json | Key goes in HYPHEN_API_KEY, never in the committed settings file. | | continue | ~/.continue/config.json | provider: "openai" with apiBase; there is no native Hyphen provider. | | opencode | ~/.config/opencode/opencode.json | model is provider_id/model_id, not a bare name. | | goose | ~/.config/goose/config.yaml | OPENAI_HOST + OPENAI_BASE_PATH; Goose ignores OPENAI_BASE_URL. | | openhands | env vars / UI | openai/ prefix, and the CLI ignores env vars without --override-with-envs. | | kilo-code | ~/.config/kilo/kilo.jsonc | tool_call: true is required or the agent cannot edit files. |

--write never destroys your settings:

  • JSON configs are deep-merged — your existing keys survive.
  • TOML/YAML configs get a clearly marked block appended.
  • An existing file is always copied to <file>.hyphen.bak first.
  • If a Hyphen block is already present, the write is skipped (exit 1) unless you pass --force.
  • If appending would corrupt the file — top-level TOML keys after a [table] header, or a duplicate top-level YAML key — the write is refused with an explanation instead.

By default the config contains a sk-YOUR_KEY placeholder. Pass --with-key to inline the key the CLI is configured with. (Configs that read the key from the environment, like Codex, Zed and Kilo Code, never inline it at all — that is deliberate.)

hyphen doctor

Six checks, one line each, with the exit code of the first failure.

$ hyphen doctor
gateway https://api.hyphen-solution.com/v1   key sk-a1b2...f9e8   probe model minimax-m2.7

PASS  API key present         sk-a1b2...f9e8 from HYPHEN_API_KEY
PASS  Gateway reachable       https://api.hyphen-solution.com/v1 responded 214ms
PASS  Key accepted            GET /v1/models returned 200
PASS  Model catalog           10 models: minimax-m2, minimax-m2-her, minimax-m2.1, minimax-m2.1-highspeed, ...
PASS  Completion round-trip   minimax-m2.7 answered (18 tokens) 1240ms
PASS  Budget history          no 429 recorded on this machine

All checks passed.

hyphen doctor alone tells a script what is wrong: exit 3 no key, 4 bad key, 5 budget or rate limit, 6 network, 8 gateway error.

hyphen mcp

Runs an MCP server over stdio. See MCP setup below.

hyphen help --agent

Prints a compact, machine-oriented summary of every command, flag, exit code and JSON shape, designed to be pasted straight into an agent's context. hyphen help --json gives the same information as a structured document.


Exit codes

Every code has exactly one meaning. They are part of the CLI's public contract.

| Code | Name | Meaning | | ---- | ---------------- | -------------------------------------------------------------------- | | 0 | OK | Success. | | 1 | ERROR | Unexpected or unclassified failure. | | 2 | USAGE | Bad usage: unknown command or flag, missing argument. | | 3 | NO_CREDENTIALS | No API key configured (not logged in, HYPHEN_API_KEY unset). | | 4 | AUTH | Key rejected by the gateway (HTTP 401/403). | | 5 | RATE_LIMIT | HTTP 429: monthly budget exceeded, or a fair-use rate limit. | | 6 | NETWORK | Could not reach the gateway (DNS, TLS, connection refused, timeout). | | 7 | API | Gateway returned a 4xx other than 401/403/429. | | 8 | SERVER | Gateway returned a 5xx. |

Note that 4 and 5 are distinct: a rejected key is not the same problem as a spent budget, and a script should not treat them the same way.

Machine-readable output

--json is available on every command that emits data. Success payloads go to stdout, always as exactly one JSON document. Errors go to stderr.

Error envelope:

{
  "ok": false,
  "error": {
    "code": "budget_exceeded",
    "message": "Budget has been exceeded! Monthly budget resets on 2026-08-01.",
    "exit_code": 5,
    "status": 429,
    "hint": "Monthly budget spent. It resets on 2026-08-01. ...",
    "reset_date": "2026-08-01",
    "retry_after_seconds": 1209600,
    "rate_limit_kind": "budget"
  }
}

error.code is one of: usage, no_credentials, auth_failed, budget_exceeded, rate_limited, network, api_error, server_error, error.

Success shapes, one per command:

| Command | --json shape | | -------- | --------------------------------------------------------------------------------------------------------------------------------- | | login | {ok, key, base_url, config_path, model_count} | | logout | {ok, removed, config_path, env_key_still_set} | | whoami | {ok, key, key_source, base_url, base_url_source, config_path, default_model, authenticated, model_count, error?} | | models | {ok, base_url, count, models:[{id, owned_by, note}]} | | chat | {ok, model, content, finish_reason, usage:{prompt_tokens,completion_tokens,total_tokens}, streamed, max_tokens} | | setup | {ok, tool, title, docs_url, writable, base_url, model, key, key_inlined, gotcha, files:[...], env:[...], steps, notes, verify, written:[...]} | | doctor | {ok, base_url, key, key_source, probe_model, exit_code, checks:[{id,title,status,detail,latency_ms,error_code}]} | | help | The full command spec: {name, version, commands:[...], exit_codes, environment, error_codes, setup_tools} |

Handling 429

A 429 means one of two very different things, and the CLI tells them apart:

  • Budget (error.rate_limit_kind: "budget", code budget_exceeded) — the monthly cap on the key is spent. reset_date carries the day it comes back. Retrying is pointless. Buy a credit pack or switch to a credit key.
  • Fair use (rate_limited) — requests-per-minute or tokens-per-minute. Back off a few seconds and retry; retry_after_seconds is the server's hint.

Both exit 5; branch on error.code or error.rate_limit_kind when you need to distinguish.


MCP setup

hyphen mcp exposes Hyphen to any MCP-capable agent over stdio (JSON-RPC 2.0, one message per line). It implements initialize, notifications/initialized, ping, tools/list and tools/call, and negotiates protocol versions 2025-06-18, 2025-03-26 and 2024-11-05.

Tools exposed:

| Tool | Input | Returns | | --------------------- | ---------------------------------------- | -------------------------------------------------------------------- | | hyphen_chat | {prompt, model?, max_tokens?, system?} | The model's reply. | | hyphen_list_models | {} | Model IDs the key can reach. | | hyphen_check_budget | {} | Whether a 429 was seen, its kind, and the reset date if known. |

Claude Code

claude mcp add hyphen -- hyphen mcp

Anything with an mcpServers block

Cursor (~/.cursor/mcp.json), Windsurf, Zed, Cline and most other clients:

{
  "mcpServers": {
    "hyphen": {
      "command": "hyphen",
      "args": ["mcp"],
      "env": {
        "HYPHEN_API_KEY": "sk-YOUR_KEY"
      }
    }
  }
}

The env block is optional — the server uses the same key resolution as every other command, so if you have run hyphen login it already has what it needs.

Verifying it by hand

printf '%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{}}}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
  | hyphen mcp

A missing API key does not stop the server from starting — tools/call returns a structured error instead, so the agent can report the problem rather than silently dying.

hyphen_check_budget reports from local history: the CLI records any 429 it sees in ~/.hyphen/state.json. There is no budget-query endpoint on the public API, so a fresh machine correctly reports "no 429 recorded" rather than guessing.


Notes on the models

Ten models, one base URL. hyphen models is always authoritative; this is the shape of it:

  • minimax-m3 — flagship, for hard reasoning and long agent runs.
  • minimax-m2.7 — balanced daily driver, the CLI's default for chat.
  • minimax-m2.5 — fast and cheap; good for background and commit-message work.
  • *-highspeed variants — same weights, latency-tuned serving, exactly 2x the rate.
  • minimax-m2.1, minimax-m2 — older generations, kept for compatibility.
  • minimax-m2-her — roleplay/dialogue tuning. Don't wire it into a coding agent.
  • minimax-text-01 — 4M context, cheapest per token.

Two behaviours worth knowing:

  • max_tokens can be eaten by reasoning. These models think before they answer, out of the same output budget. Too small a cap returns empty content rather than a short answer. Use 2000 as a floor for chat, 4000 for anything agentic.
  • tool_choice forcing does not work. "required" and named-function forcing are ignored by these models. Only "auto" and "none" take effect. Design your tool loops accordingly.

Scope

This CLI only calls public /v1/* endpoints. Admin routes (/key/*, /user/*) are blocked at the gateway's public edge, so there are deliberately no key-management or usage-reporting commands here — do that in the console.

Development

npm install
npm run build     # tsc -> dist/
npm test          # builds, then runs node:test over test/

Tests cover the pure parts — argument parsing, config precedence and masking, exit-code mapping, the setup-config generator for every tool, and the merge/write logic. None of them touch the network.

Links