# Clerk changelog

What changed in each Clerk simulator release, newest first.

What changed in each Clerk simulator release, newest first.

## v0.0.5 — 2026-11-06

1. **A key that does not start with `sk_` is refused on every route.** Every Backend API route returns 401 `clerk_key_invalid` for a bearer value that does not start with `sk_`, as Clerk does. A second `Authorization` header gets 401 `authorization_header_format_invalid`, where Clerk returns a 400 page. Deleting an organization and updating a membership used to carry out such requests, and the other routes returned a 401 or 403 that varied by route.

2. **The docs gain an Errors and limits section.** It shows the `errors` body with `code`, `long_message`, `meta.param_name` and `clerk_trace_id`, how each list pages with `limit`, `offset` and `starting_after`, and what a repeated create returns.

## v0.0.4 — 2026-11-05

1. **The twin documents its own control plane in Swagger.** `/_rystic/swagger` now lists a **Rystic control plane** spec, served at `/_rystic/swagger/spec/rystic-control-plane.json`, describing the `/_rystic/*` routes this twin serves (its scenarios, inspect views and seedable registers by name) and its `/_twin/*` routes.

2. **A state dump seeds back as it was, and the next record gets a fresh id.** `GET /_rystic/inspect` posted to `POST /_rystic/seed` after a reset restores every record where it was, per-caller records included, which used to land under a doubled key. The next record created after any seed passes every uuid and event id the simulator minted that the seed holds. `GET /_rystic/inspect?view=sequences` lists every id counter, and a world document's new `sequences` key restores them, so ids the simulator renders from a counter continue where the dump left off.

3. **A slow client no longer holds up the others.** The simulator reads a request's whole body before it starts serving it and sends the answer after, so a client that uploads slowly, or reads a large answer slowly, no longer delays other clients' requests. Answers are unchanged; one larger than 4 MiB still makes other requests wait while it is sent.

4. **The call log shows what each call asked for and whether it succeeded.** Each `GET /_rystic/calls` entry now carries `args`, the call's query and body arguments with credentials redacted (long values cut, file contents left out), and `ok`, false for an answer that is not 2xx. A path the simulator does not serve is marked `unknown_route: true`. `?tail=N` returns only the last N calls, and `dropped` counts the calls the log no longer keeps.

5. **Coverage lists the browser assets.** The docs' Coverage section now lists `GET` and `HEAD` for `/clerk.js`, `/clerk-ui.js`, `/clerk.css` and `/preview/{file}`, which the simulator already served, and counts them in its route total.

6. **The docs are one page, with a page for the browser companion.** The archive ships `README.md` in place of `HOWTO.md` and `SCENARIOS.md`, with the same sections in the same order as every Rystic simulator's page, and `CHANGELOG.md` beside it. The browser companion has its own page under `docs/features/`, and every example on these pages runs as written against a fresh simulator.

7. **The docs page links the admin token section.** The page now sends you to the admin token's section of the shared-simulators page.

8. **Scenario descriptions use customer terms.** The Scenarios table and `--list-scenarios` describe each scenario in American spelling, with no internal references.

9. **The Scenarios table is easier to scan.** Each row says in a line what the scenario is for, and a list below the table says what each scenario holds.

10. **Pro starts with a 14-day trial.** Free has ended, so every simulator is on Pro and Enterprise, and the docs name only those plans.

11. **Limitations is shorter to read.** It opens with the known issues and one sentence counting the rest. The detailed lists follow, and the website folds them behind "Show all limitations".

12. **The page has no Plans section.** The Quickstart names the plans that run the simulator, and the pricing page lists what each plan includes.

13. **The docs read more plainly, and each difference from Clerk is marked.** Sentences are shorter, and each behavior that differs from Clerk is marked "Differs from Clerk" where it's described. Rules with several outcomes, such as what a missing key returns, which `Clerk-API-Version` values the simulator serves and which writes record a webhook event, are tables. The Auth section also names the two requests that go through with a key not starting with `sk_` or a repeated `Authorization` header: deleting an organization and updating a membership. Quickstart, Auth, Seeding state and the reset section keep to this simulator's own facts, leaving the rules every simulator shares to the shared pages.

## v0.0.3 — 2026-10-27

1. **The HOWTO documents the world document `POST /_rystic/seed` takes.** A direct seed takes a whole scenario file, with its `clock`, `rng_seed`, `credentials` and `events`, not only the bare register map; the HOWTO now says so, with an example that binds a token and schedules a call.

2. **Indexed list query parameters.** A list filter sent as `user_id[0]=…&user_id[1]=…`, as some SDKs encode arrays, reads the same as the repeated `user_id=…&user_id=…` on `GET /users`, `GET /users/count`, `GET /organizations` and `GET /organizations/{organization_id}/memberships`.

3. **Swagger UI to read and call the twin from the browser.** `/_rystic/swagger`, linked from the state UI header, is Swagger UI over the published API trimmed to the operations this twin serves; Try it out sends each request to the twin.

## v0.0.2 — 2026-10-12

1. **`clerk_acme_tenant` plays a timeline.** Its backend, bound to `sk_test_acme_backend`, updates Sam's metadata two hours after the pinned clock, creates Priya Raman a day in, promotes Yuki to admin, moves the organization to the `scale` plan on day three and removes Iris on day five, all through the Backend API; advance the clock to watch the tenant change.

2. **A seeded user, organization or membership sends its created webhook.** A record a world's timeline `seed` event or a bare `POST /_rystic/seed` creates now sends `user.created`, `organization.created` or `organizationMembership.created`, as the create operation does, to the egress log and any configured webhook endpoint. A world's starting snapshot sends none.

3. **Session tokens and webhooks can follow a shifted app clock.** `POST /_rystic/clock {"wall_offset_seconds": N}` stamps session JWT `iat`, `nbf` and `exp` and the webhook `svix-timestamp` N seconds past the wall clock, so an app whose own clock you moved forward (as `sandbox clock -advance` does) still accepts them; `0` or `/_rystic/reset` puts it back.

4. **Every Backend API call without a secret key is refused as Clerk refuses it.** A request with no `Authorization` header now answers `401` with `errors[0].code = authorization_header_format_invalid` on every operation, ahead of the operation's own checks. `DELETE /v1/organizations/{id}` and `PATCH /v1/organizations/{id}/memberships/{user_id}` used to succeed without a key, and other operations answered with differing `authentication_invalid` bodies.

## v0.0.1 — 2026-10-11

1. **A local Clerk for your app's users, organizations and sign-in.** The first release of the Clerk twin: the 20 Backend API operations on users and their metadata, organizations with their metadata and memberships, at `Clerk-API-Version: 2026-05-12`, served from a model validated against a live Clerk development instance, and a browser companion that serves a lookalike `clerk.js` so a `@clerk/nextjs` app signs users in against the same state. It runs on Pro and Enterprise. Point `@clerk/backend` at it with any `sk_` key (`HOWTO.md` shows how); no email is sent and no real instance changes.

2. **Users and their metadata, as Clerk keeps them.** `POST /v1/users` stores each email address in lowercase, `GET /v1/users?email_address=` finds a user by any letter case of their address, and an address that differs from a taken one only in case answers 422 `form_identifier_exists`; a malformed one answers 422 `form_param_format_invalid`. `GET /v1/users` refuses an `order_by` that names no sortable field with 422 `form_param_value_invalid`. `PATCH` and `PUT /v1/users/{user_id}/metadata` merge and replace metadata, and `DELETE /v1/users/{user_id}` removes the user's organization memberships. Every `image_url` and `profile_image_url` leads to a PNG the twin serves under `/preview/`.

3. **Organizations, their metadata and their members.** An organization created with `created_by` lists its creator as an `org:admin` member right after the create, and `include_members_count=true` counts them. `PATCH /v1/organizations/{organization_id}/metadata` deep-merges `public_metadata` and `private_metadata`, removing a key set to `null`, and `PUT` replaces each field it names whole. Writes and lists answer with the keys Clerk's answers carry.

4. **`Clerk-API-Version` is checked on every route and echoed.** `2021-02-05`, `2024-10-01`, `2025-04-10`, `2025-11-10` and `2026-05-12` (the default) are accepted and echoed in `clerk-api-version`, and any other value answers 400 `api_version_invalid`. At `2026-05-12`, metadata sent to `PATCH /v1/users/{user_id}` or `PATCH /v1/organizations/{organization_id}` answers 422 `form_param_deprecated`, as Clerk does: write it through the `/metadata` routes.

5. **A browser sign-in for `@clerk/nextjs`.** Point `NEXT_PUBLIC_CLERK_JS_URL` and `NEXT_PUBLIC_CLERK_UI_URL` at the twin's `/clerk.js` and `/clerk-ui.js` and your app gets email sign-in and sign-up with consent, **Continue with GitHub** and **Continue with Google** buttons that sign in local test identities, organization creation and selection, and member invitation, role changes and removal; signing in as an invited address joins its organization with no email sent. Sessions are RS256 tokens stamped on the wall clock your site verifies them against, and the SDK middleware's handshake is answered by the twin, so a sandboxed site never leaves it. Boot the twin with your own RSA key, your site's origin and its own origin; `GET /_twin/config` gives the publishable key, the public PEM and the proxy URL.

6. **Webhooks Clerk would send, signed with Svix headers.** Every user write, organization create, update and delete, and membership write, from the Backend API or the browser, records `user.*`, `organization.*` or `organizationMembership.*` in `GET /_rystic/egress`; the organization `/metadata` routes record none. Boot with `CLERK_TWIN_WEBHOOK_URL` and a `whsec_` `CLERK_TWIN_WEBHOOK_SECRET` and each is also delivered, its `svix-timestamp` on the wall clock so your receiver's five-minute window holds however long the twin sat idle. A failed delivery never undoes the write. Event shapes follow Clerk's documentation and are not measured against live deliveries.

7. **Five shipped worlds.** `--scenario clerk_acme_tenant` boots Acme Robotics: five users in one organization, two pending invitations and three live sessions. `clerk_holdco_orgs` holds one identity across three organizations, `clerk_invite_backlog` an organization at its ten-seat cap with eight invitations pending, `clerk_session_sweep` six sessions from lapsed to live, and `clerk_solo_founder` one user and her organization; `SCENARIOS.md` says what each is for. Without `--scenario` the twin boots an empty instance, `POST /_rystic/seed` lands users, organizations, memberships, sessions and invitations directly, and `POST /_rystic/reset` rewinds the ID sequence, so two identical runs from a pinned clock give byte-identical users and organizations.

8. **Measured against a live Clerk development instance.** The 2026-10-07 full-suite round matched 100 of 100 Backend API probes, with 0 inconclusive. `HOWTO.md` states what the suite leaves out and the differences this release ships with: typed query parameters are not validated, responses carry no `x-clerk-trace-id` header, an unserved route answers a plain 404, not Clerk's `resource_not_found`, and deleting an organization or changing a membership's role checks no secret key.

---

Source: https://www.rystic.ai/docs/simulators/clerk/changelog · Markdown: https://www.rystic.ai/docs/simulators/clerk/changelog.md
