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

@corpus-tool/cli

v0.21.0

Published

The Corpus CLI: push a repository's structured text to a Corpus instance and pull verified translations back, format-preserving.

Readme

@corpus-tool/cli

The corpus command for Corpus, a self-hosted translation workbench for games and apps whose text is structured. The CLI runs inside the repository whose text is translated. Node 22 or later.

Quick start

npm install --save-dev @corpus-tool/cli @corpus-tool/workbench
npx corpus init --project my-game --source en \
  --messages "src/i18n/{lang}.json" --server http://localhost:3000
npx corpus workbench      # starts the instance, creates the project, writes .corpus/token
npx corpus push           # the repository's strings, and the translations it already has
npx corpus pull           # verified translations back into the repository's files

A source's path names one file per language with {lang}, a .json (a browser extension's _locales/{lang}/messages.json under library: "chrome") or Flutter's .arb; an android source names an app's res directory, whose values-<qualifier>/strings.xml are its languages, a fluent source Project Fluent's .ftl files, an xliff source XLIFF 1.2 or 2.0 as Angular writes it, with sourcePath for a source file whose name holds no language, a gettext source .po files, with the .pot as sourcePath, an xcstrings source Apple's String Catalog, one file for every language, a qt-ts source Qt Linguist's .ts files, and a yaml source Rails I18n's YAML. A messages, table or fluent source's path may be an array of such patterns, one catalogue the app merges, with merge: "last-wins" where a later file overrides an earlier one (the default, "strict", wants the files that hold a string to agree on it), and a pattern may carry {ns}, one or more segments, for one file per namespace (locales/{lang}/{ns}.json) or per component (src/{ns}/i18n/{lang}.json), whose ids are ns:key. init writes corpus.config.ts (a plain corpus.config.mjs when the package is not installed in the repository) and adds .corpus/ to .gitignore, creating the file when there is none, as workbench does too; it reads the languages from the files that fill {lang} and the library from the source file (more {{ }} strings than single-brace or printf ones, with no ICU argument, is i18next; printf verbs, %s and %[2]d, are printf; a top-level pipe or a {'…'} literal, with neither, is vue-i18n; a file of Chrome i18n entries is chrome; %(name)s placeholders outnumbering every other shape are counterpart, Element's; a {} or an @:key link is Flutter's easy_localization; %{name} placeholders are rails), or takes --languages and --library <icu|i18next|vue|printf|chrome|counterpart|easy_localization|rails>, and writes check.include from the directories that hold components. workbench starts an instance from the companion package, creates the project the config declares and writes the token to .corpus/token. Open the URL, join with the printed secret, translate and verify; pull writes the verified rows back, format-preserving, and a second pull changes nothing. For a team's instance, CORPUS_INVITE_SECRET=<secret> npx corpus project create prints the project's token once, for CORPUS_TOKEN or .corpus/token. A package manager with a release-age policy holds back a version published inside its window, and the three write it differently: pnpm's minimumReleaseAge in pnpm-workspace.yaml, yarn's npmMinimalAgeGate in .yarnrc.yml, npm's min-release-age in .npmrc. Each has an allow list for the packages a team trusts on release day: minimumReleaseAgeExclude, npmPreapprovedPackages and min-release-age-exclude[], where @corpus-tool/cli and @corpus-tool/workbench are worth naming once. Yarn 4.18 holds a same-day version back with no gate configured (quarantined), and yarn and npm refuse the install outright; pnpm installs the fresh version and writes the exclusion into pnpm-workspace.yaml itself, pinned to that version and saying so, unless minimumReleaseAgeStrict is on, when it asks first, or fails where there is no terminal to ask. Otherwise install the previous release, or wait the window out. A repository whose tree is heavy can run every command from the npm cache instead, npx --package=@corpus-tool/cli --package=@corpus-tool/workbench corpus <command>, with a plain corpus.config.mjs; pnpm's verifyDepsBeforeRun stops pnpm corpus when a build script was ignored, where pnpm exec corpus runs it.

The wiki is the manual: install and first push, the config file, each i18n library, CI, the MCP server and a translator's guide.

The commands

  • corpus push [--dry-run]: the repository's strings into Corpus by id; the translations the repository's target-language catalogues already hold travel too, and so does what an exec exporter emits as translations; both land where Corpus has no edit of its own.
  • corpus pull [--min-state <s>] [--lang <l>]... [--check]: verified translations (or looser) back into the files, and pending source proposals into the source files; --check lists what would change and exits 1 if anything would. An exec source's importCommand receives on stdin only the rows this pull selected, never the whole catalogue, so it must merge them into its file and leave every other entry alone: a command that rewrites its file from the payload loses every row the pull did not select.
  • corpus status [--json]: the dashboard's numbers, the writable sources, the pending proposals.
  • corpus validate [--json]: every translation still fits its source, offline. corpus check: no user-facing literal outside the declared sources, over .jsx, .tsx and .vue.
  • corpus build [--out <file>]: the snapshot with no server, for authoring the config.
  • corpus project create | rotate-token, corpus init, corpus workbench.

Work with an agent

corpus mcp is a Model Context Protocol server on stdio for any MCP client: Claude Code, Claude Desktop, Cursor, VS Code, OpenAI's Codex CLI or Agents SDK, Gemini CLI, or an agent of your own. The command is npx corpus mcp, started in the repository, registered before the session starts; the repository README shows each client's entry. In Claude Code:

claude mcp add corpus -- npx corpus mcp

corpus agent is the same operations as shell commands (queue, string, draft, propose, add, proposals, withdraw, status), and corpus agent --stdin runs many of them through one process, one JSON object per line in and one JSON line per operation out. Each line names its op and carries the operation's arguments by name: queue with queue (untranslated, stale, unverifiedSource or agentDrafts) and, optionally, language and type; string with key; draft with key, language and text; propose with key and text; remove with key; add with key, file and text; withdraw with proposal; proposals and status with none; an optional id is echoed back on the answer. An agent reads queues and strings as the editor shows them, saves drafts and proposes source changes, under three rules: it never overwrites a person's work, every draft is attributed, and only a signed-in maintainer verifies. The instance must run the same version as the CLI, and a project pushed before 0.7.0 needs one push before proposals know where to go.

In CI

A job with CORPUS_TOKEN can gate a merge: corpus check, corpus validate, corpus pull --check, and corpus status --json for the numbers.

Every command but init executes the repository's own corpus.config.ts, and push, build and pull run the exec commands it declares, by design: run them only in repositories you trust, as you would their build scripts. The full guide, the design spec and the changelog live in the repository.