QAKit
An AI agent that QA-tests your iOS app on a real iPhone.
Every screen, every button, dark mode, large text, VoiceOver, a crash watch, Apple's accessibility audit, and a release verdict with evidence.
Plus the two checks a release needs behind it: would your tests notice a bug, and does your copy say what it claims.
One walk, one phone. Onboarding, every scroll position, every button tapped once, the audit on each screen. 29 frames from one test's attachments. |
Same walk, three variants. --variant default --variant dark --variant large-text switches the phone, not the app. The examples/Notes app. |
Sixty seconds
pip install qa-agent-kit # qakit-device, qakit-release-checks, qakit-mutate, qakit-prose, qakit-install-skills
qakit-device doctor --manifest myapp/release/testing/device_qa.json # Xcode, the phone, signing, the manifest
qakit-device test --manifest myapp/release/testing/device_qa.json --suite qa --variant dark --variant large-text
qakit-device test --manifest myapp/release/testing/device_qa.json --suite qa --variant dark --simulator # no phone yet? the same run on a simulator
A run leaves summary.json, a contact sheet of every screenshot, the audit report per screen and any crash logs
(docs/report.md). Your walkthrough test is a few lines on top of the Swift package:
import XCTest
import QAKit
QA.walk(app, "settings", in: self, deny: ["Delete"]) { QA.settle(app, on: screen, in: self) { relaunch() } }
QA.audit(app, "detail", in: self) // Apple's accessibility audit, every issue in one report, known classes explained
QA.answerSystemAlert() // permission prompts, in the phone's language
Give the procedure to the agent you already use:
claude plugin marketplace add younatics/QAKit && claude plugin install qakit@younatics # Claude Code: skills + MCP tools
qakit-install-skills --target codex # or cursor, gemini, all; --scope user
claude mcp add qakit -- python3 /path/to/qakit/mcp/server.py # any MCP client: doctor, test, shots, crashes, release checks, mutation, prose, verdict
What the agent does that a test runner does not
- Walks the app the way a tester does.
QA.walkscreenshots the screen, runs the accessibility audit, taps every visible button once at every scroll position, checks the app is still in front and comes back. Nothing random. - Changes the phone, not the app. Dark mode, accessibility text sizes, a simulated location and VoiceOver are set on
the device through Xcode 27's
devicectl, so system alerts and other apps render as your users will see them. - Explains the audit instead of drowning in it. One report per screen; the classes that are never a defect (a system bar button, text measured under the floating tab bar, secondary text that nearly passed) are counted and named.
- Checks what the store will check. What's New, review notes, localized permission strings, required-reason APIs,
the age rating, entitlements and associated domains, before the upload (
release_checks.py). - Keeps one phone fair between agents. Several sessions share a USB iPhone in arrival order (
qakit-device lock). - Says what it did. The protocol has 180 checks with IDs, pass criteria and sources (docs/device-qa-protocol.md, 한국어); the verdict cites them.
The two layers behind it
| Layer | Question it answers | Tool | Use it on |
|---|---|---|---|
| Mutation testing | Would my tests notice if this line were wrong? | qakit-mutate (docs) |
Swift, Python, JavaScript, C-family; any repo with a test command |
| Prose QA | Does the memo, README or paper say what it claims? | qakit-prose (docs) |
Markdown and plain text, with a claims ledger |
Both are gates in forge, a multi-agent coding loop, on every task. The mutation layer was measured on humanize, tenacity and swift-argument-parser: of fifteen sampled survivors, seven were real test gaps (docs/case-studies.md).
Where it comes from
QAKit grew out of shipping App Store apps as a solo developer whose QA team is an agent. Every check was added after a
defect that green tests let through. A >= became > at a grading boundary and 13 mutants survived. A review note ran
over the 4,000-character limit. A caption failed contrast and nobody looked. A What's New still announced the first
release in version 1.1. A walk put the phone in the app switcher. Two apps and the example app have been through it on
a USB iPhone, and every gap they hit came back as a fix with a test and a tag (RELEASING.md).
Documentation
| Document | What it covers |
|---|---|
| docs/getting-started.md | Installing, linking the Swift package, the first walkthrough test, the first device run |
| docs/device-qa-protocol.md | The protocol: 24 areas, 180 checks with IDs, exit criteria, what only a human can do (한국어판) |
| docs/manifest.md | Every key of the device_qa.json manifest |
| docs/report.md | What a run leaves behind: summary.json, contact sheets, crash reports |
| examples/README.md | The Notes example app: build it, walk it, see the two planted defects reported |
| docs/mutation-testing.md | mutate.py operators, config, reports, how to read a score |
| docs/prose-qa.md | The prose gates and the claims ledger |
| docs/case-studies.md | Does the mutation layer find real gaps? Measured on three open-source projects |
| docs/agents.md | Attaching the kit to Claude Code (plugin), Codex, Cursor, Gemini CLI and any MCP client |
| mcp/README.md | The MCP server: nine tools, one stdio process, no dependencies |
| docs/pypi.md | The pip package: the five commands, where the skills land, the release procedure |
| skills/README.md | Installing the skills by hand |
| ROADMAP.md | What comes next and the loop that keeps the kit honest |
| RELEASING.md | How a change becomes a tagged release |
Requirements
iOS 17 or later for the accessibility audit, Xcode 15 or later to build the Swift package, Xcode 27 for the variants.
A USB-attached iPhone is the real thing; --simulator runs the same suites and variants (except VoiceOver) on an iOS
Simulator, so the first hour needs only Xcode. The Python tools need Python 3.10 or later and nothing else; the test
suite runs on Linux too.
Status
Private beta, 178 tests, in daily use on the author's apps. The Swift API and the manifest keys may still change between minor versions until 1.0 (CHANGELOG.md). MIT (LICENSE).
Metadata
Release files for qa-agent-kit 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| qa_agent_kit-0.7.0.tar.gz | 245.6 kB | Without provenance | Details for qa_agent_kit-0.7.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| qa_agent_kit-0.7.0-py3-none-any.whl | Python 3 | none | any | Details for qa_agent_kit-0.7.0-py3-none-any.whl |
Total release size: 431.3 kB
Release files / qa_agent_kit-0.7.0.tar.gz
| Download URL | qa_agent_kit-0.7.0.tar.gz |
|---|---|
| Size | 245.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2cfa6c3af704abd408479fae2a6654094c3c87af415d6e404dfeabad2b1f7f5d
|
|
BLAKE2b-256 checksum How to use checksums |
0d988032e7c2465d78c5a8e0dcfa288004cac3f49e28cdebc1a44d793603688b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.15
|
Release files / qa_agent_kit-0.7.0-py3-none-any.whl
| Download URL | qa_agent_kit-0.7.0-py3-none-any.whl |
|---|---|
| Size | 185.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
988e13a7035c182f237769b2ea1a28bfd2f21ca8ffa75b1f99688b35d611eb10
|
|
BLAKE2b-256 checksum How to use checksums |
83f84798845ae197c334d2868b278203466ebb18c2297dc7799f5a5d5b9096c2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.15
|
Security for qa-agent-kit 0.7.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.