> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mobileboost.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Changelog

> What shipped in MobileBoost: the Platform, the test agent, the SDKs and the API.

export const PER_PAGE = 50;

export const ENTRIES = [{
  date: "August 28, 2026",
  href: "/changelog/2026-08-28-ios-resigning-keychain-reset",
  title: "iOS re-signing and keychain reset",
  description: "Turn on re-signing for physical iOS devices, so the gateway installs your build directly instead of going through MDM."
}, {
  date: "August 28, 2026",
  href: "/changelog/2026-08-28-blocked-execution-reason",
  title: "Say why a blocked execution never ran",
  description: "A blocked execution now carries the pipeline's own reason for stopping, on the screens that show it."
}, {
  date: "August 28, 2026",
  href: "/changelog/2026-08-28-generation-device-budget",
  title: "A device budget of its own for writing tests",
  description: "Give test generation its own parallel-run budget, so writing a suite cannot stall the suite you are running today."
}, {
  date: "August 27, 2026",
  href: "/changelog/2026-08-27-pre-requests-and-teardown",
  title: "Setup and cleanup calls around a test",
  description: "Give a test HTTP calls to make before it starts and after it finishes, carried through to the device that runs it."
}, {
  date: "August 27, 2026",
  href: "/changelog/2026-08-27-app-quality-issue-clustering",
  title: "App Quality: failures, clustered into issues",
  description: "A dashboard that groups failing executions into defects, so one broken backend reads as one issue rather than eleven."
}, {
  date: "August 25, 2026",
  href: "/changelog/2026-08-25-live-generation-view",
  title: "Watch the automation being written",
  description: "Follow a generation live: the device screen, and the steps the agent is taking as it works out your flow."
}, {
  date: "August 25, 2026",
  href: "/changelog/2026-08-25-environment-variable-vault",
  title: "Environment variables, from a vault",
  description: "Store your organisation's credentials once and hand them to a run through a scoped, revocable grant."
}, {
  date: "August 22, 2026",
  href: "/changelog/2026-08-22-test-schedules",
  title: "Test Schedules: on a cron, or on every build",
  description: "Run a selection of tests on a schedule, or automatically whenever a new build is uploaded."
}, {
  date: "August 21, 2026",
  href: "/changelog/2026-08-21-retry-single-execution",
  title: "Retry a single blocked or failed test",
  description: "Run one test again from its report, against the app the original run installed, without re-running the suite."
}, {
  date: "August 20, 2026",
  href: "/changelog/2026-08-20-mobileboost-local-tunnels",
  title: "MobileBoost Local: test against your own network",
  description: "Name a tunnel on a run, and every device in it reaches your internal services through your network."
}, {
  date: "August 19, 2026",
  href: "/changelog/2026-08-19-email-password-signup",
  title: "Sign up with email and password",
  description: "Register at /signup without waiting for a workspace admin to invite you."
}, {
  date: "August 19, 2026",
  href: "/changelog/2026-08-19-kotlin-sdk-2-7-0",
  title: "Kotlin SDK 2.7.0: the session URL where CI shows it",
  description: "Every failure the SDK raises now carries the MobileBoost session URL, so it reaches the Gradle console and the JUnit XML report."
}, {
  date: "August 18, 2026",
  href: "/changelog/2026-08-18-physical-verification",
  title: "Confirm a simulator failure on real hardware",
  description: "A test that fails on a simulator is re-run on a physical device before self-healing touches it."
}, {
  date: "August 15, 2026",
  href: "/changelog/2026-08-15-generation-by-bundle-id",
  title: "Write automation against a bundle ID",
  description: "Generate a test for an app installed from a store, with no build for us to upload."
}, {
  date: "August 14, 2026",
  href: "/changelog/2026-08-14-platform-mcp-server",
  title: "Platform MCP server",
  description: "Connect your coding agent to your Platform test library: write specs, upload builds, start runs on real devices, and read back what happened step by step."
}, {
  date: "August 13, 2026",
  href: "/changelog/2026-08-13-swift-sdk-1-10-0",
  title: "Swift SDK 1.10.0: typing speed and native steps",
  description: "Control how fast text is typed, and see nativeAction blocks in the session recording."
}, {
  date: "August 13, 2026",
  href: "/changelog/2026-08-13-sdk-sessions-and-prompt-variations",
  title: "Sessions, step by step, and a prompt you can change",
  description: "Read an SDK session as the agent saw it, and try a different prompt against any step without re-running the test."
}, {
  date: "August 13, 2026",
  href: "/changelog/2026-08-13-parallel-self-healing",
  title: "Self-healing, in parallel",
  description: "Failed tests in a parallel run now heal at once rather than one lane at a time."
}, {
  date: "August 13, 2026",
  href: "/changelog/2026-08-13-automated-test-generation",
  title: "Describe a test, get the automation written",
  description: "Creating a Platform test asks an agent to explore your app on a real device, write the pytest file, verify it, and commit it to your repository."
}, {
  date: "August 10, 2026",
  href: "/changelog/2026-08-10-delete-tests",
  title: "Delete tests, and see what depended on them",
  description: "Delete from a row or from a selection, with a confirmation that names what else is about to change."
}, {
  date: "August 5, 2026",
  href: "/changelog/2026-08-05-sdk-session-metadata",
  title: "Every SDK names the run it belongs to",
  description: "Sessions started by the Node, Python, Kotlin and Java SDKs now carry metadata identifying the automated run they came from."
}, {
  date: "July 31, 2026",
  href: "/changelog/2026-07-31-autotest-pr-comments",
  title: "Autotest results land on the pull request",
  description: "A run triggered from a pull request comments its result back onto that pull request."
}, {
  date: "July 29, 2026",
  href: "/changelog/2026-07-29-physical-devices-and-buildless-runs",
  title: "Run on physical devices, with or without a build",
  description: "Target real hardware from a run, and start a run from a bundle ID when there is no build to upload."
}, {
  date: "July 28, 2026",
  href: "/changelog/2026-07-28-run-playback",
  title: "Play a run back, and read it as a checklist",
  description: "Run reports now play: a transport with the steps, a list that follows the playhead, and markers where the agent acted."
}, {
  date: "July 28, 2026",
  href: "/changelog/2026-07-28-github-and-slack-integrations",
  title: "GitHub and Slack, with screens of their own",
  description: "Configure the GitHub App and Slack notifications from Platform, instead of asking us to flip a field."
}, {
  date: "July 27, 2026",
  href: "/changelog/2026-07-27-plain-english-failures",
  title: "Why a test failed, in plain English",
  description: "An execution report leads with an account of what the app actually did, with the traceback moved behind a disclosure."
}, {
  date: "July 26, 2026",
  href: "/changelog/2026-07-26-self-healed-execution-flags",
  title: "See which passes the agent had a hand in",
  description: "Executions the agent re-attempted or edited are marked, and the run report's columns sort."
}, {
  date: "July 26, 2026",
  href: "/changelog/2026-07-26-cancel-runs",
  title: "Cancel a run, or one test of it",
  description: "Stop a queued or running run from the report, or stop a single execution within it."
}, {
  date: "July 24, 2026",
  href: "/changelog/2026-07-24-user-management-roles",
  title: "User management, with roles",
  description: "Members and pending invitations in one table, with admin and user roles and admin-only controls."
}, {
  date: "July 22, 2026",
  href: "/changelog/2026-07-22-mobileboost-platform-launch",
  title: "MobileBoost Platform is live",
  description: "A new web app at platform.mobileboost.io, built around code-backed tests rather than recorded step lists."
}, {
  date: "July 9, 2026",
  href: "/changelog/2026-07-09-qa-studio-mcp-dependencies-inputs",
  title: "QA Studio MCP: dependencies, pre-requests and inputs",
  description: "Manage a test's dependency, its pre-requests and its test inputs from an AI agent, with the same semantics as the web editor."
}, {
  date: "June 30, 2026",
  href: "/changelog/2026-06-30-usage-alerts-and-agent-budgets",
  title: "Know what you are spending before you run out",
  description: "A usage dashboard, email alerts at usage thresholds, and a monthly agent budget per organisation."
}, {
  date: "June 26, 2026",
  href: "/changelog/2026-06-26-node-sdk-1-0-15",
  title: "Node SDK 1.0.15: appId, and smoother gestures",
  description: "Name the app under test explicitly, override backend URLs from the environment, and get more responsive gestures."
}, {
  date: "June 23, 2026",
  href: "/changelog/2026-06-23-caching-controls",
  title: "Caching you can steer",
  description: "Two organisation settings that decide which past sessions your cache is allowed to replay from."
}, {
  date: "June 23, 2026",
  href: "/changelog/2026-06-23-issues-page",
  title: "An Issues page",
  description: "Failures collected on a page of their own, rather than found by reading run after run."
}, {
  date: "June 15, 2026",
  href: "/changelog/2026-06-15-recording-interaction-marks",
  title: "Skip the dead air in a recording",
  description: "Interaction marks on the seek bar, and a playback mode that plays only the seconds around each action."
}, {
  date: "June 15, 2026",
  href: "/changelog/2026-06-15-ai-failure-reports",
  title: "Failure reports, written for you",
  description: "When the review pipeline confirms a failure is a real app bug, an agent writes a self-contained report of it."
}, {
  date: "June 12, 2026",
  href: "/changelog/2026-06-12-pr-comment-review",
  title: "Reply to the agent on a pull request",
  description: "Comment on a pull request the agent opened, and it works out whether you asked for a code change or an answer."
}, {
  date: "June 8, 2026",
  href: "/changelog/2026-06-08-infrastructure-blocked-runs",
  title: "Tell an infrastructure failure apart from a broken app",
  description: "A run that never reached your app is classified as blocked rather than failed, and kept out of the review pipeline."
}, {
  date: "June 2, 2026",
  href: "/changelog/2026-06-02-proposed-prs",
  title: "Review the fixes the agent proposes",
  description: "A page listing the pull requests the agent has drafted from failing runs, before any of them land."
}, {
  date: "May 28, 2026",
  href: "/changelog/2026-05-28-simulator-archive-uploads",
  title: "Simulator archives upload as they come out of Xcode",
  description: "iOS companion binaries are stripped during upload, and CI metadata travels with the build."
}, {
  date: "May 27, 2026",
  href: "/changelog/2026-05-27-suite-tags-in-reports",
  title: "Suite results carry tags, and the emails say which",
  description: "Test tags travel into run documents and result emails, so notifications can be routed by area."
}, {
  date: "May 21, 2026",
  href: "/changelog/2026-05-21-sdk-session-auto-review",
  title: "Auto-review for SDK sessions",
  description: "Sessions from the SDKs get the same review, verdict and prompt revision as tests run from the app."
}, {
  date: "May 19, 2026",
  href: "/changelog/2026-05-19-python-sdk-2-2-0",
  title: "Python SDK 2.2.0: turn self-healing off",
  description: "A global flag to disable self-healing, for suites that want a failure to stay a failure."
}, {
  date: "May 19, 2026",
  href: "/changelog/2026-05-19-optimize-and-validate",
  title: "Optimize and Validate",
  description: "Run a test, let auto-review refine it, and rerun until it holds, in one chained action."
}, {
  date: "May 18, 2026",
  href: "/changelog/2026-05-18-auto-review",
  title: "Auto-review: a second opinion on every run",
  description: "Every finished run is reviewed to decide whether a failure is a real app bug or a test that needs rewording, and the test is refined and retried."
}, {
  date: "May 18, 2026",
  href: "/changelog/2026-05-18-app-handbook",
  title: "App handbook: give the agent your product's vocabulary",
  description: "Write down what your app's terms mean, and every agent run gets that context."
}, {
  date: "May 16, 2026",
  href: "/changelog/2026-05-16-validate-test-content",
  title: "Check a test before you spend a device on it",
  description: "A preflight check reads your test and tells you what the agent will not be able to act on."
}, {
  date: "May 13, 2026",
  href: "/changelog/2026-05-13-runs-api",
  title: "Read a run by id",
  description: "Fetch a run's status and results from the API, scoped to your organisation."
}, {
  date: "May 3, 2026",
  href: "/changelog/2026-05-03-build-picker",
  title: "The build picker, redesigned",
  description: "Pick a build from a three-column picker, and pin the ones you use every day."
}, {
  date: "April 30, 2026",
  href: "/changelog/2026-04-30-mcp-server-and-oauth",
  title: "The MCP server, and OAuth to connect it",
  description: "Connect Claude, Cursor or any MCP client to your tests, authenticated with a browser sign-in rather than a pasted key."
}, {
  date: "April 29, 2026",
  href: "/changelog/2026-04-29-test-recorder",
  title: "Record a test on your simulator, get a draft back",
  description: "Capture your simulator and your voice, and get a written test back from the recording."
}, {
  date: "April 28, 2026",
  href: "/changelog/2026-04-28-markdown-test-editor",
  title: "The markdown test editor",
  description: "Write a test as a document with a Goal, Context, Steps and Success Criteria, instead of a list of commands."
}, {
  date: "April 24, 2026",
  href: "/changelog/2026-04-24-pre-requests-and-teardown-qa-studio",
  title: "Pre-requests and teardown requests",
  description: "Give a test HTTP calls to make before it starts and after it finishes, so setup and cleanup stay out of the test body."
}, {
  date: "April 20, 2026",
  href: "/changelog/2026-04-20-node-sdk-1-0-14",
  title: "Node SDK 1.0.14: the session link in your logs",
  description: "Every run prints its session link, and reports how many steps ran and how many hit the cache."
}, {
  date: "April 16, 2026",
  href: "/changelog/2026-04-16-api-keys",
  title: "API keys, and endpoints that require them",
  description: "Create and manage API keys in the app, and authenticate the data endpoints with them."
}, {
  date: "April 8, 2026",
  href: "/changelog/2026-04-08-open-app-clip-link",
  title: "openAppClipLink",
  description: "Open an App Clip or a deep link directly, instead of navigating to it."
}, {
  date: "April 2, 2026",
  href: "/changelog/2026-04-02-push-files-to-device",
  title: "Push a file to the device before a test",
  description: "Upload an image, video or document from the test editor and have it on the device when the test starts."
}, {
  date: "April 2, 2026",
  href: "/changelog/2026-04-02-github-app",
  title: "GitHub App: a check on every run",
  description: "Install the MobileBoost GitHub App and get run results as a check on the commit that triggered them."
}, {
  date: "March 31, 2026",
  href: "/changelog/2026-03-31-ephemeral-tests",
  title: "Ephemeral tests: run a flow from CI without saving it",
  description: "Send a test definition with the run and have it execute without ever being stored in your library."
}, {
  date: "March 26, 2026",
  href: "/changelog/2026-03-26-swift-sdk-native-first",
  title: "Swift SDK 1.9: native-first, with AI fallback",
  description: "Write a step as native XCTest code and let the agent take over only when the native path throws."
}, {
  date: "March 25, 2026",
  href: "/changelog/2026-03-25-tests-crud-api",
  title: "Manage tests over the API",
  description: "Create, read, update and delete tests through the public API, with their pre-requests, inputs and launch parameters."
}, {
  date: "March 11, 2026",
  href: "/changelog/2026-03-11-strict-caching",
  title: "Strict caching, with a syncing mechanism",
  description: "Replay a single baseline session in order and resync when the app diverges, instead of matching steps across whichever sessions look similar."
}, {
  date: "March 11, 2026",
  href: "/changelog/2026-03-11-saml-sso",
  title: "SAML SSO, and an email-first sign-in",
  description: "Sign in through your identity provider, on a login screen that asks for your email first and then routes you."
}, {
  date: "March 9, 2026",
  href: "/changelog/2026-03-09-multitap-and-longpress-duration",
  title: "multiTap, and a duration for longPressOn",
  description: "Tap an element several times in a row, and hold a press for as long as the interaction needs."
}, {
  date: "March 3, 2026",
  href: "/changelog/2026-03-03-dynamic-values-in-caching",
  title: "Caching that knows your dynamic values",
  description: "Mark the parts of a step that change every run, so the cache matches on what is stable and the agent handles the rest."
}, {
  date: "February 27, 2026",
  href: "/changelog/2026-02-27-kotlin-sdk-2-1-0",
  title: "Kotlin SDK 2.1.0: caching mode, and Compose",
  description: "Set a caching mode per execute call, assert against Compose UI, and end a session with an explicit verdict."
}, {
  date: "February 25, 2026",
  href: "/changelog/2026-02-25-node-sdk-1-0-11",
  title: "Node SDK 1.0.11: faster screenshots",
  description: "Screenshots are compressed before upload and taken over ADB on Android, cutting the per-step cost of a run."
}, {
  date: "February 23, 2026",
  href: "/changelog/2026-02-23-session-step-breakdown",
  title: "See how a session split between local, cached and AI steps",
  description: "Every session shows how many of its steps ran locally, came from the cache, or went to the agent."
}, {
  date: "February 16, 2026",
  href: "/changelog/2026-02-16-complete-task-when-step-completed",
  title: "Let a step finish the task",
  description: "An SDK flow can end as soon as a step reports the task done, rather than running to the end of the list."
}, {
  date: "February 12, 2026",
  href: "/changelog/2026-02-12-remembered-values",
  title: "Remember a value, use it later",
  description: "Capture something the app shows you and refer to it in a later step."
}, {
  date: "February 9, 2026",
  href: "/changelog/2026-02-09-tapon-center",
  title: "tapOn center",
  description: "Tap the middle of the screen without describing what is there."
}, {
  date: "January 27, 2026",
  href: "/changelog/2026-01-27-caching-in-parallel",
  title: "Cache lookups, done in parallel",
  description: "Cached step comparisons run in parallel with a bounded per-step limit, so a cached run starts faster."
}, {
  date: "January 26, 2026",
  href: "/changelog/2026-01-26-offline-testing",
  title: "Test what your app does offline",
  description: "Take the device off the network mid-test and put it back, to check the states most suites never reach."
}, {
  date: "January 22, 2026",
  href: "/changelog/2026-01-22-swift-sdk-1-7-0",
  title: "Swift SDK 1.7.0: synchronous wrappers with timeouts",
  description: "Call the SDK from a synchronous XCTest without writing async plumbing, with a timeout on every call."
}, {
  date: "January 20, 2026",
  href: "/changelog/2026-01-20-global-test-inputs",
  title: "Test inputs you define once",
  description: "Define an input at organisation level and every test picks it up by default, instead of repeating it per test."
}, {
  date: "January 15, 2026",
  href: "/changelog/2026-01-15-launch-parameters",
  title: "Launch parameters on every session",
  description: "Pass launch arguments and environment values to the app when a session starts it."
}, {
  date: "January 14, 2026",
  href: "/changelog/2026-01-14-node-sdk-config-and-stable-screens",
  title: "Node SDK: config from the environment, and steadier screens",
  description: "Configure the driver from environment variables, and let the SDK wait for the screen to settle between steps."
}, {
  date: "January 12, 2026",
  href: "/changelog/2026-01-12-mobileboost-local-recording",
  title: "Record swipes, slides and Enter locally",
  description: "The local recorder captures swipe and scroll gestures with direction and distance, presses Enter, and shows each step as it executes."
}, {
  date: "January 5, 2026",
  href: "/changelog/2026-01-05-regions-of-interest",
  title: "Scope an assertion to part of the screen",
  description: "Point an assertion or a cached step at a region rather than the whole screen, so the parts that always change stop mattering."
}, {
  date: "December 18, 2025",
  href: "/changelog/2025-12-18-sdk-zoom",
  title: "Zoom gestures from the SDKs",
  description: "Pinch to zoom in and out from an SDK session."
}, {
  date: "December 18, 2025",
  href: "/changelog/2025-12-18-java-sdk-self-healing-flag",
  title: "Java SDK: one switch for self-healing",
  description: "A global flag to enable or disable self-healing, and sessions that fail on an assertion error."
}, {
  date: "December 9, 2025",
  href: "/changelog/2025-12-09-mobileboost-studio",
  title: "MobileBoost Studio: author tests on your own machine",
  description: "A local app that drives a simulator or emulator, records what you do, and writes the test file into your repository."
}, {
  date: "December 3, 2025",
  href: "/changelog/2025-12-03-swift-sdk-caching-mode",
  title: "Swift SDK: caching mode, and cache hits in the log",
  description: "Set a caching mode per session and see which steps came from the cache."
}, {
  date: "December 2, 2025",
  href: "/changelog/2025-12-02-browserstack-devices",
  title: "BrowserStack devices in the picker",
  description: "Choose a BrowserStack device by name, with locale, language and zoom supported."
}, {
  date: "November 28, 2025",
  href: "/changelog/2025-11-28-ignored-elements",
  title: "Elements a test should never touch",
  description: "Name the elements the agent should ignore, so it stops choosing them."
}, {
  date: "November 26, 2025",
  href: "/changelog/2025-11-26-claude-agent-default",
  title: "claude-agent becomes the default vision model",
  description: "New runs use claude-agent for vision steps unless an organisation has chosen otherwise."
}, {
  date: "November 25, 2025",
  href: "/changelog/2025-11-25-sdk-caching-rebuilt",
  title: "SDK caching, rebuilt",
  description: "Cached steps are keyed on the step itself, with scale multipliers so a cache survives a different screen size."
}, {
  date: "November 13, 2025",
  href: "/changelog/2025-11-13-python-sdk-self-healing",
  title: "Self-healing in the Python SDK",
  description: "A self-healing driver for Python, with automatic retries on assertions and checks."
}, {
  date: "November 4, 2025",
  href: "/changelog/2025-11-04-jira-tickets",
  title: "Raise a Jira ticket from a finding",
  description: "Turn a localization finding into a Jira ticket without leaving the review screen."
}, {
  date: "October 23, 2025",
  href: "/changelog/2025-10-23-ocr-assert-visible",
  title: "OCR-backed assert visible",
  description: "Assertions can read text out of the pixels, for the strings that are not in the view hierarchy."
}, {
  date: "October 17, 2025",
  href: "/changelog/2025-10-17-device-hub-redis",
  title: "Sessions on Redis, and a device health endpoint",
  description: "Session state moves to Redis, and the device pool exposes a health endpoint."
}, {
  date: "October 14, 2025",
  href: "/changelog/2025-10-14-swift-sdk-retries",
  title: "Swift SDK: retries, and the session URL",
  description: "Network calls retry, assertions retry, and the session URL is tracked so a failure can point at it."
}, {
  date: "October 14, 2025",
  href: "/changelog/2025-10-14-localization-visual-review",
  title: "Localization: a visual review queue",
  description: "Step through localization findings against the screenshot each came from, and accept or dismiss them."
}, {
  date: "October 10, 2025",
  href: "/changelog/2025-10-10-physical-device-toggle",
  title: "Run on a physical device from the editor",
  description: "A toggle on the editor and on cloud runs that sends the test to real hardware."
}, {
  date: "October 9, 2025",
  href: "/changelog/2025-10-09-sentry-logs",
  title: "Sentry logs on a run",
  description: "See the errors your app reported to Sentry during a run, next to the run itself."
}, {
  date: "October 9, 2025",
  href: "/changelog/2025-10-09-app-distribution-oauth",
  title: "Connect App Distribution over OAuth",
  description: "Authorise once in the browser and clone builds from App Distribution, without pasting a service account key."
}, {
  date: "September 29, 2025",
  href: "/changelog/2025-09-29-page-source-context",
  title: "Page source in the agent's context",
  description: "The agent sees the view hierarchy alongside the screenshot, so it can act on elements a screenshot cannot describe."
}, {
  date: "September 24, 2025",
  href: "/changelog/2025-09-24-assert-visible-ai-fallback",
  title: "assert visible, with an AI fallback",
  description: "When a text assertion cannot find its string, the agent looks at the screen before the test fails."
}, {
  date: "September 23, 2025",
  href: "/changelog/2025-09-23-new-editor-assistant",
  title: "A new editor assistant",
  description: "The assistant that helps write a test, rebuilt."
}, {
  date: "September 15, 2025",
  href: "/changelog/2025-09-15-java-sdk-self-healing",
  title: "Self-healing for the Java SDK",
  description: "When a locator stops matching, the agent finds the element and the test carries on instead of failing."
}, {
  date: "September 4, 2025",
  href: "/changelog/2025-09-04-localization-csv",
  title: "Export localization findings",
  description: "Take the localization results out as CSV, with their categories, for whoever fixes the strings."
}, {
  date: "September 2, 2025",
  href: "/changelog/2025-09-02-localization-locale-rules",
  title: "Localization: rules and exceptions per locale",
  description: "Teach the localization check what is correct in each language, and what to stop flagging."
}, {
  date: "August 28, 2025",
  href: "/changelog/2025-08-28-usage-split-by-vision",
  title: "Usage, split by vision and non-vision",
  description: "Vision steps, non-vision steps, SDK steps and localization checks are counted separately."
}, {
  date: "August 28, 2025",
  href: "/changelog/2025-08-28-localization-testing",
  title: "Localization testing",
  description: "Every screenshot in a run is read with OCR and checked against the locale it was meant to be in, so truncated and untranslated strings get found."
}, {
  date: "August 27, 2025",
  href: "/changelog/2025-08-27-web-chromium-driver",
  title: "Web testing with the Chromium driver",
  description: "Point an SDK session at a Chromium Appium driver and test a web app the same way."
}, {
  date: "August 18, 2025",
  href: "/changelog/2025-08-18-listen-command",
  title: "listen: assert what the app said",
  description: "Capture what the app plays back and assert on the words in it."
}, {
  date: "August 5, 2025",
  href: "/changelog/2025-08-05-assert-not-visible",
  title: "assert not visible",
  description: "Assert that something is gone, which is a different check from asserting something is there."
}, {
  date: "August 4, 2025",
  href: "/changelog/2025-08-04-play-audio",
  title: "Play audio into a test",
  description: "Feed a sound file to the app mid-test, for the flows that listen."
}, {
  date: "July 29, 2025",
  href: "/changelog/2025-07-29-restart-app",
  title: "restartApp",
  description: "Restart the app mid-test, to check what survives a cold start."
}, {
  date: "July 24, 2025",
  href: "/changelog/2025-07-24-info-bar-commands",
  title: "openInfoBar and closeInfoBar",
  description: "Pull down the notification shade and put it back, for the flows that go through it."
}, {
  date: "July 21, 2025",
  href: "/changelog/2025-07-21-dual-platform-instances",
  title: "One machine, both platforms",
  description: "A bare metal instance can serve iOS and Android sessions, instead of being dedicated to one."
}, {
  date: "July 11, 2025",
  href: "/changelog/2025-07-11-app-distribution",
  title: "Pull builds from App Distribution",
  description: "Connect Firebase App Distribution and test the builds already being distributed to your testers."
}, {
  date: "July 3, 2025",
  href: "/changelog/2025-07-03-run-by-build-id",
  title: "Run against a specific build",
  description: "Name a build id on a run and get exactly that build, not the newest one for the platform."
}, {
  date: "June 29, 2025",
  href: "/changelog/2025-06-29-take-screenshot",
  title: "takeScreenshot, with a label",
  description: "Capture a screenshot at a point you choose and give it a name you will recognise in the report."
}, {
  date: "June 26, 2025",
  href: "/changelog/2025-06-26-grant-permissions",
  title: "Grant permissions on launch",
  description: "Start the app with its permissions already granted, instead of dismissing dialogs in every test."
}, {
  date: "June 17, 2025",
  href: "/changelog/2025-06-17-remove-text-sdk",
  title: "removeText on the SDKs",
  description: "Clear a field from an SDK test rather than selecting and retyping over it."
}, {
  date: "June 13, 2025",
  href: "/changelog/2025-06-13-per-step-cache-control",
  title: "Turn caching off for a single step",
  description: "Exclude one step from the cache without changing anything for the rest of the test."
}, {
  date: "June 11, 2025",
  href: "/changelog/2025-06-11-zoom-in-browser-device",
  title: "Zoom on the in-browser device",
  description: "Pinch to zoom in and out on the device in your browser, including on iOS."
}, {
  date: "June 9, 2025",
  href: "/changelog/2025-06-09-browserstack",
  title: "Run on BrowserStack devices",
  description: "Point a run at your BrowserStack account and use their device cloud, with your own credentials."
}, {
  date: "May 29, 2025",
  href: "/changelog/2025-05-29-slack-webhooks",
  title: "Send results to your own Slack webhook",
  description: "Point run notifications at a webhook you control, rather than a single fixed channel."
}, {
  date: "May 22, 2025",
  href: "/changelog/2025-05-22-kotlin-sdk-1-2-0",
  title: "Kotlin SDK 1.2.0",
  description: "Steadier waiting, cleaner key input, and UI Automator for the parts Espresso cannot reach."
}, {
  date: "May 20, 2025",
  href: "/changelog/2025-05-20-clone-test",
  title: "Clone a test",
  description: "Copy a test with its steps, inputs and settings, as a starting point for the next one."
}, {
  date: "May 14, 2025",
  href: "/changelog/2025-05-14-custom-type-strings",
  title: "Type exactly what you mean",
  description: "The type command takes custom strings, including the characters that used to need a workaround."
}, {
  date: "May 14, 2025",
  href: "/changelog/2025-05-14-csv-export-device-os",
  title: "Run exports name the device and OS",
  description: "CSV exports carry the device and OS version each result came from."
}, {
  date: "May 12, 2025",
  href: "/changelog/2025-05-12-biometry-and-scroll-to-bottom",
  title: "biometry and scrollToBottom",
  description: "Answer a biometric prompt on the in-browser device, and scroll a list to its end in one step."
}, {
  date: "April 30, 2025",
  href: "/changelog/2025-04-30-datetime-command",
  title: "datetime",
  description: "Insert a date or time computed at run time, in the format the app expects."
}, {
  date: "April 30, 2025",
  href: "/changelog/2025-04-30-pre-requests-responses",
  title: "Read what a pre-request returned",
  description: "Parse a pre-request's response and use values from it in the test that follows."
}, {
  date: "April 28, 2025",
  href: "/changelog/2025-04-28-env-vars-in-inputs",
  title: "Environment variables in test inputs",
  description: "Refer to an environment variable from a test input, so credentials stay out of the test."
}, {
  date: "April 24, 2025",
  href: "/changelog/2025-04-24-code-generation",
  title: "Turn a passing run into code",
  description: "Generate SDK code from a run that worked, so a test written in the app can move into your repository."
}, {
  date: "April 23, 2025",
  href: "/changelog/2025-04-23-shake-command",
  title: "Shake the device",
  description: "Trigger the shake gesture, for the debug menus and feedback flows behind it."
}, {
  date: "March 28, 2025",
  href: "/changelog/2025-03-28-curl-request",
  title: "Call an API from a test",
  description: "Make an HTTP request mid-test, to set up state or check what the backend recorded."
}, {
  date: "March 26, 2025",
  href: "/changelog/2025-03-26-go-offline",
  title: "Go offline mid-test",
  description: "Cut the device's network during a test and restore it, to reach the states that only appear when the connection drops."
}, {
  date: "March 25, 2025",
  href: "/changelog/2025-03-25-assert-visible-text",
  title: "assert visible text",
  description: "Assert on exact text rather than describing what should be on screen."
}, {
  date: "March 20, 2025",
  href: "/changelog/2025-03-20-local-commands-goto-press",
  title: "go to, press, and line breaks in test inputs",
  description: "Navigate straight to a screen, press a key, and put multi-line values in test inputs."
}, {
  date: "March 18, 2025",
  href: "/changelog/2025-03-18-claude-agent-vision",
  title: "Claude as the vision model",
  description: "Runs can use Claude for vision steps, with action history handled the way the model expects."
}, {
  date: "March 16, 2025",
  href: "/changelog/2025-03-16-test-search",
  title: "Search your tests",
  description: "Find a test by name or by what is in it, across the whole library."
}, {
  date: "February 20, 2025",
  href: "/changelog/2025-02-20-kotlin-sdk-launch",
  title: "The Kotlin SDK",
  description: "Drive MobileBoost from an Android instrumentation test, with screenshot stability detection built in."
}, {
  date: "February 13, 2025",
  href: "/changelog/2025-02-13-stealth-mode",
  title: "Stealth mode",
  description: "Run a suite without notifying anyone, for the runs that are not about the app."
}, {
  date: "February 10, 2025",
  href: "/changelog/2025-02-10-random-numbers",
  title: "randomNumber and randomNumberInRange",
  description: "Generate a fresh number each run, for the fields that reject a value they have seen before."
}, {
  date: "February 7, 2025",
  href: "/changelog/2025-02-07-run-metadata",
  title: "Attach metadata to a run",
  description: "Send your own fields with a run and get them back in the results and the Slack notification."
}, {
  date: "February 6, 2025",
  href: "/changelog/2025-02-06-swift-sdk-launch",
  title: "The Swift SDK",
  description: "Drive MobileBoost from XCUITest, with a native executor for steps that do not need the agent."
}, {
  date: "February 6, 2025",
  href: "/changelog/2025-02-06-test-references",
  title: "Reference one test from another",
  description: "Call an existing test from inside another one, instead of copying its steps."
}, {
  date: "January 28, 2025",
  href: "/changelog/2025-01-28-subtests",
  title: "Subtests",
  description: "Break a long flow into pieces that run in order and report separately."
}, {
  date: "January 23, 2025",
  href: "/changelog/2025-01-23-in-browser-device",
  title: "Edit and run a test on an in-browser device",
  description: "Write a test with a live device beside it in the browser, and watch each step run as you write it."
}, {
  date: "January 17, 2025",
  href: "/changelog/2025-01-17-device-hub",
  title: "Devices, assigned from a pool",
  description: "Sessions take a device from a managed pool with per-organisation limits, instead of being pinned to a fixed machine."
}, {
  date: "January 13, 2025",
  href: "/changelog/2025-01-13-usage-tracking",
  title: "Usage, counted per organisation",
  description: "Every model call a run makes is logged against the organisation that made it."
}, {
  date: "January 7, 2025",
  href: "/changelog/2025-01-07-match-biometry",
  title: "Test the Face ID and fingerprint prompts",
  description: "Answer a biometric prompt from a test, instead of stopping at it."
}];

export const ChangelogList = () => {
  const [page, setPage] = useState(0);
  const pageCount = Math.ceil(ENTRIES.length / PER_PAGE);
  const shown = ENTRIES.slice(page * PER_PAGE, (page + 1) * PER_PAGE);
  const go = n => {
    setPage(n);
    if (typeof window !== "undefined") window.scrollTo({
      top: 0,
      behavior: "smooth"
    });
  };
  return <div className="changelog">
      <div className="changelog-list">
        {shown.map(e => <a key={e.href} href={e.href} className="changelog-row">
            <div className="changelog-row-head">
              <span className="changelog-row-title">{e.title}</span>
              <span className="changelog-row-date">{e.date}</span>
            </div>
            <p className="changelog-row-desc">{e.description}</p>
          </a>)}
      </div>
      {pageCount > 1 && <nav className="changelog-pager" aria-label="Changelog pages">
          <button type="button" className="changelog-pager-step" onClick={() => go(page - 1)} disabled={page === 0}>
            Previous
          </button>
          <div className="changelog-pager-pages">
            {Array.from({
    length: pageCount
  }, (_, i) => <button key={i} type="button" className={"changelog-pager-page" + (i === page ? " is-active" : "")} onClick={() => go(i)} aria-current={i === page ? "page" : undefined}>
                {i + 1}
              </button>)}
          </div>
          <button type="button" className="changelog-pager-step" onClick={() => go(page + 1)} disabled={page === pageCount - 1}>
            Next
          </button>
        </nav>}
    </div>;
};

Everything we ship that changes what you can do, newest first.

<ChangelogList />
