Metadata-Version: 2.5
Name: qa-agent-kit
Version: 0.7.0
Summary: The QA agent kit: mutation testing for any repo, prose gates with a claims ledger, and real-device QA for Apple apps, with the procedures an AI coding agent follows.
Project-URL: Homepage, https://github.com/younatics/QAKit
Project-URL: Changelog, https://github.com/younatics/QAKit/blob/main/CHANGELOG.md
Project-URL: Documentation, https://github.com/younatics/QAKit/blob/main/docs/getting-started.md
Author: younatics
License-Expression: MIT
License-File: LICENSE
Keywords: agents,claude-code,codex,ios,mutation-testing,prose,qa,xcuitest
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.10
Provides-Extra: test
Requires-Dist: pyflakes; extra == 'test'
Requires-Dist: pytest; extra == 'test'
Description-Content-Type: text/markdown

<p align="center">
  <img src="assets/banner.svg" alt="QAKit: the QA agent kit" width="100%">
</p>

<h1 align="center">QAKit</h1>

<p align="center"><b>An AI agent that QA-tests your iOS app on a real iPhone.</b><br>
Every screen, every button, dark mode, large text, VoiceOver, a crash watch, Apple's accessibility audit, and a release verdict with evidence.<br>
Plus the two checks a release needs behind it: would your tests notice a bug, and does your copy say what it claims.</p>

<p align="center">
  <a href="https://github.com/younatics/QAKit/actions/workflows/ci.yml"><img src="https://github.com/younatics/QAKit/actions/workflows/ci.yml/badge.svg" alt="ci"></a>
  <a href="https://pypi.org/project/qa-agent-kit/"><img src="https://img.shields.io/pypi/v/qa-agent-kit?label=pypi&color=22d3ee" alt="PyPI"></a>
  <img src="https://img.shields.io/badge/iOS-17%2B-34d399" alt="iOS 17+">
  <img src="https://img.shields.io/badge/Xcode-27-34d399" alt="Xcode 27">
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-lightgrey" alt="MIT"></a>
</p>

<table align="center"><tr>
<td align="center"><img src="assets/demo-walk.gif" width="260" alt="An agent walking an app on a real iPhone: onboarding, the home screen at every scroll position, each button tapped once"><br><sub><b>One walk, one phone.</b> Onboarding, every scroll position, every button tapped once, the audit on each screen. 29 frames from one test's attachments.</sub></td>
<td align="center"><img src="assets/demo-variants.gif" width="260" alt="The Notes example app's screens in the default, dark and large-text variants"><br><sub><b>Same walk, three variants.</b> <code>--variant default --variant dark --variant large-text</code> switches the phone, not the app. The <code>examples/Notes</code> app.</sub></td>
</tr></table>

## Sixty seconds

```bash
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](docs/report.md)). Your walkthrough test is a few lines on top of the Swift package:

```swift
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:

```bash
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.walk` screenshots 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`](tools/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](docs/device-qa-protocol.md), [한국어](docs/ko/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](docs/mutation-testing.md)) | 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](docs/prose-qa.md)) | Markdown and plain text, with a claims ledger |

Both are gates in [forge](https://github.com/younatics/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](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](RELEASING.md)).

## Documentation

| Document | What it covers |
|---|---|
| [docs/getting-started.md](docs/getting-started.md) | Installing, linking the Swift package, the first walkthrough test, the first device run |
| [docs/device-qa-protocol.md](docs/device-qa-protocol.md) | The protocol: 24 areas, 180 checks with IDs, exit criteria, what only a human can do ([한국어판](docs/ko/device-qa-protocol.md)) |
| [docs/manifest.md](docs/manifest.md) | Every key of the `device_qa.json` manifest |
| [docs/report.md](docs/report.md) | What a run leaves behind: `summary.json`, contact sheets, crash reports |
| [examples/README.md](examples/README.md) | The Notes example app: build it, walk it, see the two planted defects reported |
| [docs/mutation-testing.md](docs/mutation-testing.md) | `mutate.py` operators, config, reports, how to read a score |
| [docs/prose-qa.md](docs/prose-qa.md) | The prose gates and the claims ledger |
| [docs/case-studies.md](docs/case-studies.md) | Does the mutation layer find real gaps? Measured on three open-source projects |
| [docs/agents.md](docs/agents.md) | Attaching the kit to Claude Code (plugin), Codex, Cursor, Gemini CLI and any MCP client |
| [mcp/README.md](mcp/README.md) | The MCP server: nine tools, one stdio process, no dependencies |
| [docs/pypi.md](docs/pypi.md) | The pip package: the five commands, where the skills land, the release procedure |
| [skills/README.md](skills/README.md) | Installing the skills by hand |
| [ROADMAP.md](ROADMAP.md) | What comes next and the loop that keeps the kit honest |
| [RELEASING.md](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](CHANGELOG.md)). MIT ([LICENSE](LICENSE)).
