@zibby/skills
v0.1.3
Published
Built-in skill definitions for Zibby test automation framework
Maintainers
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/skillsImport 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 inskills: ['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` CLIClaude: 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
