opensrc
Give coding agents access to any package's source code.
Emulates developer APIs such as Vercel, GitHub, Google, Slack, Apple, AWS and Twilio locally, so integrations can be built and tested in CI or without network access. Includes skills for each service and for building custom emulators.
Claude Code
$ npx -y skills add vercel-labs/emulate --agent claude-code
Codex
$ npx skills add vercel-labs/emulate -a codex
Cursor
$ npx skills add vercel-labs/emulate -a cursor
Gemini CLI
$ npx skills add vercel-labs/emulate -a gemini-cli
GitHub Copilot
$ npx skills add vercel-labs/emulate -a github-copilot
OpenCode
$ npx skills add vercel-labs/emulate -a opencode
Windsurf
$ npx skills add vercel-labs/emulate -a windsurf
Local drop-in replacement services for CI and no-network sandboxes. Fully stateful, production-fidelity API emulation. Not mocks.
npx emulate
All services listen on IPv4 loopback (127.0.0.1) by default. No config file needed:
http://localhost:4000http://localhost:4001http://localhost:4002http://localhost:4003http://localhost:4004http://localhost:4005http://localhost:4006http://localhost:4007http://localhost:4008http://localhost:4009http://localhost:4010http://localhost:4011http://localhost:4012http://localhost:4013Stripe webhooks configured with a secret include a Stripe-Signature header signed over the timestamp and raw request body.
Slack event callbacks use X-Slack-Request-Timestamp and X-Slack-Signature when slack.signing_secret is configured. The signature is an HMAC-SHA256 over v0:<timestamp>:<raw-body>; configure the receiver with the same secret and verify against the unparsed request body. Existing event subscriptions remain unsigned when the secret is absent or empty.
Resend POST /emails and POST /emails/batch support 24-hour Idempotency-Key replay, returning the original email IDs without duplicate emails or webhooks. Optional resend.allowlist restrictions let tests reject recipients while resend.send_attempts records accepted and rejected sends.
Build and share emulators for the third-party HTTP APIs your app uses. Define a provider's behavior in TypeScript, run it alongside built-in services, and reuse it in tests and framework adapters. emulate provides seeds, resets, persistence, and request/state inspection.
Start from a working scaffold and adapt its routes and state to your provider:
npm install -D emulate
npx emulate init --custom inventory
npx emulate start --watch
The scaffold implements reservations, stock changes, cancellation, and out-of-stock errors. It creates a runnable Node test and adds the service to a discovered YAML, JSON, TypeScript, or JavaScript config. For an unusual executable config, it prints the import and service entry to add manually. init prints the test command and directs you to the service URL and Inspector link printed by start; the port depends on the config. Watch mode retries when a missing local import is created, including outside the config directory. Use the inspector to view requests and state or reset to the initial seed. Structured inspection redacts token and secret fields such as access_token, refresh_token, and client_secret.
import { defineEmulator, createEmulator } from 'emulate'
const acme = defineEmulator({
name: 'acme',
state: () => ({ anvils: 100 }),
setup({ app, state }) {
app.get('/inventory', (c) => c.json(state))
app.post('/orders', (c) => {
if (!state.anvils) return c.json({ error: 'sold_out' }, 409)
state.anvils -= 1
return c.json({ shipped: 'anvil', to: 'coyote' }, 201)
})
},
})
const api = await createEmulator({ service: acme, listen: false })
try {
await api.request('/orders', { method: 'POST' })
const checkpoint = api.snapshot()
await api.reset()
await api.restore(checkpoint)
} finally {
await api.close()
}
Use defineConfig({ services: { acme: { emulator: acme }, github: { emulator: 'github' } } }) in emulate.config.ts. YAML/JSON entries accept local module paths and installed packages. --config selects a config explicitly; legacy flat configs and --seed remain supported. Node loads local TypeScript with path aliases and source locations without additional runtime dependencies. Node 26 supports erasable TypeScript only; compile enums and parameter properties to JavaScript before loading them. Node 24 also supports native TypeScript transforms.
Custom state uses your own record shapes and IDs. Seeds replace the complete initial state. Reset restores the captured seed; successful watch reloads create a new baseline and reset the run. With config auto-discovery, watch mode also detects recognized config files created after startup. Instances are independent. Persistence is opt-in, with versioned snapshots and no cross-process locking. Use port: 0 for HTTP tests, or listen: false to test without opening a port. Custom reset and close are awaitable. Framework adapters keep root-relative custom redirects under the service mount while preserving custom HTML bodies.
Streamed responses persist state changes when their bodies finish or are canceled. Reset and close cancel active streams before running cleanup. c.header('Set-Cookie', value, { append: true }) retains cookies already set on the response. In a Next.js route, export OPTIONS from createEmulateHandler to forward preflight requests and custom OPTIONS handlers.
See the custom emulator guide and complete inventory example for validation, middleware, persistence, adapters, package sharing, and troubleshooting.
# Start all services (zero-config)
npx emulate
# Start specific services
npx emulate --service vercel,github
# Custom port
npx emulate --port 3000
# Use a seed config file
npx emulate --seed config.yaml
# Generate omitted service secrets into a private file
npx emulate start --seed config.yaml --generated-secrets-file .emulate-secrets.json
# Generate a starter config
npx emulate init
# Generate config for a specific service
npx emulate init --service vercel
# List available services
npx emulate list
| Flag | Default | Description |
|---|---|---|
-p, --port | 4000 | Base port (auto-increments per service) |
--host | 127.0.0.1 | Listening address; use 0.0.0.0 to allow network access |
-s, --service | all | Comma-separated services to enable |
--seed | auto-detect | Path to seed config (YAML or JSON) |
--base-url | none | Override advertised base URL (supports {service} template) |
--portless | off | Serve over HTTPS via portless (auto-registers aliases) |
--generated-secrets-file | none | Generate omitted service secrets and write them to a new owner-only JSON file |
The port can also be set via EMULATE_PORT or PORT environment variables.
For access from a container or another machine, use npx emulate start --host 0.0.0.0. Set --base-url to a URL reachable by those clients when using OAuth redirects or other advertised URLs.
To control a local emulator from an MCP client, run npx emulate mcp. Results remove terminal escapes and redact URL credentials and sensitive query values while preserving clean URLs. See the MCP server guide for client setup and tool behavior.
portless gives emulators trusted HTTPS URLs with auto-generated certs and no browser warnings.
# Start the portless proxy (first time only)
portless proxy start
# Start emulate with portless integration
npx emulate start --portless
Each service registers as a portless alias and gets a named HTTPS URL:
github https://github.emulate.localhost
google https://google.emulate.localhost
slack https://slack.emulate.localhost
If portless is not installed, emulate will prompt to install it (npm i -g portless).
The --portless flag overwrites any existing portless aliases matching *.emulate. Aliases are removed automatically when emulate shuts down.
For a custom base URL without portless (any reverse proxy), use --base-url or the EMULATE_BASE_URL env var:
npx emulate start --base-url "https://{service}.myproxy.test"
The PORTLESS_URL env var is automatically set by the portless CLI wrapper when running a command through it (e.g. portless github.emulate emulate start), typically to a value like https://{service}.emulate.localhost. It supports {service} interpolation, just like --base-url and EMULATE_BASE_URL. When no explicit baseUrl is provided, it is used as a fallback.
Per-service overrides are also supported in the seed config (these take highest priority over all other base URL sources):
github:
baseUrl: https://github.emulate.localhost
npm install emulate
Each call to createEmulator starts a single service:
import { createEmulator } from 'emulate'
const github = await createEmulator({ service: 'github', port: 4001 })
const vercel = await createEmulator({ service: 'vercel', port: 4002 })
github.url // 'http://localhost:4001'
vercel.url // 'http://localhost:4002'
await github.close()
await vercel.close()
When a GitHub App omits private_key, createEmulator generates an RSA-2048 PKCS#1 key for that emulator instance:
const github = await createEmulator({
service: 'github',
seed: {
github: {
users: [{ login: 'octocat' }],
apps: [{
app_id: 12345,
slug: 'my-github-app',
name: 'My GitHub App',
installations: [{ installation_id: 100, account: 'octocat' }],
}],
},
},
})
const privateKey = github.generatedSecrets.find(
secret => secret.kind === 'github.app_private_key' && secret.id === '12345',
)?.value
Generated keys remain stable across reset() calls and appear only in generatedSecrets. Explicitly configured keys are never returned there. A new createEmulator call generates a new key.
The CLI can also generate omitted GitHub App keys when a delivery file is requested:
npx emulate start --service github --seed config.yaml \
--generated-secrets-file .emulate-secrets.json
The destination must not exist. emulate removes inherited ACLs, verifies effective owner-only access, and publishes complete JSON before opening listeners or configuring portless. Handled startup failures remove the invocation-owned artifact so the command can be retried immediately. A hard termination such as SIGKILL can leave a complete published artifact that must be removed manually after confirming no invocation is using it. Only generated secrets are included. Explicitly configured keys are never copied into the artifact. Linux requires setfacl and getfacl from the acl package. The flag fails closed when access controls cannot be verified and is not supported on Windows. Without --generated-secrets-file, CLI seed files keep requiring private_key.
Give coding agents access to any package's source code.
A framework for generating dynamic UIs from prompts using predefined components and actions, with codegen, core schema and catalog tools, and devtools inspectors for React, Solid, and Svelte apps.
The programming language for agents. Zerolang is an experimental graph-native programming language where the semantic graph is the program database. Humans ask for outcomes. Agents query the graph, submit checked edits, and prove the result.
A development methodology for coding agents that makes the agent brainstorm before building, follow plans, run parallel work and finish branches in a disciplined way. You get fewer skipped steps and more consistent results from your coding assistant.
Helps you take a change from a rough idea or bug report through to a tested, reviewed result, with each step handled by a focused skill. Its skills cover pinning down domain terms, designing module interfaces, diagnosing hard bugs, and reviewing changes against your repo's coding standards.
Gives your coding agent a planning, testing and review routine to follow on every task. It plans before building, checks changes with tests, has a fresh reviewer look for regressions, and saves repeated wins as reusable skills.
Developer tools for working on the React codebase itself. Provides skills for extracting error messages, managing and debugging feature flags across release channels, running Flow type checks, and fixing lint and formatting issues before committing.
Install it with the command on its page. It includes apple, aws, custom-apis. Its skills do not fire on their own yet. Free and open source.
Is this plugin yours?
Claim it with GitHubSubmit a pluginPromote it