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

@openh/cli

v0.4.0

Published

The openharness terminal UI: an Ink (React) chat client installed as the `oh` command.

Readme

openharness

The terminal UI for openharness — an open-source implementation of Anthropic's Managed Agents architecture (a stateless brain, a durable session log, pluggable hands). An Ink (React) chat client that talks to an openharness server, installed as the oh command.

One self-contained file, no runtime dependencies: oh loads everything at startup, so an npm install -g @openh/cli@next — including the one oh runs for itself — may replace it on disk while a chat is running.

Install

Requires Node.js 24 or newer.

npm i -g @openh/cli

This installs the oh command. The npm package is @openh/cli (npm refuses the unscoped openharness name, #194); the command it installs is oh.

Use

Sign in, add a provider key, and chat — oh will offer the first two itself if you just run it:

oh                 # signed out? it asks, then runs the device flow
                   # no provider key? it asks for one right here, then opens a chat
oh providers list  # what you have stored: provider, last four, when it was added

oh talks to https://app.oharness.dev unless you point it somewhere else. --server is per-run; to keep it, either export it or write it to the config file:

oh --server http://localhost:3000 login        # a server of your own (see the repo for one)
export OPENHARNESS_URL=http://localhost:3000   # or, persistent:
# ~/.config/openharness/config.json → { "server": "http://localhost:3000" }

Resolution order, highest first: --server, OPENHARNESS_URL, ~/.config/openharness/config.json, then https://app.oharness.dev as the default.

Working from a checkout of the repo, yarn oh builds the CLI and runs it against http://localhost:3000 (yarn oh:staging and yarn oh:prod run it against staging and production); arguments pass straight through, so yarn oh:staging login works.

Commands

| command | what it does | | -------------------------------------- | ------------------------------------------------------------------------- | | oh | start a new chat on your default model | | oh -c / oh -s <id> | resume the most recent session, or a particular one | | oh sessions | list your sessions; oh sessions delete <id> deletes one (asks first) | | oh agents | list saved agent presets; start one with --agent <id\|name> | | oh providers | list the model-provider keys you have stored | | oh providers add [provider] | connect a provider — paste its key into a hidden prompt | | oh providers remove <provider> | forget a key (asks first; --yes skips the question) | | oh default-model [provider/model] | print or set the model a new chat starts on | | oh modes | list your modes; start a chat on one with --mode <name> | | oh settings | show or set when a long chat is summarized, and by which model | | oh tools [name] | list the built-in tools, or set one (--on/--off/--policy) | | oh mcp | your remote MCP servers: add, connect (OAuth), test, set tool permissions | | oh login / oh logout / oh whoami | sign in (browser device flow), revoke, who am I | | oh update | install the newest published version now | | oh --help, oh --version | print and stop |

Inside a chat: Enter sends (a message sent mid-reply steers it), and Ctrl+J or Alt+Enter inserts a newline. Type / for the command menu — ↑/↓ choose, Tab completes, Enter runs, Esc closes — which holds /model (switch models), /providers (connect a provider without leaving the chat), /new (start a new chat on the current model), /compact [instructions] (summarize the older history now, with optional guidance for the summary), /tools (turn the built-in tools on or off and set what each may do: allow, ask or deny), /mcp (your remote MCP servers), /agents (this chat's background tasks: open one's own chat, or stop one), /clear (clear the screen, keeping the session), /help, and /exit. A message that starts with // sends a literal /. Ctrl+C interrupts the reply; pressed again when idle, it leaves. On the way out, oh prints the oh -s <id> line that resumes the chat.

The model can use tools: fetch a page, search the web (on providers that have a native search), keep a task list, ask you a question, and call the tools of your remote MCP servers. Each call is a line in the transcript with a ⎿ line under it saying what came back; Ctrl+O shows the full input and result of the calls still on screen. A task list stays pinned above the prompt (Ctrl+T folds it). A tool set to ask, and every MCP tool until you allow it, waits for your answer — allow once, for this chat, always, or deny — and a question from the model is answered with the arrow keys and Enter. If an MCP server needs signing in again mid-chat, Ctrl+R reconnects it.

A chat can hand work to a background task (epic #340). The model starts a helper — a subagent, on a type you describe as a mode in the web app — and each task is a card in the transcript, where the call that started it was: the status, the type, the description the parent gave it, what the child has spent, the child's own activity as it works, what the two have said to each other and the task's result. /agents lists this chat's tasks and is the way in and out of them — Enter opens a task's own chat, Enter on the row at the top goes back up, and s stops the highlighted task while it is still working: a finished one is not something to stop, and oh says so rather than flipping it to stopped. A child's chat is a full chat, with the normal composer and a breadcrumb line naming the chain down to it; Esc in one stops that child's turn, which is the one thing a reader does to a helper (Ctrl+C still interrupts, and still leaves oh on the second idle press). A child's output is drawn as plain text: the terminal escape sequences a page or an MCP server could have left in it are stripped before anything is measured, so a helper cannot retitle the window or clear the screen you are reading in.

oh modes marks a subagent type — a mode with a description — and prints that description read-only under the mode's line, with a note saying so: oh does not edit modes, and a description is what a parent model chooses a type by, so the web app's Settings → Modes is where one is written. The four calls that start, steer and stop a task — agent, agent_message, agent_stop and a child's message_parent — take allow or deny and never ask, because a task is drawn as a card rather than a call line and nothing a client could show would answer the pause: oh tools --policy ask agent is refused before it writes anything, and /tools' ←/→ skips ask on those rows. agent_wait is unaffected — its pause is a task wait.

When a chat's context fills up, the server summarizes the older history and the chat carries on from the summary and the recent messages; the transcript keeps the whole conversation, with a "Conversation summarized" divider. The status line shows how full the context is ("62% of context used") and "Summarizing… 2 of 3" while a summary is being made. oh settings changes when this happens (a share of the model's context), which model writes the summary, and how many passes it may take — the same settings as the web app's Settings → Context.

The session token is stored per server in ~/.config/openharness/credentials.json (mode 0600). oh logout revokes it server-side and forgets it locally.

Your provider keys are not stored on this machine. A key typed into oh providers add goes over HTTPS to the same credentials API the web app uses, is validated once against the provider, and is stored encrypted on the server — oh keeps no copy, and the prompt that takes it echoes nothing.

Updating

Installed with npm i -g @openh/cli, oh keeps itself current: at most once an hour it asks npm for the published version and, when that one is newer, installs it for the next run — in the background, without interrupting the chat you are in. The next run prints one line about how it went. Because the package is a single self-contained file, the copy running right now is never the one that changes.

The check runs in a process of its own, detached from the one you started it with, so it sees itself through whether or not the command you typed sticks around: oh whoami sets an update in motion just as a long chat does. A check that fails — no network, no answer from npm — is not counted as this hour's: the next run asks again.

oh update     # the same thing now, in the foreground, with npm's own progress

Turn the background update off with any of: OH_NO_AUTO_UPDATE=1 in the environment, "autoUpdate": false in ~/.config/openharness/config.json, or running in CI. It is also inert when oh was not installed globally (for example, run from a checkout) — oh update says so and stops. What it remembers between runs lives in ~/.config/openharness/ (update-state.json and update.log), beside the config and credentials files.

Links

MIT © Amir Tuval