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

@paragraph-com/cli

v0.4.0

Published

CLI for Paragraph

Readme

@paragraph-com/cli

Command-line interface for Paragraph. Designed for both human and programmatic (agent) usage.

Install

npm install -g @paragraph-com/cli

Or via Homebrew:

brew tap paragraph-xyz/tap && brew install paragraph

Quick start

# Authenticate
paragraph login

# Create a post
paragraph post create --title "My Post" --file ./draft.md

# Publish it
paragraph post publish my-post

# List your posts
paragraph post list

Run paragraph --help to see all commands, or paragraph <command> --help for details on any command.

Authentication

Get your API key from paragraph.com/settings -> Publication -> Developer.

# Interactive login (opens browser or prompts for key)
paragraph login

# Provide token directly
paragraph login --token <your-api-key>

# Pipe token from stdin (useful for CI/agents)
echo "<your-api-key>" | paragraph login --with-token

# Or skip login — pass the key per-command via env var
PARAGRAPH_API_KEY=<your-api-key> paragraph post list

# Verify
paragraph whoami

# Remove stored credentials
paragraph logout

Credentials are stored in ~/.paragraph/config.json (mode 0600). If an API key is revoked, the CLI automatically clears the stored credentials on the next 401 response.

Commands

Posts

# List your posts (requires auth)
paragraph post list
paragraph post list --status draft
paragraph post list --limit 50 --cursor <cursor>

# List posts from any publication (public)
paragraph post list --publication <id-or-slug>

# Get a post -- accepts ID, URL, or @publication/slug
paragraph post get <post-id>
paragraph post get @yearn/some-post-slug
paragraph post get https://paragraph.com/@yearn/some-post-slug

# Extract a single field (outputs raw value to stdout, pipeable)
paragraph post get <id> --field markdown > post.md
paragraph post get <id> --field title

# Browse posts
paragraph post by-tag defi --limit 20
paragraph post feed --limit 10

# Create a post (defaults to draft)
paragraph post create --title "My Post" --text "# Hello World"
paragraph post create --title "My Post" --file ./draft.md
cat draft.md | paragraph post create --title "From Stdin"
paragraph post create --title "Post" --text "Content" --subtitle "Summary" --tags "web3,defi"

# Update a post
paragraph post update <id-or-slug> --title "New Title"
paragraph post update <id-or-slug> --file ./updated.md --tags "new,tags"

# Lifecycle
paragraph post publish <id-or-slug>                  # publish a draft
paragraph post publish <id-or-slug> --newsletter     # publish + send email to subscribers
paragraph post draft <id-or-slug>                    # revert to draft
paragraph post archive <id-or-slug>                  # archive

# Preview before acting
paragraph post publish <id-or-slug> --dry-run
paragraph post delete <id-or-slug> --dry-run

# Send test newsletter email (draft only)
paragraph post test-email <id>

# Delete a post
paragraph post delete <id-or-slug>
paragraph post delete <id-or-slug> --yes             # skip confirmation (required for agents/CI)

Top-level shortcuts:

paragraph create --title "Quick Post" --text "Content"
paragraph update my-post-slug --title "Updated"
paragraph delete my-post-slug --yes

Content

Drafted short-form content: X posts and threads, LinkedIn posts, one-off emails, and X Articles. These commands only draft — nothing is posted, emailed, or scheduled. Send the piece from the Paragraph app.

# Create a draft -- --kind is tweet, linkedin, newsletter, or x_article
paragraph content create --kind tweet --title "Launch note" --text "We shipped it."
paragraph content create --kind tweet --title "Thread" --tweet "First." --tweet "Second."
paragraph content create --kind linkedin --title "Launch note" --file ./post.md
paragraph content create --kind newsletter --title "October update" --subject "What we shipped" --file ./body.md
paragraph content create --kind x_article --title "Editor rewrite" --headline "Why we rebuilt the editor" --file ./article.md
cat post.md | paragraph content create --kind linkedin --title "Launch note"

# List -- --status defaults to all, which excludes archived pieces
paragraph content list
paragraph content list --kind tweet --status draft --limit 50
paragraph content list --status archived

# Get one piece, with its body
paragraph content get <id>
paragraph content get <id> --field body

# Rename, replace the body, or both. The body is replaced, not merged.
paragraph content update <id> --title "Launch note, second pass"
paragraph content update <id> --text "Rewritten, and shorter."

# Archive and restore
paragraph content archive <id>
paragraph content archive <id> --dry-run
paragraph content restore <id>

Content groups

A group is one identity for a post and everything made out of it — the post, the thread drawn from it, the LinkedIn version, the newsletter. It's what a writer sees as a single stacked row under Content in the Paragraph app.

Seed the group from the post, then draft into it with --bucket:

# Get or create a post's group. Safe to repeat: the same ID comes back.
paragraph content bucket create <post-id>

# Draft into it
paragraph content create --kind tweet --title "Thread" --tweet "First." --bucket <bucket-id>

# Group a draft you made earlier. A piece already grouped with a different
# post is refused rather than moved -- ungroup it in the app first.
paragraph content update <id> --bucket <bucket-id>

# Read
paragraph content bucket list
paragraph content bucket get <bucket-id>
paragraph content bucket for-post <post-id>

Taking a piece back out of a group is done in the app.

Publications

# Get publication -- accepts ID, slug, or custom domain
paragraph publication get @variantwriting
paragraph publication get blog.variant.fund
paragraph publication get <publication-id>

Search

paragraph search post --query "ethereum"
paragraph search blog --query "web3"

Subscribers

paragraph subscriber list --limit 100
paragraph subscriber count <publication-id>
paragraph subscriber add --email [email protected]
paragraph subscriber import --csv subscribers.csv

Coins

paragraph coin get <id-or-address>
paragraph coin popular --limit 10
paragraph coin search --query "test"
paragraph coin holders <id-or-address> --limit 50
paragraph coin quote <id-or-address> --amount <wei>

Users

paragraph user get <user-id>
paragraph user get 0x1234...    # by wallet address

Interactive TUI

Running paragraph with no arguments launches an interactive terminal UI with menus, scrollable lists, and keyboard navigation.

The TUI is disabled automatically when:

  • --json, --help, or --version flags are used
  • stdout is not a TTY (e.g., piped output)
  • CI=true or PARAGRAPH_NON_INTERACTIVE=1 is set

Agent / programmatic usage

The CLI is designed for use by AI agents and scripts.

JSON output

All commands support --json. Data goes to stdout, status messages to stderr, so you can pipe cleanly:

paragraph --json post list | jq '.data[0].title'
paragraph --json post get <id> | jq '.markdown'
paragraph --json search post --query "web3" | jq '.length'

Paginated commands return:

{
  "data": [{ "id": "...", "title": "..." }],
  "pagination": { "cursor": "abc123", "hasMore": true }
}

Single-item commands return the object directly:

{ "id": "...", "title": "...", "markdown": "..." }

Structured errors

In --json mode, errors are structured JSON on stderr with a non-zero exit code:

{ "error": "Not found.", "code": "NOT_FOUND", "status": 404 }

Error codes: UNAUTHORIZED, FORBIDDEN, NOT_FOUND, RATE_LIMITED, SERVER_ERROR, REQUEST_FAILED, CLIENT_ERROR, UNKNOWN.

Flags and stdin

Every identifier accepts both a positional argument and an --id flag, so you can chain commands:

paragraph post get --id $(paragraph --json post list | jq -r '.data[0].id')

Content can come from --text, --file, or stdin:

cat draft.md | paragraph post create --title "My Post"

Non-interactive safety

  • delete requires --yes in non-TTY environments
  • login supports --with-token for stdin piping and --token for direct input
  • Destructive commands support --dry-run to preview without acting
  • Set PARAGRAPH_NON_INTERACTIVE=1 or CI=true to force CLI mode

Environment variables

| Variable | Purpose | |----------|---------| | PARAGRAPH_API_KEY | API key (alternative to login) | | PARAGRAPH_API_URL | Custom API base URL | | PARAGRAPH_NON_INTERACTIVE | Set to 1 to disable TUI | | CI | Set to true to disable TUI |


Development

git clone https://github.com/paragraph-xyz/paragraph-cli.git
cd paragraph-cli
npm install
npm run build
npm run dev         # watch mode
npm test

Requires Node.js >= 18.

Releasing

npm run release patch   # 0.1.0 → 0.1.1
npm run release minor   # 0.1.0 → 0.2.0
npm run release major   # 0.1.0 → 1.0.0

Builds, tests, publishes to npm, creates a GitHub release, and updates the Homebrew tap. Requires gh CLI and npm publish access.