| name | counterfact-repl |
| description | Interact with Counterfact mock API server programmatically. Inspect and modify context state, configure proxy settings, test endpoints, and control mock behavior. Use when the user mentions "counterfact", "mock server", "REPL", testing APIs, or working with OpenAPI mocks.
|
| applyTo | ["**/*.{yaml,yml,json}","**/routes/**/*.{ts,js}","**/*context.{ts,js}"] |
Counterfact REPL Skill
Purpose
This skill enables AI agents to interact with a running Counterfact mock server through its Admin API. Counterfact provides programmable API mocks based on OpenAPI specifications, with a REPL for runtime manipulation. This skill exposes those capabilities programmatically via HTTP endpoints.
What is Counterfact?
Counterfact is a contract-driven mock API server that:
- Generates mock endpoints from OpenAPI specifications
- Provides a JavaScript REPL for runtime state manipulation
- Allows programmable behavior (not just static responses)
- Supports context objects for storing mock state
- Enables proxy mode to route requests to real APIs selectively
The REPL lets developers manipulate mock state in real-time using JavaScript. This skill exposes the same capabilities via HTTP API.
When to Use This Skill
Invoke this skill when the user:
- Mentions "counterfact", "mock server", "REPL", or "OpenAPI"
- Wants to test or develop against a mock API
- Needs to inspect or modify mock server state
- Wants to configure proxy vs. mock routing
- Needs to simulate API failures or edge cases
- Says things like:
- "Add data to the mock"
- "Change the mock state"
- "Make the API return an error"
- "Proxy this endpoint to the real server"
- "What data is in the mock store?"
- "Simulate a service failure"
Detecting Counterfact
To determine if Counterfact is running, check in this order:
-
Check for health endpoint (most reliable):
GET http://localhost:3100/_counterfact/api/health
If successful, Counterfact is running on port 3100.
-
Look for package.json:
- Check if
counterfact is in dependencies or devDependencies
- Read scripts to find the port (e.g.,
--port 3000)
-
Check for routes directory:
- Look for
routes/ or api/routes/ directory
- TypeScript/JavaScript files matching OpenAPI paths
-
Check for OpenAPI spec:
- Files matching
*.yaml, openapi.yaml, swagger.yaml
- Look for
openapi: or swagger: in content
-
Try alternate ports:
- Port 3100 (default)
- Port 3000 (common alternative)
- Check environment variables or config files
Admin API Endpoints
All Admin API endpoints are prefixed with /_counterfact/api/
Health Check
Request:
GET /_counterfact/api/health
Response:
{
"status": "ok",
"port": 3100,
"uptime": 123.45,
"basePath": "/path/to/routes",
"prefix": ""
}
Use when: Checking if server is running, getting server info.
List All Contexts
Request:
GET /_counterfact/api/contexts
Response:
{
"success": true,
"data": {
"paths": ["/", "/pets", "/users"],
"contexts": {
"/": { "rootProperty": "value" },
"/pets": { "pets": [...] },
"/users": { "users": [...] }
}
}
}
Use when: Discovering what contexts exist, getting overview of all state.
Get Specific Context
Request:
GET /_counterfact/api/contexts/{path}
Example:
GET /_counterfact/api/contexts/pets
Response:
{
"success": true,
"data": {
"path": "/pets",
"context": {
"pets": [
{ "id": 1, "name": "Fido" },
{ "id": 2, "name": "Whiskers" }
]
}
}
}
Use when: Inspecting state for a specific API path.
Update Context
Request:
POST /_counterfact/api/contexts/{path}
Content-Type: application/json
{
"property": "newValue",
"arrayProperty": [...]
}
Example:
POST /_counterfact/api/contexts/pets
Content-Type: application/json
{
"pets": [
{ "id": 1, "name": "Fido" },
{ "id": 2, "name": "Whiskers" },
{ "id": 3, "name": "Rex" }
]
}
Response:
{
"success": true,
"message": "Context updated for path: /pets",
"data": {
"path": "/pets",
"context": { "pets": [...] }
}
}
Use when: Adding data, modifying state, simulating conditions.
Important: The update uses smart diffing - only changed properties are updated, preserving methods and other properties.
Get Full Configuration
Request:
GET /_counterfact/api/config
Response:
{
"success": true,
"data": {
"alwaysFakeOptionals": false,
"basePath": "/path/to/routes",
"buildCache": false,
"generate": { "routes": true, "types": true },
"openApiPath": "/path/to/openapi.yaml",
"port": 3100,
"proxyUrl": "",
"prefix": "",
"startRepl": true,
"startServer": true,
"watch": { "routes": true, "types": true },
"proxyPaths": []
}
}
Use when: Getting full server configuration.
Get Proxy Configuration
Request:
GET /_counterfact/api/config/proxy
Response:
{
"success": true,
"data": {
"proxyUrl": "https://api.example.com",
"proxyPaths": [
["/api/users", true],
["/api/posts", false]
]
}
}
Use when: Checking what paths are proxied vs. mocked.
Update Proxy Configuration
Request:
PATCH /_counterfact/api/config/proxy
Content-Type: application/json
{
"proxyUrl": "https://api.example.com",
"proxyPaths": [
["/api/users", true],
["/api/posts", false]
]
}
Response:
{
"success": true,
"message": "Proxy configuration updated",
"data": {
"proxyUrl": "https://api.example.com",
"proxyPaths": [
["/api/users", true],
["/api/posts", false]
]
}
}
Use when: Switching between mock and real API, testing integration.
Notes:
proxyUrl is the base URL to proxy to
proxyPaths is an array of [path, enabled] tuples
- Path of
"" or "/" enables proxy globally
- Setting path
true routes to real API, false uses mock
List All Routes
Request:
GET /_counterfact/api/routes
Response:
{
"success": true,
"data": {
"routes": [
{
"path": "/pets",
"methods": {
"GET": true,
"POST": true
}
},
{
"path": "/pets/{id}",
"methods": {
"GET": true,
"PUT": true,
"DELETE": true
}
}
]
}
}
Use when: Discovering available endpoints, understanding API structure.
Common Usage Patterns
Pattern 1: Inspect Current State
User request: "What pets are in the store?"
Agent workflow:
1. GET /_counterfact/api/health
→ Confirm server running
2. GET /_counterfact/api/contexts/pets
→ Retrieve pets array
3. Present formatted list to user
Example response:
Currently in the pet store:
- ID 1: Fido
- ID 2: Whiskers
Pattern 2: Add Test Data
User request: "Add a new pet named Rex with ID 3"
Agent workflow:
1. GET /_counterfact/api/contexts/pets
→ Get current pets
2. Append new pet to array
3. POST /_counterfact/api/contexts/pets
Body: { "pets": [...existingPets, newPet] }
→ Update context
4. Verify by GETting /pets endpoint
→ Confirm change visible in API
Pattern 3: Simulate Failure
User request: "Make the user service unavailable"
Agent workflow:
1. POST /_counterfact/api/contexts/users
Body: { "serviceAvailable": false }
→ Set failure flag
2. Explain that route handlers should check this flag
3. Optionally: Test GET /users to verify error
Note: The route handler must be coded to check context.serviceAvailable. The skill sets the flag, but behavior depends on route implementation.
Pattern 4: Switch to Proxy Mode
User request: "Route /orders to the real API"
Agent workflow:
1. GET /_counterfact/api/config/proxy
→ Check current proxy settings
2. PATCH /_counterfact/api/config/proxy
Body: {
"proxyUrl": "https://api.production.com",
"proxyPaths": [["/orders", true]]
}
→ Enable proxy for /orders
3. Confirm that /orders now hits real server
Pattern 5: Batch Data Setup
User request: "Set up test data: 3 users and 5 products"
Agent workflow:
1. Create users array with test data
2. POST /_counterfact/api/contexts/users
Body: { "users": [...testUsers] }
3. Create products array with test data
4. POST /_counterfact/api/contexts/products
Body: { "products": [...testProducts] }
5. Confirm setup complete
Error Handling
Server Not Running
If health check fails:
❌ Error: Counterfact server not running
Suggestion: Start the server with: npx counterfact openapi.yaml
Context Not Found
If context doesn't exist:
GET /_counterfact/api/contexts/nonexistent
→ Returns: { "path": "/nonexistent", "context": {...} }
Note: Contexts are hierarchical. If /api/users doesn't exist, it returns parent context.
Invalid JSON
If request body is malformed:
← 400 Bad Request
{ "success": false, "error": "Request body must be a valid JSON object" }
Server Error
If internal error occurs:
← 500 Internal Server Error
{
"success": false,
"error": "Error message",
"stack": "..." // Only in development
}
Advanced Techniques
Hierarchical Contexts
Contexts are hierarchical. If you have:
/ → root context
/api → api context
/api/users → users context
Then GET /_counterfact/api/contexts/api/users/123 returns the /api/users context (closest parent).
Smart Diffing
Context updates use smart diffing:
POST { users: [...newUsers] }
Testing Proxied Requests
After setting proxy:
1. PATCH /_counterfact/api/config/proxy
Body: { "proxyPaths": [["/users", true]] }
2. Make request to http://localhost:3100/users
→ This now proxies to real server
3. Check response headers for proxy evidence
Limitations
- In-memory state: Changes reset on server restart
- No TypeScript validation: Context can accept any JSON object
- No authentication: Admin API is unauthenticated (local development tool)
- No versioning: API is v1, may evolve
- Context discovery: Must know or discover paths, no automatic schema
Security Considerations
⚠️ Warning: The Admin API provides full control over mock server state.
Recommendations:
- Only run Counterfact in development/testing environments
- Do not expose the Admin API to untrusted networks
- Configure a bearer token when exposing the Admin API beyond local development
- Be cautious with context updates from untrusted sources
Current access controls:
- By default, the Admin API only listens on the loopback interface (localhost)
- You can require a bearer token for all Admin API requests:
- CLI flag:
--admin-api-token <TOKEN_VALUE>
- Environment variable:
COUNTERFACT_ADMIN_API_TOKEN=<TOKEN_VALUE>
- When a token is configured, clients must send:
- HTTP header:
Authorization: Bearer <TOKEN_VALUE>
Integration with OpenAPI
The skill works best when paired with OpenAPI understanding:
- Read the OpenAPI spec to understand available paths
- Map OpenAPI paths to context paths
- Use OpenAPI schemas to validate context updates
- Generate realistic test data based on OpenAPI examples
Example:
1. Read openapi.yaml
2. Find path /pets with schema: { id: number, name: string }
3. Generate test data: { id: 1, name: "Fido" }
4. POST /_counterfact/api/contexts/pets with test data
Troubleshooting
Issue: Health check returns 404
Solution: Server may not have Admin API. Update to latest Counterfact version.
Issue: Context update doesn't affect API responses
Solution: Check route handler implementation. It must read from $.context.
Example route handler:
export const GET: HTTP_GET = ($) => {
return $.response[200].json($.context.pets);
};
Issue: Proxy not working
Solution:
- Verify proxyUrl is set:
GET /_counterfact/api/config/proxy
- Check path is enabled:
proxyPaths array
- Ensure path matches exactly (case-sensitive)
See Also