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

@sayrio/cli

v0.4.0

Published

Sayr.io command-line interface — manage tasks, comments, and releases from your terminal

Downloads

65

Readme

Full documentation

Overview

The Sayr CLI (@sayrio/cli, binary sayr) wraps the same personal-access-token-authenticated API surface (/v1/me/*) that powers integrations and bots — list, create, and update tasks, manage labels and assignees, post comments, and run your releases (create, update, publish, and manage their labels, status updates, comments, and linked pull requests), all without opening a browser.

Installation

npm install -g @sayrio/cli
sayr --help

Prefer a one-off run without a global install? Use npx -p @sayrio/cli sayr --help. The package ships two commands (sayr and sayr-local), so plain npx @sayrio/cli can't pick one to run.

Authentication

The CLI authenticates with a personal access token, the same kind used by any other API client (see the Public API & SDK docs). Generate one from your Sayr account settings, then log in:

sayr login --token api_xxxxxxxx

Omit --token and you'll be prompted to paste it instead. Pass --base-url to point at a self-hosted instance or a local dev server — it defaults to https://api.sayr.io:

sayr login --token api_xxxxxxxx --base-url https://api.your-instance.com

Credentials are written to ~/.sayr/config.json (owner-readable only). sayr logout clears them. SAYR_TOKEN and SAYR_BASE_URL environment variables override the stored values for a single command without touching the file — handy in CI.

Working against a second backend (e.g. a local dev instance)

~/.sayr/config.json holds one login at a time. To keep a separate one — most commonly a local sayr backend running against its own database, alongside your normal production login — use sayr-local instead of sayr for those commands. It's the same CLI with SAYR_PROFILE=local pre-set, which reads/writes ~/.sayr/config.local.json instead:

sayr-local login --token api_xxxxxxxx --base-url http://localhost:5468
sayr-local task list --org platform

sayr (unprefixed) is completely unaffected — the two configs never interact. SAYR_PROFILE=<name> works the same way directly if you want more than two (~/.sayr/config.<name>.json).

Configuration

Most commands need an organization. Set a default once instead of passing --org <slug> on every command:

sayr config set-org platform
sayr config get             # show the current config (token is truncated)
sayr config set-base-url http://localhost:5468

Commands

| Command | What it does | | ------------------------------------------------------------------- | ------------------------------------------------------------------------------- | | sayr login [--token] [--base-url] | Authenticate and store credentials | | sayr logout | Clear stored credentials | | sayr whoami | Show the authenticated user | | sayr orgs list | List organizations you belong to | | sayr categories list | List an organization's categories | | sayr labels list | List an organization's labels | | sayr labels create <name> | Create a label (or return the existing one with that name) | | sayr task create <title> | Create a task | | sayr task list | List tasks — search, filter, sort, paginate | | sayr task view <taskId> | Show a single task, its AI summary (if any), and recent comments | | sayr task update <taskId> | Update title, status, priority, category, release, or visibility | | sayr task label <taskId> --set <ids> | Replace a task's full set of labels | | sayr task assign <taskId> --set <ids> | Replace a task's full set of assignees | | sayr comment list <taskId> | List a task's top-level comments, paginated | | sayr comment replies <commentId> | List replies to a top-level comment, paginated | | sayr comment create <taskId> <content> | Post a comment on a task | | sayr comment update <commentId> <content> | Edit a comment | | sayr comment delete <commentId> | Delete a comment | | sayr releases list | List an organization's releases, optionally by --status | | sayr releases view <release> | Show a release: progress, labels, pull requests, tasks, latest status update | | sayr releases create <name> | Create a release | | sayr releases update <release> | Update a release's name, slug, description, status, dates, color, icon, or lead | | sayr releases publish <release> | Mark a release released and close its open tasks as done | | sayr releases delete <release> | Delete a release — its tasks are unlinked, not deleted | | sayr releases label <release> | Add and/or remove labels on a release with --add / --remove | | sayr releases status-update list <release> | List a release's status updates | | sayr releases status-update create <release> [content] | Post a status update with a --health and Markdown content | | sayr releases status-update update <release> <updateId> [content] | Edit a status update | | sayr releases status-update delete <release> <updateId> | Delete a status update | | sayr releases comment list <release> | List a release's top-level comments, paginated | | sayr releases comment replies <commentId> | List replies to a release comment | | sayr releases comment create <release> <content> | Post a comment (or a reply) on a release | | sayr releases comment update <commentId> <content> | Edit a release comment | | sayr releases comment delete <commentId> | Delete a release comment | | sayr releases pr list <release> | List the pull requests linked to a release | | sayr releases pr link <release> <prUrl> | Link a GitHub pull request to a release | | sayr releases pr unlink <release> <prUrl> | Unlink a pull request from a release |

Every command accepts --json for scriptable output, and sayr <command> --help prints its full flag list.

<release> is a release's slug or id — sayr releases list shows both. The same value works for --release on task create, task update, and task list; task update --no-release takes a task out of its release. Release descriptions, status updates, and release comments accept Markdown on both create and update.

releases publish and releases delete can't be undone, so they ask for confirmation first. With --yes they skip the prompt; without a terminal, or together with --json, they refuse to run unless you pass --yes. Note that releases update --status released only changes the status — releases publish is what also closes the release's open tasks. Publishing a release that's already released closes any tasks still open, and does nothing if there are none.

Guided mode

At a terminal, a command that's missing something it needs asks for it, with pickers filled in from your organization, instead of failing — nothing to look up or paste:

  • sayr task create with no title asks for one, then offers to add a description, status, priority, category and release.
  • sayr task update <taskId> with no field flags shows the task and asks what to change: title, status, priority, category, release or visibility.
  • sayr task label <taskId> with no --set lists the organization's labels with the task's current ones ticked.
  • sayr releases create with no name asks for the name, status and target date, then offers a slug, description and colour.
  • sayr releases update <release> with no field flags asks what to change: name, slug, description, status, target date, released date or colour. Type none to clear a date.
  • Any command with no --org and no default organization asks which one — or just uses it, if you belong to only one. sayr config set-org <org> makes it stick.

Guided mode only fills in what's missing. A command you've fully specified runs exactly as it always did, and the prompts never appear with --json, when stdin or stdout isn't a terminal (scripts, CI, pipes, agents), or when SAYR_NO_INTERACTIVE is set (SAYR_NO_INTERACTIVE=1 is the usual form; empty, 0, false, no and off leave prompts on); in those cases you get the same errors as before. Ctrl+C or Esc at any prompt cancels ("Cancelled.", exit code 1) before anything is written. When a guided run succeeds, the CLI prints the flag-based command that does the same thing, so the next one can skip the prompts.

$ sayr task update 79
SAY-79  Fix the flaky deploy check
◇  What do you want to change?
│  Status, Priority
◇  New status
│  done
◇  New priority
│  high
✓ Updated Fix the flaky deploy check
Tip: sayr task update 79 --org platform --status done --priority high

Names instead of ids

Wherever a category or label id was needed, a name works too — --category on task create, task update and task list, task label --set, and releases label --add / --remove. Names are matched exactly, ignoring case (--category bug finds "Bug"). A name that matches nothing is an error that lists the names your organization has; one that matches several asks you to use the id instead. Anything that already looks like an id is sent as it is, without a lookup, so existing commands and scripts are unchanged.

sayr task create "Fix login" --category Bug
sayr task label 123 --set "Backend,Needs review"
sayr releases label v1-2-0 --add Backend --remove Frontend

Examples

Create a task and check the queue:

sayr task create "Fix the flaky deploy check" --priority high --status todo
sayr task list --sort newest --limit 5

Move a task through statuses and assign it:

sayr task update 123 --status in-progress
sayr task assign 123 --set <user-id>

Comment from a script, with machine-readable output:

sayr comment create 123 "Deploy finished successfully." --json

Ship a release — create it, move tasks in, check progress, then publish:

sayr releases create "v1.2.0" --target-date 2026-10-31 --status in-progress
sayr task update 123 --release v1-2-0
sayr task update 124 --release v1-2-0
sayr releases view v1-2-0
sayr releases publish v1-2-0 --yes

publish marks the release released and closes its remaining open tasks as done. Drop --yes at a terminal to be asked first.

Permissions

The CLI can only do what your personal access token's scopes — and your own role in the organization — allow. Reading tasks and releases needs tasks.read, creating tasks needs tasks.create, commenting (on tasks and on releases) needs tasks.comment, and so on down to content.manageLabels, tasks.assign, tasks.changeStatus, tasks.changePriority, and tasks.editAny. Anything that changes a release — creating, editing, publishing, and deleting it, and managing its labels, status updates, and linked pull requests — needs content.manageReleases, and you need the Manage releases permission in the organization too. Editing or deleting someone else's release comment needs moderation.manageComments. A key is always a ceiling, never a grant — it can never do more than its owner can, and it can never touch member, team, or billing management no matter what scopes it's given.

releases publish and releases delete need --yes whenever they can't ask you (no terminal, or --json). Keys that already hold content.manageReleases, including full-access keys, can now change releases through the CLI and the API. Keys that hold tasks.comment (including the task-management preset) can now comment on releases too, and keys with moderation.manageComments can edit or delete other people's release comments — narrow or revoke them if that isn't what you want.