loading…
Search for a command to run...
loading…
Lightweight, embeddable skill/tool registration framework for AI agents
Lightweight, embeddable skill/tool registration framework for AI agents
The skill infrastructure every AI agent deserves.
CI npm version License: MIT TypeScript Node MCP SKILL.md
Self-describing skills. AES-256 credentials. MCP server. SKILL.md support. Multi-user auth. Real-time SSE. ~8500 LOC.

Every AI agent framework has a different way to register tools. SkillForge gives you one consistent layer that works everywhere:
| Feature | What it means |
|---|---|
| 🧠 MCP Server | Expose skills to Claude Desktop, Cursor, VS Code — any MCP client |
| 📝 SKILL.md | Define HTTP skills in markdown — no code required |
| 🔐 AES-256 Credentials | Encrypted, isolated, never in logs or MCP responses |
| 🚦 Feature Flags | FNV-1a hashing, rollout %, user targeting, kill switches |
| ⚡ Event Bus | Pub/sub with chaining, wildcards, and pipeline triggers |
| 👥 Multi-User Auth | Username/password login, role-based access (admin/operator/viewer) |
| 📡 Real-Time SSE | Server-Sent Events for live events, logs, and dashboard stats |
| 🎯 Auto-Generated UI | Forms from JSON Schema, live execution, dashboards |
| 🔌 OpenAPI | Auto-generated spec, Swagger UI ready |
npm install @ganeshvardhineedi/skillforge
export SKILLFORGE_ENCRYPTION_KEY=$(node -e "console.log(require('crypto').randomBytes(32).toString('hex'))")
export SKILLFORGE_SECRET=$(node -e "console.log(require('crypto').randomBytes(32).toString('hex'))")
npx skillforge doctor
npx skillforge serve 3456
Open http://localhost:3456/ui/v2 — login with admin / changeme (set SKILLFORGE_ADMIN_PASSWORD for production).
import { SkillForge } from "@ganeshvardhineedi/skillforge";
const sf = new SkillForge();
sf.startServer(3456);
// Skills auto-discover, API starts, UI is ready.
// Default login: admin / changeme
{
"mcpServers": {
"skillforge": {
"command": "npx",
"args": ["-y", "@ganeshvardhineedi/skillforge", "serve-mcp"]
}
}
}
Now Claude can use all your SkillForge skills as native tools.
---
name: httpbin
version: 1.0.0
description: HTTP testing service
credentials:
- name: api_key
type: apikey
requiredFields: ["key"]
---
## get
Returns anything passed in the request
**Runtime:** http
**Endpoint:** https://httpbin.org/get
**Method:** GET
**Headers:**
Authorization: Bearer {{credentials.api_key.key}}
**Params Mapping:**
q={{input.query}}
**Input:**
- query (string, optional): Query string to echo
npx skillforge load-md ./skills/httpbin/SKILL.md
npx skillforge serve 3456
┌──────────────────────────────────────────────────────┐
│ SkillForge │
│ │
│ ┌──────────┐ ┌──────────┐ ┌───────────────────┐ │
│ │ Skills │ │Registry │ │ Credential │ │
│ │ ┌──────┐ │ │ │ │ Store (AES-256) │ │
│ │ │JS │ │ │ Auto- │ │ │ │
│ │ │SKILL │ │──│ discover │──│ encrypt / decrypt │ │
│ │ │.md │ │ │ validate │ │ sanitize (MCP) │ │
│ │ └──────┘ │ │ │ │ │ │
│ └──────────┘ └──────────┘ └───────────────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ ┌───────────────────┐ │
│ │ Runner │ │ Feature │ │ MCP Adapter │ │
│ │ │ │ Flags │ │ (stdio/HTTP) │ │
│ │ Retry │ │ │ │ │ │
│ │ Timeout │ │ FNV-1a │ │ Tools / Resources │ │
│ │ Validate │ │ Rollout │ │ Prompts / Rate │ │
│ └──────────┘ └──────────┘ └───────────────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ ┌───────────────────┐ │
│ │Event Bus │ │ Pipeline │ │ Auto-Generated │ │
│ │ chain │ │ Steps │ │ UI + OpenAPI │ │
│ │ wildcard │──│ Context │──│ │ │
│ └──────────┘ └──────────┘ └───────────────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ Auth │ │ SSE │ │
│ │ UserStore│ │ Real-Time│ │
│ │ bcryptjs │ │ Events │ │
│ │ Roles │ │ Stream │ │
│ └──────────┘ └──────────┘ │
└──────────────────────────────────────────────────────┘
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/skills |
List all skills |
| GET | /api/skills/:name |
Skill detail with actions & triggers |
| GET | /api/skills/:name/actions |
Action schemas |
| GET | /api/flags |
List feature flags |
| GET | /api/flags/:name |
Evaluate a flag |
| POST | /api/webhook/:skill/:trigger |
Incoming webhook |
| GET | /api/events/log |
Event bus log |
| GET | /api/events |
Event subscriptions |
| GET | /api/openapi.json |
Auto-generated OpenAPI 3.0 spec |
| GET | /api/health |
Health check |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/auth/login |
Login with username/password, returns JWT |
| GET | /api/auth/me |
Get current user info (any authenticated role) |
| Method | Endpoint | Required Role | Description |
|---|---|---|---|
| POST | /api/admin/token |
secret in body | Generate JWT (headless fallback) |
| POST | /api/admin/sse-token |
any | Short-lived SSE token (5min) |
| POST | /api/admin/run |
admin, operator | Execute any skill action |
| POST | /api/admin/credentials |
admin | Store credentials |
| DELETE | /api/admin/credentials/:skill/:cred |
admin | Delete credentials |
| POST | /api/admin/pipeline/run |
admin, operator | Run multi-step pipeline |
| GET | /api/admin/logs |
admin, operator, viewer | Execution logs |
| GET | /api/admin/users |
admin | List users |
| POST | /api/admin/users |
admin | Create user |
| PUT | /api/admin/users/:id/role |
admin | Change user role |
| DELETE | /api/admin/users/:id |
admin | Delete user |
| PUT | /api/admin/skills/:name/toggle |
admin | Enable/disable skill |
| DELETE | /api/admin/skills/:name |
admin | Delete skill |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/events/stream?token=<sse-token> |
SSE stream for live events, logs, stats |
import type { ISkill, IActionContext } from "@ganeshvardhineedi/skillforge";
export default {
name: "my-service",
description: "My awesome API integration",
version: "1.0.0",
credentials: [
{ name: "api_key", type: "apikey", requiredFields: ["key"] }
],
actions: [
{
name: "do_thing",
description: "Do the thing",
inputSchema: {
type: "object",
properties: {
query: { type: "string", description: "Search query" },
limit: { type: "number", default: 10 },
},
required: ["query"],
},
timeout: 10000,
retry: { maxAttempts: 3, delayMs: 1000, backoff: "exponential" },
run: async (params, ctx) => {
const apiKey = await ctx.getCredential("api_key");
return { result: "done" };
},
},
],
triggers: [],
credentials: [],
schema: { type: "object", properties: {} },
} satisfies ISkill;
See the SKILL.md Format section above.
import { toSkill, actionFromFunction } from "@ganeshvardhineedi/skillforge";
const forecast = actionFromFunction(
async (params: { city: string }) => ({ temp: 72 }),
{ name: "get_forecast", description: "Get weather" }
);
export default toSkill("weather", "Weather API", [forecast]);
npx skillforge list # List registered skills
npx skillforge validate # Validate skill schemas
npx skillforge flags # List feature flags
npx skillforge doctor # Check local setup health
npx skillforge serve 3456 # Start HTTP server
npx skillforge serve-mcp # Start MCP server (stdio)
npx skillforge load-md <path> # Load skills from SKILL.md
npx skillforge run <skill> <action> [json-params]
| Skill | Actions | Type | Description |
|---|---|---|---|
| weather | 3 | TypeScript | Weather via OpenWeatherMap |
| github | 2 | TypeScript | Repos, issues, PRs |
| gmail | 4 | TypeScript | Read, search, send via Google OAuth |
| telegram | 4 | TypeScript | Messages, groups, polls |
| trading | 5 | TypeScript | Crypto signals, backtesting |
| hive | 6 | TypeScript | Docker container monitoring |
| openclaw | 4 | TypeScript | Agent framework bridge |
| stripe | 6 | TypeScript | Payments, subscriptions, customers, refunds |
| slack | 5 | TypeScript | Messages, channels, files, reactions |
| notion | 5 | TypeScript | Search, read, create, update pages |
| jira | 5 | TypeScript | Jira Cloud — search, create/update issues, list projects |
| twilio | 5 | TypeScript | Twilio — SMS, calls, phone lookup |
| memory | 5 | TypeScript | Persistent action history — search, timeline, observations |
SkillForge works with any MCP-compatible client:
| Client | Setup |
|---|---|
| Claude Desktop | Add to claude_desktop_config.json (see above) |
| Cursor | Add to .cursor/mcp.json |
| VS Code + Copilot | Add to MCP settings |
| OpenClaw | openclaw mcp set skillforge -- npx -y @ganeshvardhineedi/skillforge serve-mcp |
| Any MCP client | npx @ganeshvardhineedi/skillforge serve-mcp |
| Layer | What |
|---|---|
| Credentials | AES-256-CBC encryption, never in logs or MCP responses |
| MCP Sanitization | 13 regex patterns strip API keys, JWTs, Bearer tokens from errors/results |
| SSRF Prevention | HTTPS required, private IP blocking, DNS rebinding guard |
| SKILL.md | HTTP-only runtime (no shell/eval), path traversal protection, 1MB file limit |
| Auth | bcryptjs password hashing, JWT tokens with expiration, role-based access control |
| SSE | Short-lived tokens (5min), 5 connections/user limit, safe write with cleanup |
| UI | XSS-safe, all input escaped |
| Variable | Required | Description |
|---|---|---|
SKILLFORGE_SECRET |
Admin features | JWT signing secret |
SKILLFORGE_ENCRYPTION_KEY |
Credentials | AES-256 key (min 16 chars) |
SKILLFORGE_ADMIN_USER |
No | Default admin username (default: admin) |
SKILLFORGE_ADMIN_PASSWORD |
No | Default admin password (default: changeme) |
SKILLFORGE_FLAGS |
No | Path to feature flags JSON |
SKILLFORGE_PORT |
No | Server port (default: 3456) |
SKILLFORGE_RATE_LIMIT |
No | Max Express requests/min (default: 300) |
SKILLFORGE_CORS_ORIGIN |
No | Comma-separated allowed browser origins. Empty disables cross-origin browser requests. |
SKILLFORGE_MCP_RATE_LIMIT |
No | Max MCP tool calls/min (default: 100) |
# Generate keys
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
npm install @ganeshvardhineedi/skillforge
git clone https://github.com/vardhineediganesh877-ui/skillforge.git
cd skillforge && npm install && npm run build
The v2 UI is a modern single-page application built with Vite, React 19, Tailwind CSS v4, and TanStack Query.

npm install && npx skillforge doctor && npx skillforge serve 3456
Open http://localhost:3456/ui/v2 — modern dashboard with full SPA navigation.
| Route | Page | Description |
|---|---|---|
/ui/v2 |
Dashboard | System overview, stats, recent activity |
/ui/v2/skills |
Skills | Browse all registered skills |
/ui/v2/skills/:name |
Skill Detail | Actions, schema, live playground |
/ui/v2/playground |
Playground | Execute skill actions interactively |
/ui/v2/mcp |
MCP Tools | Browse MCP-exposed tools and resources |
/ui/v2/credentials |
Credentials | Manage encrypted API keys |
/ui/v2/activity |
Activity | Real-time events and execution history (SSE) |
/ui/v2/settings |
Settings | Feature flags, user management, configuration |
Note: The classic
/uidashboard is deprecated and will be removed in v2.2.
MIT © 2026 Ganesh Vardhineedi
Add this to claude_desktop_config.json and restart Claude Desktop.
{
"mcpServers": {
"skillforge": {
"command": "npx",
"args": [
"-y",
"@ganeshvardhineedi/skillforge"
]
}
}
}pro tip
Just installed Skillforge? Say to Claude: "remember why I installed Skillforgeand what I want to try" — it'll save into your Vault.
how this works →