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

@housein_isprogramming/arnold-curls

v2.2.0

Published

GraphQL API flow runner with multi-set support - execute flows step-by-step with context passing

Readme

arnold-curls

GraphQL API flow runner with multi-set support. Execute flows step-by-step with context passing and response validation.

Installation

CLI (npm package)

npm install -D @housein_isprogramming/arnold-curls

Then use via npx:

npx arnold init my-api
npx arnold run my-api
npx arnold status my-api

Claude Code Plugin

After installing the npm package, install the Claude Code plugin:

claude /plugin install node_modules/@housein_isprogramming/arnold-curls

Then use the @arnold agent in Claude:

@arnold create a flow to test user registration and login
@arnold run my-api --full

Or use the slash commands:

/arnold-list
/arnold-status my-api
/arnold-run my-api --full

Quick Start

# Initialize a set
npx arnold init my-api

# Edit .arnold/sets/my-api.json with your steps
# Run steps one by one
npx arnold run my-api

# Or run all at once
npx arnold run my-api --full

# Check status
npx arnold status my-api

Commands

npx arnold init <name>              # Create empty set
npx arnold init <name> --from <f>   # Create from existing JSON file
npx arnold init <name> --stdin      # Create from stdin

npx arnold run <name>               # Run next pending step
npx arnold run <name> --full        # Run ALL steps, stop on first error
npx arnold run <name> --step <N>    # Run specific step (0-indexed)

npx arnold preview <name>           # Preview next step (resolved variables)
npx arnold preview <name> --step <N> # Preview specific step

npx arnold status <name>            # Show set status
npx arnold list                     # List all sets
npx arnold reset <name>             # Clear execution state for set
npx arnold reset --all              # Clear ALL execution state

File Structure

.arnold/
├── sets/
│   ├── auth-flow.json     # Set definition (committed)
│   └── user-crud.json     # Set definition (committed)
├── state.json             # Execution state (gitignored)
└── .env                   # Secrets (gitignored)

Set Definition

.arnold/sets/<name>.json:

{
  "name": "auth-flow",
  "baseUrl": "https://api.example.com/graphql",
  "headers": {
    "Authorization": "Bearer ${token}"
  },
  "steps": [
    {
      "name": "Login",
      "query": "mutation { login(user: \"admin\", pass: \"secret\") { token success } }",
      "extractToContext": { "token": "data.login.token" },
      "expected": { "data": { "login": { "success": true } } }
    },
    {
      "name": "Get Profile",
      "query": "query { me { id name } }"
    }
  ]
}

Step Fields

| Field | Description | |-------|-------------| | name | Step display name | | query | GraphQL query/mutation | | variables | Optional query variables | | extractToContext | Extract values to context for later steps | | expected | Validate response (subset match) |

Context Variables

Use ${varName} in queries, variables, or headers:

{
  "headers": { "Authorization": "Bearer ${token}" },
  "steps": [
    {
      "name": "Login",
      "query": "mutation { login { token } }",
      "extractToContext": { "token": "data.login.token" }
    },
    {
      "name": "Protected Query",
      "query": "query { secretData { value } }"
    }
  ]
}

Environment Variables

Create .arnold/.env for secrets:

API_KEY=your-api-key
AUTH_TOKEN=bearer-token
# Comments supported
  • .env values override context values
  • Add to .gitignore (contains secrets)

Output Format (JSON)

run (single step)

{
  "step": "Login",
  "index": 0,
  "status": "done",
  "duration": 234,
  "result": { "data": { "login": { "token": "abc" } } },
  "context": { "token": "abc" },
  "remaining": 1
}

run --full (success)

{
  "set": "auth-flow",
  "status": "done",
  "steps": [...],
  "duration": 567
}

run --full (error)

{
  "set": "auth-flow",
  "status": "error",
  "stoppedAt": 1,
  "error": "connection refused",
  "completedSteps": [...]
}

status

{
  "name": "auth-flow",
  "baseUrl": "...",
  "pending": 2,
  "done": 1,
  "failed": 0,
  "errors": 0,
  "steps": [...]
}

list

{
  "sets": [
    { "name": "auth-flow", "pending": 2, "done": 1, "failed": 0, "errors": 0 }
  ]
}

Response Validation

Add expected for subset matching:

{
  "name": "Login",
  "query": "mutation { login { success } }",
  "expected": { "data": { "login": { "success": true } } }
}
  • Response must contain expected values (extra fields OK)
  • On mismatch: status becomes failed with validationError
  • Context extraction still runs (data exists)

Testing

bun test

License

MIT