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

@zibby/skills

v0.1.3

Published

Built-in skill definitions for Zibby test automation framework

Readme

@zibby/skills

Skill definitions for the Zibby test automation framework.

A skill is the contract between a workflow node and a tool. It tells the framework what the tool does, how to start it, and what it needs. The framework never hardcodes any skill by name — it reads the skill definition and wires things up generically for both Claude and Cursor agents.

Quick start

npm install @zibby/skills

Import the package to register all built-in skills:

import '@zibby/skills';

The skill() factory

One function to create any skill. Auto-detects the type and auto-registers.

Function skill

One skill = one tool. Flat, no nesting.

import { skill } from '@zibby/skills';

export const add = skill('add', {
  description: 'Add two numbers',
  input: { a: 'number', b: 'number' },
  handler: async ({ a, b }) => ({ result: a + b })
});

Use it in a node:

export const mathNode = {
  name: 'do_math',
  skills: ['add'],
  prompt: (state) => `Add ${state.a} and ${state.b}`,
};

MCP skill

For wrapping existing MCP server packages:

import { skill } from '@zibby/skills';

export const linear = skill('linear', {
  envKeys: ['LINEAR_API_KEY'],
  description: 'Linear issue tracker',
  resolve() {
    if (!process.env.LINEAR_API_KEY) return null;
    return {
      command: 'npx',
      args: ['-y', '@modelcontextprotocol/server-linear'],
      env: { LINEAR_API_KEY: process.env.LINEAR_API_KEY },
    };
  }
});

Built-in skills

| ID | Server | MCP Package | |----|--------|-------------| | browser | playwright | @zibby/mcp-browser / @playwright/mcp | | jira | jira | @zibby/mcp-jira | | github | github | @modelcontextprotocol/server-github | | slack | slack | @modelcontextprotocol/server-slack |

Function skill API

skill(id, { description, input, handler })
  • id — Unique skill identifier (used in skills: ['add'])
  • description — What the tool does (shown to the LLM)
  • input — Parameter definitions:
{
  param: { type: 'string' },             // full form
  other: 'number',                       // shorthand
  optional: { type: 'string', required: false },
}
  • handler — The function that runs when the tool is called:
handler: async ({ param, other }) => {
  return { result: 'something' };        // any JSON-serializable value
}

Handler rules

  • Must be async (or return a Promise)
  • Receives one object argument with the input parameters
  • Must return a JSON-serializable value
  • Has full access to imports, closures, and the module scope
  • Runs in a child process (the function bridge)

More examples

import { skill } from '@zibby/skills';

export const fetchUrl = skill('fetch_url', {
  description: 'Fetch a URL and return the response body',
  input: { url: 'string' },
  handler: async ({ url }) => {
    const res = await fetch(url);
    return { status: res.status, body: await res.text() };
  }
});

export const healthCheck = skill('health_check', {
  description: 'Check if the service is running',
  handler: async () => ({ status: 'ok', timestamp: Date.now() })
});

MCP skill API

skill(id, config)

Config object:

| Property | Required | Description | |---|---|---| | resolve(options) | Yes | Returns { command, args, env } or null | | serverName | No | MCP server name (defaults to id) | | allowedTools | No | Tool patterns (defaults to ['mcp__<serverName>__*']) | | envKeys | No | Env vars the skill needs | | description | No | Human-readable description | | tools | No | Tool schemas for compile-time validation | | cursorKey | No | Override key in ~/.cursor/mcp.json | | sessionEnvKey | No | Env var for session artifact paths (Cursor only) |

Advanced example: custom binary with fallback

import { skill } from '@zibby/skills';
import { createRequire } from 'module';

const _require = createRequire(import.meta.url);

export const database = skill('database', {
  envKeys: ['DATABASE_URL'],
  description: 'Database query MCP server',
  resolve({ sessionPath } = {}) {
    let bin;
    try { bin = _require.resolve('@myorg/mcp-database/server.js'); }
    catch { bin = null; }

    if (bin) {
      return {
        command: 'node',
        args: [bin, '--read-only'],
        env: { DATABASE_URL: process.env.DATABASE_URL },
      };
    }

    return {
      command: 'npx',
      args: ['-y', '@myorg/mcp-database', '--read-only'],
      env: { DATABASE_URL: process.env.DATABASE_URL },
    };
  }
});

How it works under the hood

  Node definition                Skill definition              Agent strategy
  ─────────────                  ────────────────              ──────────────
  skills: ['add']        ──►     getSkill('add')        ──►    strategy-specific setup
                                   │
                                   ▼
                                 skill.resolve()
                                   │
                                   ▼
                                 { command, args, env }
                                   │
                          ┌────────┴────────┐
                          ▼                 ▼
                      Claude SDK         Cursor CLI
                      ──────────         ──────────
                      In-memory          Writes to
                      mcpServers         ~/.cursor/mcp.json
                      param to           before spawning
                      query()            `agent` CLI

Claude: The SDK receives mcpServers as a parameter. It spawns the MCP server as a child process, connects via stdio, routes tool calls through it.

Cursor: The framework writes ~/.cursor/mcp.json to disk before spawning the agent CLI. Cursor reads that file and manages MCP servers itself.

The strategies never reference any skill by name. They loop over the skill definitions and call resolve() on each.

API

import {
  skill,             // Unified factory — auto-detects type, auto-registers
  registerSkill,     // Register a raw skill definition
  getSkill,          // Get a skill by ID
  hasSkill,          // Check if a skill is registered
  getAllSkills,       // Get all registered skills (Map)
  listSkillIds,      // Get array of registered skill IDs
  SKILLS,            // Built-in skill ID constants
} from '@zibby/skills';

License

MIT