Generate a runnable mockstar mock server for a service from its specs and docs. Use when asked to mock a service, stand up a fake/stub API, create mockstar mocks/fixtures, or scaffold a mock backend from an API spec or documentation. Accepts OpenAPI (json/yaml), Postman collections, HAR captures, curl examples, GraphQL SDL/introspection, and prose docs (Markdown/PDF/DOCX or a documentation URL); normalizes every input into one Endpoint Inventory, uses native `mockstar import` for OpenAPI and hand-authors the rest, infers scenarios/dynamic handlers/webhooks at full fidelity, runs `mockstar enhance` for Tier 2 placeholders, then boots the server and smoke-tests every route. Tags each mock with provenance and confidence and emits a coverage report flagging speculative inferences and documented-but-unmocked gaps. Not for the mockstar HTTPS proxy or native GraphQL semantics. Targets the mockstar CLI (`bunx @dhaneshpurohit/mockstar`).
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Generate a runnable mockstar mock server for a service from its specs and docs. Use when asked to mock a service, stand up a fake/stub API, create mockstar mocks/fixtures, or scaffold a mock backend from an API spec or documentation. Accepts OpenAPI (json/yaml), Postman collections, HAR captures, curl examples, GraphQL SDL/introspection, and prose docs (Markdown/PDF/DOCX or a documentation URL); normalizes every input into one Endpoint Inventory, uses native `mockstar import` for OpenAPI and hand-authors the rest, infers scenarios/dynamic handlers/webhooks at full fidelity, runs `mockstar enhance` for Tier 2 placeholders, then boots the server and smoke-tests every route. Tags each mock with provenance and confidence and emits a coverage report flagging speculative inferences and documented-but-unmocked gaps. Not for the mockstar HTTPS proxy or native GraphQL semantics. Targets the mockstar CLI (`bunx @dhaneshpurohit/mockstar`).
x-spec-version
1
license
MIT
compatibility
Requires Bun (`bunx @dhaneshpurohit/mockstar` >= 0.2.2) or Docker (ghcr.io/dhanesh/mockstar), plus `uv` and `curl` for the bundled helpers.
Converts any combination of API specs and docs into a runnable mockstar mock project. It accepts
OpenAPI 3.x (JSON/YAML), Postman collections, HAR captures, curl command files, GraphQL
SDL/introspection, and prose documentation (Markdown, PDF, DOCX, or a URL) โ one or several at
once โ and produces a fully configured mockstar project with realistic scenarios, dynamic handlers,
and webhooks, verified by booting the server and smoke-testing every route.
The defining rule: no fabricated endpoints. Every mock traces back to a fetched or provided
source. Behavior that is reasoned from context rather than explicitly documented is tagged
confidence: "inferred" in the Endpoint Inventory and flagged in the coverage report.
Speculation is visible and reviewable; it is never silently promoted to ground truth.
When to use
Use when you need to stand up a mock backend quickly from existing specs or documentation:
mocking a third-party API for local development, building a test double from an OpenAPI spec,
scaffolding fixtures from a HAR capture of real traffic, or generating stubs from API prose docs.
Works on any mix of input types; the skill normalizes them all into one Endpoint Inventory before
generating.
When not to use
mockstar HTTPS proxy mode โ this skill generates config-driven mocks; it does not configure
the mockstar proxy for intercepting live traffic.
Native GraphQL server semantics โ GraphQL is modeled as a single POST /graphql endpoint
with operation routing via scenarios[].when.body. If you need a proper GraphQL resolver
server (subscriptions, schema stitching, persisted queries), use a dedicated GraphQL toolchain.
Non-mockstar mock servers โ MSW, Prism, WireMock, json-server. This skill targets only
the mockstar CLI.
Prerequisites
bunx @dhaneshpurohit/mockstar available (install: bun add -g @dhaneshpurohit/mockstar or use bunx
directly with Bun). Package name matters: mockstar is published on npm as the scoped package
@dhaneshpurohit/mockstar (latest โฅ 0.2.2). The unscopedmockstar on npm is an unrelated
project โ never invoke bare bunx mockstar. Equivalent Docker image: ghcr.io/dhanesh/mockstar:latest
(--runtime docker). The importer's schema-derived bodies and mixed-segment path-param handling
require mockstar โฅ 0.2.2; the coverage report records the resolved runtime and version.
uv available โ used to run for binary input conversion.
assets/extract_text.py
curl available โ used by assets/smoke.sh for smoke testing routes.
For --runtime docker: a reachable Docker daemon and the ghcr.io/dhanesh/mockstar image.
Invariants (do not violate)
No fabricated endpoints. Every endpoint in the output must trace to a fetched or provided
source. If an endpoint is absent from every input, do not emit it.
Prefer native tooling. Use bunx @dhaneshpurohit/mockstar import for OpenAPI (and losslessly-liftable
Postman/HAR) rather than hand-authoring what the importer can produce. Use
bunx @dhaneshpurohit/mockstar enhance for Tier 2 placeholder rewriting rather than hand-tokenizing bodies.
Schema-valid output. Verification (Stage 5) boots the server. A mock project that fails
to boot is not a valid deliverable. The --no-verify flag skips the boot, which is only
acceptable in CI pre-check mode where boot is deferred.
No silent truncation. When --max-endpoints caps the inventory, every dropped endpoint
is logged to MOCKSTAR-COVERAGE.md under the "Dropped" section with its source.
Read-only inputs. Never modify source spec files, HAR archives, or documentation. The
only writes are to the --into output directory and to MOCKSTAR-COVERAGE.md.
Flags
--into <dir> โ output directory for the generated mockstar project (default: mock-<service-name> in cwd).
--tenant <name> โ mockstar tenant name used as the mocks subdirectory (default: default). Important: when passed to mockstar import, the equals form --tenant=<name> is required โ the space form is silently ignored by the importer.
--fidelity full|static โ full generates scenarios, dynamic handlers, and webhooks from IR hints; static emits one default response per endpoint only (default: full).
--no-verify โ skip Stage 5 boot-and-smoke verification (the generated project is not started).
--deterministic โ passed through to bunx @dhaneshpurohit/mockstar during smoke testing; disables random Faker values for reproducible responses.
--max-endpoints N โ cap the merged Endpoint Inventory at N records; excess are dropped in reverse-priority order and reported.
--runtime auto|local|docker โ selects how mockstar is invoked (default: auto). auto prefers Docker (the ghcr.io/dhanesh/mockstar image) when the Docker daemon is reachable and the image is available, else falls back to local bunx @dhaneshpurohit/mockstar. local always uses bunx @dhaneshpurohit/mockstar. docker always uses Docker and fails fast if the daemon is down.
--image <ref> โ the Docker image reference used when --runtime is docker or auto resolves to Docker (default: ghcr.io/dhanesh/mockstar:latest). For reproducibility, pin by digest: ghcr.io/dhanesh/mockstar@sha256:<digest>.
Procedure
Run these stages in order. Fan out subagents where noted.
Locating asset helpers (do this first). The bundled helpers assets/extract_text.py and
assets/smoke.sh are referenced by paths relative to this skill's directory, but subagents
run from the target repository โ a bare assets/ path will not resolve for them. Before
dispatching any subagent, resolve this skill's absolute base directory once and pass the
absolute paths into every subagent prompt:
Obtain the skill's base directory from the harness (it is provided when the skill loads).
Set EXTRACT="<skill-base-dir>/assets/extract_text.py" and
SMOKE="<skill-base-dir>/assets/smoke.sh".
If the harness does not expose the base directory, discover it:
find ~/.claude ~/.config ~/.agents -path '*mockstar-mock*/assets/extract_text.py' 2>/dev/null | head -1
Verify: uv run "$EXTRACT" --help should print usage.
Hand subagents the literal absolute $EXTRACT and $SMOKE values โ never a relative
assets/-prefixed form.
Stage 0 โ Compatibility preflight
Before any other work, resolve the runtime environment and validate the live CLI surface.
1. Resolve runtime.
Evaluate --runtime:
local โ use bunx @dhaneshpurohit/mockstar directly.
docker โ use the Docker image (--image value). Fail fast if docker version (server) is
unreachable.
auto (default) โ prefer Docker: run docker version and confirm the server is reachable,
then confirm the image is reachable via docker manifest inspect <image>. If either check
fails, fall back to local and note the fallback in the coverage report.
Record the resolved runtime (local or docker) and the image ref when docker is chosen.
2. Detect mockstar version.
Local: bunx @dhaneshpurohit/mockstar version โ capture the printed version string.
Docker: docker run --rm <image> version โ capture the printed version string.
Record the version. Note the known caveat: the CLI's printed version may lag the package
version (treat it as advisory, not definitive).
3. Validate the live CLI surface.
Run the help command for the chosen runtime:
Local: bunx @dhaneshpurohit/mockstar help
Docker: docker run --rm <image> help
Confirm that import, enhance, and serve-as-default are all present in the output. For
mockstar import, discover the real --tenant flag form from the live help output rather
than assuming. The skill's default assumption is the equals form --tenant=<name> (verified
for current mockstar), but if the live surface shows a different form, prefer the live surface
and note the drift in the coverage report's "Runtime & compatibility" section.
Principle: when the live CLI surface contradicts this skill's baked-in assumptions, prefer
the live truth and flag the drift in the coverage report.
4. Record findings.
Record the detected runtime, mockstar version, and image ref/digest in the coverage report's
"Runtime & compatibility" section (see references/coverage-report.md).
Stage 1 โ Intake & classify
Examine every provided input and classify each by type using these detection signals:
.graphql / .gql extension, or {"data":{"__schema":...}}
GraphQL SDL / introspection
.md, .pdf, .docx, plain text, or http(s):// URL
Prose documentation
For binary inputs (PDF, DOCX) and local text files, convert to plain text before proceeding:
uv run "$EXTRACT" <local-file>
For documentation URLs, fetch the content first with curl -L (or WebFetch), save it to a
temp file, then pass the temp file to $EXTRACT if it is binary, or use it directly if it is
already plain text or Markdown. Never pass a URL directly to $EXTRACT โ the helper
handles only local .pdf, .docx, .txt, .md, and .markdown files; a URL causes exit 3
("unsupported extension").
# URL: fetch first, then optionally extract
curl -L -o /tmp/apidoc.md "https://example.com/api-docs"# /tmp/apidoc.md is already text โ use directly as prose source# Binary (PDF, DOCX): use $EXTRACT
uv run "$EXTRACT" /path/to/spec.pdf
assets/extract_text.py emits the extracted text to stdout; capture it to a temp file and use
that as the prose source for Stage 2. This is the only stage where the absolute $EXTRACT
path is needed for subagents.
Stage 2 โ Extract โ Endpoint Inventory
Fan out one subagent per input type. Each subagent follows the adapter rules in
references/input-adapters.md and emits records that are valid against
references/inventory.schema.json. Key rules per adapter:
OpenAPI โ preferred path: if the sole input is a raw OpenAPI 3.x file and no extra
examples need merging, skip manual extraction and hand the file directly to
bunx @dhaneshpurohit/mockstar import in Stage 3. Manual extraction is needed only when merging additional
examples or overriding generated config.
Postman โ walk item[] recursively; rewrite {{var}} placeholders to Hono :param.
Lift to OpenAPI with postman-to-openapi first when saved responses are well-structured.
HAR โ group entries by (method, normalised-path); rewrite numeric/UUID path segments
to :id / :uuid. Discard entries outside the target origin.
curl โ one record per curl invocation; all records are confidence: "inferred" because
curl carries no response information.
GraphQL โ model the entire API as a single POST /graphql record; each named operation
becomes a responses[] entry with a when.body predicate matching on operationName.
Prose โ extract from code fences, Markdown tables, and inline backtick references in that
order; never invent endpoints that are absent from the text.
After all subagents complete, merge their outputs into a single Endpoint Inventory array.
Deduplication key: (method, path) (case-insensitive method, exact Hono-style path). Resolve
conflicts in priority order: OpenAPI > Postman/HAR > curl > prose. Union responses[] by
status code. Enforce --max-endpoints by dropping records in reverse-priority order and
logging each dropped (method, path) to the coverage report with reason "dropped: max-endpoints".
Stage 3 โ Generate config (hybrid)
For each endpoint in the merged Endpoint Inventory, generate a mockstar JSON mock entry following
references/mockstar-mapping.md. Use the hybrid strategy:
Native path (preferred for OpenAPI and losslessly-liftable inputs):
The importer writes mock JSON files to <out>/mocks/<tenant>/. Use this path for:
Raw OpenAPI 3.x inputs (most complete).
Postman or HAR inputs that have been converted to OpenAPI 3.x without data loss.
Hand-authored path (for everything else):
For curl, GraphQL, prose, and any Postman/HAR that could not be losslessly lifted, generate
mock JSON entries by hand per references/mockstar-mapping.md and write them to <out>/mocks/<tenant>/:
Map method + path โ match.method + match.path.
Map auth โ match.headers predicate.
Map responses[0] (no when) โ response with kind: "static".
Map responses[] entries with when โ scenarios[] entries.
When --fidelity full (default):
statefulHints โ response.kind: "dynamic" + a minimal TypeScript handler in handlers/.
webhookHints[] โ webhooks[] on the triggering entry.
For GraphQL: route operations via scenarios[].when.body matching on operationName
(NOT via a match.body.jsonpath router on the parent entry).
Prefer literal example values in the initial output; Tier 2 token rewriting is deferred to Stage 4.
Stage 4 โ Enhance
Run mockstar's enhance pass over the generated mocks directory:
When an OpenAPI input exists, add --spec <openapi-file> so the enhancer can cross-reference
the schema for more accurate placeholder selection.
The enhancer rewrites hardcoded IDs and timestamps to Tier 2 tokens ({{faker.uuid}},
{{now.iso}}, {{id("prefix_", 14)}}, etc.) and writes a _mockstarGenerated manifest
(idempotent โ safe to re-run). It does not validate schema conformance; that is proven
by the Stage-5 boot, where mockstar validates every config file with Zod and fails fast on
any invalid entry. Review the enhancer's diff โ the coverage report flags any Tier 2
rewriting that changes confidence from "grounded" to "inferred".
Stage 5 โ Verify
Unless --no-verify is set:
Write a routes TSV file at <out>/mocks/routes.tsv with one line per endpoint:
METHOD<TAB>/path<TAB>EXPECTED_STATUS
Use the primary (no-when) status code from the Endpoint Inventory. For endpoints without
a grounded status, use 200.
Run the smoke suite using the absolute $SMOKE path resolved in Stage 1, passing the
resolved runtime environment and the tenant via MOCKSTAR_SMOKE_TENANT:
# local runtime
MOCKSTAR_SMOKE_RUNTIME=local MOCKSTAR_SMOKE_TENANT=<tenant> sh "$SMOKE" <out>/mocks <out>/mocks/routes.tsv
# docker runtime
MOCKSTAR_SMOKE_RUNTIME=docker MOCKSTAR_SMOKE_IMAGE=<image> MOCKSTAR_SMOKE_TENANT=<tenant> \
sh "$SMOKE" <out>/mocks <out>/mocks/routes.tsv
Tenant selection is mandatory for any non-default tenant. mockstar resolves a tenant
before routing (default modes: path + header). Only the default tenant is served at
the bare path; a named tenant's routes all 404 at the bare path even though the mocks are
valid. smoke.sh sends x-mockstar-tenant: <tenant> on every probe (header mode) so named
tenants resolve โ do not skip MOCKSTAR_SMOKE_TENANT, or a correct project will look broken
and trigger a false fix-loop. See "Tenant selection" under Output layout.
assets/smoke.sh boots mockstar via the chosen runtime. Both paths poll GET /health for
liveness before testing routes (/health is tenant-agnostic; /ready reports drain state).
Set MOCKSTAR_SMOKE_PORT for a non-default smoke port. The server boots via the default
command (bunx @dhaneshpurohit/mockstar <config-root>); the explicit serve subcommand
(bunx @dhaneshpurohit/mockstar serve <config-root>) is equivalent โ both are valid.
For any FAIL lines from the smoke run, inspect the generated config, fix the entry, and
re-run until all routes pass. Do not ship a project with smoke failures. Before editing a
mock in response to a 404, confirm the probe carried the tenant selector โ a bare-path 404
on a named tenant is a selector problem, not a mock problem.
Stage 6 โ Report
Write MOCKSTAR-COVERAGE.md to the output directory root, following the template in
references/coverage-report.md. The report must include:
Endpoints table โ one row per mock: method, path, mock file, source, locator, confidence.
Grounded vs. inferred โ counts and explanation.
Review me (speculative) โ every inferred scenario, dynamic handler, and webhook with
the reason it was inferred and its source.
Gaps โ endpoints or behaviors present in the source docs but not mocked (e.g. prose
that names an endpoint without a path, or a schema type with no example).
Dropped โ endpoints cut by --max-endpoints, with source.
Conflicts โ endpoints described differently across inputs and how conflicts were resolved.
Output layout
The config-root is a mocks/ directory containing one <tenant>/ subdirectory per tenant,
with a sibling handlers/ directory for dynamic handlers. Default layout (when --into is
not set, <service> is derived from the primary spec's title or the target URL hostname):
mock-<service>/
mocks/
<tenant>/ # mockstar mock JSON files (e.g. users.json, orders.json)
handlers/ # TypeScript dynamic handler files (--fidelity full only)
routes.tsv # routes used for smoke testing
MOCKSTAR-COVERAGE.md
Tenant selection (how a consumer reaches the mocks)
mockstar runs tenant resolution as the first routing step, with default modes path and
header. A request that carries no selector falls back to the default tenant. So:
The default tenant is served at the bare path โ GET /pet/findByStatus.
Any named tenant (anything other than default) is reachable only via a selector:
Path mode: prefix the path with /t/<tenant> โ GET /t/petstore/pet/findByStatus
(the /t/<tenant> prefix is stripped before route matching).
Header mode: send x-mockstar-tenant: <tenant> โ GET /pet/findByStatus with the header.
(Subdomain mode <tenant>.host exists but is off by default.)
Consequence for this skill: if --tenant is not default, every consumer โ the smoke test,
the coverage-report examples, and whoever calls the mock โ must use a selector. The coverage
report's Summary states the tenant and the exact selector to use. When in doubt, use default
as the tenant so bare-path access works with zero configuration. No mockstar.config.json is
required for tenant routing: the CLI serve path always enables path + header modes.
Ways to run mockstar
The generated mocks/ config-root is portable across all of mockstar's distribution channels.
Pick per persona; each honours the same tenant selectors above.
Developer โ bunx (hot reload):bunx @dhaneshpurohit/mockstar mocks/ --handlers handlers/.
Editing a mocks/<tenant>/*.json file hot-reloads only that tenant.
Docker (shared/staging/CI): mount mocks/ โ /config/mocks and handlers/ โ
/config/handlers (see "Docker delivery" below). The container binds 0.0.0.0:3000 and is
crash-only โ the orchestrator must set a restart policy (--restart=always, K8s
restartPolicy: Always, or systemd Restart=on-failure). Use /health for liveness and
/ready for load-balancer drain.
SDET โ library embed (in-process, no daemon): import mockstar into a Jest/Vitest/bun test
suite and point it at the same config-root:
Drop the -v handlers bind-mount when no dynamic handlers exist. <abs> is the absolute path to the output directory; <image> is the resolved ref from Stage 0 (tag or digest).
(b) Baked image (share / CI):
The skill renders assets/Dockerfile.template โ filling <TAG> with the detected image ref/digest from Stage 0 โ and writes it as Dockerfile in the output directory root. Build and run with:
The template (assets/Dockerfile.template) copies mocks/ into /config/mocks (and optionally handlers/ into /config/handlers) and inherits the base image's ENTRYPOINT/CMD, which serves /config/mocks on port 3000.
Air-gap fallback (Stage 0 runtime resolution): if docker manifest inspect <image> fails due to no network but the image is already present locally, docker image inspect <image> is sufficient to treat docker as available. The coverage report notes whether the image ref was verified remotely or resolved from the local cache.
References
references/input-adapters.md โ per-format extraction rules and merge/dedupe logic.
references/inventory.schema.json โ JSON Schema for Endpoint Inventory records.
references/mockstar-mapping.md โ IR โ mockstar config field mapping, scenarios, handlers, webhooks, Tier 2 tokens.
references/coverage-report.md โ the MOCKSTAR-COVERAGE.md template.
Assets
assets/extract_text.py โ converts PDF/DOCX inputs and documentation URLs to plain text (uv run).
assets/smoke.sh โ boots mockstar and smoke-tests every route in a TSV file.
assets/fixtures/ โ sample inputs used by the test suite (petstore-mini.yaml, routes.tsv).
Subagent dispatch note
The skill's asset helpers (assets/extract_text.py, assets/smoke.sh) live in this skill's
directory, not in the target repository. Subagents launched in Stage 2 and Stage 5 run from the
target repo's working directory, so a relative assets/ path will not resolve for them. Always
resolve the absolute path to each helper once before dispatching any subagent, and pass the
literal absolute path into the subagent's prompt โ never a relative assets/-prefixed form.
This mirrors the pattern used by the base-in-reality skill for its fetch_sources.py helper.