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

@every-env/spiral-cli

v1.11.0

Published

CLI for Spiral API - generate writing in your voice

Readme

@every-env/spiral-cli

A command-line interface for Spiral, the agent that writes in your voice.

Quickstart

npx @every-env/spiral-cli@latest login
spiral write "a tweet about shipping fast" --instant

That's it. login opens a browser to authenticate, write produces a draft in your voice.

Installation

# Run directly (no install needed)
npx @every-env/spiral-cli@latest --help

# Or install globally
npm install -g @every-env/spiral-cli

Requires Node.js >= 18.

Authentication

Browser sign-in (recommended)

# Print the sign-in link and open it in your browser
spiral login

# Or pass an API key directly
spiral login --token spiral_sk_...

# Check status
spiral auth status

# Logout
spiral logout

spiral login prints the sign-in URL and opens it in your browser, then waits for you to approve. If the browser can't open (e.g. over SSH), just paste the printed URL. No code to copy back — the token is delivered straight to the CLI once you approve.

spiral login and spiral logout are shortcuts for spiral auth login and spiral auth logout — use whichever reads better.

Get your API key at app.writewithspiral.com/settings/api-keys.

Agent sign-in (no API key in the transcript)

When an AI coding agent runs the CLI, it can sign its human in without ever handling an API key — so no spiral_sk_... key leaks into the chat transcript, tool logs, or session history.

# 1. Agent starts a sign-in and gets a shareable link (non-blocking, exits 0).
spiral login --json
# → { "status": "pending",
#     "auth_url": "https://app.writewithspiral.com/connect?user_code=ABCD-2345",
#     "user_code": "ABCD-2345",
#     "expires_in": 900,
#     "poll_command": "spiral auth status --json" }

# 2. Agent hands `auth_url` to its human, who opens it and approves in a browser.

# 3. Agent polls status until the token lands (it claims the token for you).
spiral auth status --json
# → { "authenticated": false, "status": "pending", "auth_url": "..." }   (still waiting)
# → { "authenticated": true,  "status": "authenticated", "source": "stored" }  (done)

spiral auth status opportunistically completes a pending sign-in: once the human approves, the next status call claims the token, stores it locally, and reports authenticated: true. Subsequent spiral write calls then just work.

If a credential is already present (a prior spiral login or SPIRAL_TOKEN), spiral login --json returns { "status": "already_authenticated", "authenticated": true, "prefix": "..." } and starts no new flow — there's nothing to approve. To sign in as a different account, run spiral logout first. So an agent should treat both already_authenticated and a later authenticated: true from auth status as "done."

This path is auto-selected whenever the CLI isn't attached to an interactive terminal (which is how agents run it). Use --no-browser to force it from a real terminal too (prints the link as text instead of opening a browser), and --json for machine-readable output. The existing --token, SPIRAL_TOKEN, and spiral setup --pairing-code paths are unchanged.

Environment variable

For CI/CD and agent environments:

export SPIRAL_TOKEN=spiral_sk_...

SPIRAL_TOKEN takes precedence over any token stored by spiral login, so you can override locally-stored credentials without logging out.

Usage

Write content

spiral write "a blog post about shipping fast"         # Interactive (may ask questions)
spiral write "a tweet about AI" --instant               # Skip clarifying questions
spiral write "make it shorter" --session <id>           # Refine existing drafts
spiral write "..." --style <id> --workspace <id>        # With style and workspace
spiral write "..." --num-drafts 3                       # Multiple variations
spiral write "..." --instant --json                     # Machine-readable output
echo "prompt" | spiral write --instant --json           # Piped input

Set up your voice

Spiral writes in your voice. Give it a few writing samples so drafts sound like you from the first one — no per-request style wrangling.

spiral onboard                                        # Check voice setup and how to finish it
spiral samples                                        # List your writing samples
spiral samples add "a paragraph you actually wrote"   # Add a text sample
spiral samples add https://yourblog.com/a-post        # A URL → one sample
spiral samples add https://yourblog.com --site        # --site crawls the whole site into samples
cat draft.md | spiral samples add                     # Pipe text in

Samples added at the workspace root feed Auto Style, so every spiral write leans on them automatically — pin a specific --style only when you want a particular voice. Target a named style or team workspace with --style <id> / --workspace <id>. spiral onboard reports whether you have enough to write in voice yet and what to add next (add --json for agents).

Create a named style or a new workspace to organize voices, samples, and prompts:

spiral styles create "Punchy LinkedIn" --channel linkedin   # New empty style
spiral samples add "a post you wrote" --style <id>          # then add samples to it
spiral workspaces create "Client A" --description "Work for A"
spiral workspaces create "Acme" --team <team-id>            # team workspace (needs a team plan)

A new style starts empty; add the user's writing with spiral samples add --style <id>. A workspace groups styles, samples, and prompts (one per client or project); pass its id to --workspace on later commands (e.g. spiral samples add "..." --workspace <id>). A style id goes to --style, a workspace id to --workspace; they are not interchangeable.

Personalize and humanize existing text

Two single-shot commands for transforming text you already have. Both never ask clarifying questions, take ~3-8 seconds, and accept positional input or piped stdin. Use them when you don't need a full draft — just a voice swap or a clean-up.

# Rewrite text in your unique writing voice (uses your Spiral style guide).
spiral personalize "their text here"
spiral personalize "their text" --style <id>            # Use a specific style
spiral personalize "their text" --channel x             # Hint a channel-specific style
echo "their text" | spiral personalize                  # Or pipe from anywhere

# Apply your writing rules + remove AI tells (em-dashes, "delve",
# hype words). No voice rewrite — just mechanical cleanup.
spiral humanize "their text here"
pbpaste | spiral humanize | pbcopy                      # Clean what's on the clipboard

By default both print plain text to stdout — perfect for piping. Add --json for the full response — personalize returns { text, style_used, quota_remaining }, humanize returns { text, quota_remaining } (no style_used, since there's no voice rewrite).

When in doubt: personalize includes the humanize cleanup as its final step, so reach for humanize only when you specifically don't want a voice rewrite.

Browse resources

spiral styles                  # List writing styles
spiral workspaces              # List workspaces
spiral prompts                 # List saved prompts (reusable templates)
spiral prompts get <command>   # Print a saved prompt's text
spiral sessions                # List past conversations
spiral drafts --session <id>   # View drafts from a session
spiral quota                   # Check session quota and plan
spiral prime                   # Full API documentation

Saved prompts are reusable templates you create in the Spiral app (they appear there as /slash-commands). Write with one by passing its command to --prompt; Spiral prepends the template server-side, and an unknown command fails fast with the list of available commands:

spiral write "This week: our v2 launch." --prompt blog-intro

spiral prompts get <command> prints a template's raw text when you want to pipe it somewhere else.

Agent setup

For AI agents (Claude Code, Plus One, etc.), copy the install command from Settings → Agents and paste it into your agent. The command looks like:

spiral setup --pairing-code <single-use-code>

The pairing code is single-use and expires in 15 minutes. The CLI exchanges it for a fresh API key the first time it runs — no long-lived secret in the install command itself.

The legacy spiral setup --token spiral_sk_... form still works for older install commands that already embedded a raw key.

This validates the resulting key and prints a memory block for the agent to save. The block tells the installing agent when to reach for each command — write for new content, personalize for "rewrite in my voice" requests, humanize for "remove AI tells" requests — so the agent picks the right tool without the user having to spell it out every time.

File attachments

Pass reference documents directly via --file (repeatable):

spiral write "Turn this into a blog post" --file quarterly-report.xlsx --instant
spiral write "Compare these two decks" --file deck-a.pdf --file deck-b.pdf --instant

Supported formats: PDF, DOCX, PPTX, XLSX, HTML, EPub, TXT, MD, CSV, JSON, XML. Max 5 files, 10MB each. Spiral extracts text automatically — no need to paste file contents into the prompt.

Flags

| Flag | Description | |------|-------------| | --json | Machine-readable JSON output | | --session <id> | Session ID for multi-turn / refinement | | --style <id> | Writing style ID | | --workspace <id> | Workspace ID | | --file <path> | Attach a file (PDF, DOCX, XLSX, etc.) — repeatable | | --instant | Skip clarifying questions | | --num-drafts <n> | Number of drafts (1-5, default 1) | | --channel <c> | Channel hint (x, linkedin, blog, ...) for personalize and styles create | | --description <t> | Description for styles create / workspaces create | | --team <id> | Team UUID for workspaces create (creates a team workspace) | | --token <key> | API key for auth/setup | | --no-browser | login: print the sign-in link and exit instead of opening a browser (agent path) | | --debug | Show debug info on errors | | --help, -h | Show help | | --version, -v | Show version |

Agent-native usage

spiral-cli is designed to work in any environment — terminals, Docker containers, subprocess shells, CI pipelines. In non-interactive environments (no TTY), it automatically:

  • Skips spinners and terminal animations
  • Outputs plain text without ANSI color codes
  • Returns raw markdown instead of terminal-formatted text
  • Times out stdin reads to avoid hanging
# Typical agent workflow
spiral prime                                            # Get API docs
spiral onboard --json                                   # Confirm the user's voice is set up first
spiral styles --json                                    # Discover styles
spiral write "a launch tweet" --instant --json           # Generate content
spiral write "make it punchier" --session <id> --json    # Refine
spiral personalize "$USER_TEXT" --json                   # Rewrite in user's voice
spiral humanize "$USER_TEXT" --json                      # Strip AI tells, no voice rewrite

Exit codes

| Code | Meaning | |------|---------| | 0 | Success | | 1 | General error | | 2 | Authentication required | | 3 | API error (quota, rate limit, timeout) | | 4 | Network error | | 5 | Invalid arguments |

Subscription required

The Spiral API is paid-only. Each call to spiral write, spiral personalize, or spiral humanize requires:

  1. An authenticated session (spiral login).
  2. A paid Spiral plan (Personal, Team, or an active Every Bundle subscription).

If a request can't be served, the CLI prints a clear next step:

  • Invalid or expired API key (HTTP 401): Invalid or expired API key. Run \spiral auth login` to re-authenticate.`
  • Free-tier account (HTTP 402): a Stripe Checkout link to subscribe — open it in your browser, complete payment, and re-run your command.
  • Paid plan over quota (HTTP 402, Personal only): a Stripe Checkout link for a one-time top-up. Team and Trial accounts get a clear quota message but no top-up link (those tiers don't support one-off top-ups; subscribe to a Personal plan, wait for the period to reset, or contact your team admin).

In --json mode the same information is returned in structured form so agents can parse it:

{
  "error": "ApiError",
  "message": "A Spiral subscription is required to use the API. Visit app.writewithspiral.com and upgrade to a paid plan.",
  "statusCode": 402,
  "upgrade_url": "https://checkout.stripe.com/c/pay/cs_test_..."
}

When the URL points at Stripe Checkout, the post-payment redirect lands on a public confirmation page that tells the user to return to the CLI — useful when the browser isn't signed in to Spiral, or is signed in as a different account than the CLI's API key.

Environment variables

| Variable | Description | |----------|-------------| | SPIRAL_TOKEN | Auth token (alternative to spiral login; takes precedence when set) | | SPIRAL_API_URL | Override API endpoint (default: https://api.writewithspiral.com) |

Writing styles

Create writing styles at app.writewithspiral.com/writing-styles to customize Spiral's output to match your voice.

License

MIT