# Peekie
[](https://swiftpackageindex.com/dodobrands/Peekie)
[](https://swiftpackageindex.com/dodobrands/Peekie)
[](https://github.com/dodobrands/Peekie/actions/workflows/unittest.yml)
[](https://developer.apple.com/documentation/xctest)
[](https://developer.apple.com/xcode/swift-testing/)
**Peekie** is a CLI for Xcode `.xcresult` bundles. One subcommand per data type — `tests`, `warnings`, `errors`, `coverage` — each emitting machine-readable JSON (or a human-readable list, or SonarQube XML). Designed to be reached from CI scripts and **LLM coding agents** (Claude Code, Cursor) without re-explaining how `xcresulttool` works every time.
> Upgrading from 4.x? Read [**MIGRATION.md**](MIGRATION.md).
## Table of Contents
- [Install](#install)
- [CLI](#cli)
- [`peekie tests`](#peekie-tests)
- [`peekie warnings`](#peekie-warnings)
- [`peekie errors`](#peekie-errors)
- [`peekie coverage`](#peekie-coverage)
- [`peekie attachments`](#peekie-attachments)
- [Agent integration](#agent-integration)
- [Library (PeekieSDK)](#library-peekiesdk)
- [License](#license)
## Install
The fastest way to get the `peekie` binary on your `PATH` is via [mise](https://mise.jdx.dev/):
```bash
mise use github:dodobrands/peekie
```
Other options: [Homebrew tap](https://github.com/dodobrands/homebrew-tap) (coming soon), or download a pre-built binary from the [Releases page](https://github.com/dodobrands/Peekie/releases).
## CLI
Five data-axis subcommands. Each runs only the `xcrun` calls it needs.
```
peekie tests [--format json|list|sonar|allure] default: list
peekie warnings [--format json|list] default: json
peekie errors [--format json|list] default: json
peekie coverage [--format json|list] default: json
peekie attachments --output-dir [--format json|list] default: json
```
### `peekie tests`
Test results, with status filtering, SonarQube and Allure export.
```bash
# Human-readable, all statuses
peekie tests Tests.xcresult
# Only failures and flaky tests
peekie tests Tests.xcresult --include failure,mixed
# JSON for a dashboard
peekie tests Tests.xcresult --format json > tests.json
# SonarQube generic test execution XML
peekie tests Tests.xcresult --format sonar --tests-path Tests > sonar-tests.xml
# Allure 2 results directory, ready for `allurectl upload` / `allure generate`
peekie tests Tests.xcresult --format allure --output-dir allure-results
# Same, with XCTest activities mapped to Allure steps and metadata labels
# (allure.id / allure.label.* / allure.name / allure.description) — for UI tests
peekie tests UITests.xcresult --format allure --output-dir allure-results --steps
```
**Options:** `--include` (comma-separated statuses), `--include-device-details`, `--tests-path` (required with `--format sonar`), `--output-dir` (required with `--format allure`), `--steps` (with `--format allure`: activities → steps and labels; one extra `xcresulttool` call per test), `--attachments skip|export` + `--attachments-to ` (embeds attachment metadata into each test in the JSON output; required together when exporting).
### `peekie warnings`
Flat JSON array of build warnings. Pipe to `jq` for filtering.
```bash
peekie warnings Tests.xcresult
# [
# {"file":"Foo.swift","line":42,"column":8,"type":"DeprecatedDeclaration","message":"'oldFoo()' is deprecated: use bar"},
# ...
# ]
# Group by type
peekie warnings Tests.xcresult | jq 'group_by(.type) | map({type: .[0].type, count: length})'
# Human-readable
peekie warnings Tests.xcresult --format list
# Foo.swift:42:8 [DeprecatedDeclaration] 'oldFoo()' is deprecated
```
### `peekie errors`
Same shape as `warnings`, for the `errors[]` array. Use as a build-failed gate:
```bash
errors=$(peekie errors Tests.xcresult | jq 'length')
[ "$errors" -gt 0 ] && exit 1
```
### `peekie coverage`
```bash
# JSON for a dashboard
peekie coverage Tests.xcresult
# {"coverage": 0.6234, "modules": [{"name":"Calculator","coverage":0.71,"files":[…]}, …]}
# Total in one line
peekie coverage Tests.xcresult | jq '.coverage'
# 0.6234
# Padded table
peekie coverage Tests.xcresult --format list
# Calculator 71.6% (167/233)
# StringUtils 84.0% (42/50)
# total 62.3%
```
### `peekie attachments`
Exports `XCTAttachment` / Swift Testing `Attachment.record(...)` payloads to a directory and emits a flat JSON array describing each one (which test it came from, suggested filename, MIME type, whether it's tied to a failure).
```bash
# Export every attachment in the bundle
peekie attachments Tests.xcresult --output-dir ./attachments
# [
# {
# "qualifiedName": "ExamplesTests / ExampleSUITests / withAttachment()",
# "name": "Calculation Result_0_.txt",
# "exportedFileName": ".txt",
# "path": "./attachments/.txt",
# "contentType": "text/plain",
# "isAssociatedWithFailure": false,
# "repetitionNumber": 1
# },
# ...
# ]
# Only attachments from failing tests
peekie attachments Tests.xcresult --output-dir ./attachments --include failure
# A single test by identifier
peekie attachments Tests.xcresult --output-dir ./attachments --test-id "ExamplesTests/ExampleSUITests/withAttachment()"
# Human-readable
peekie attachments Tests.xcresult --output-dir ./attachments --format list
```
**Options:** `--output-dir` (required), `--test-id`, `--include` (comma-separated statuses), `--format json|list`.
Need the attachments embedded into each test (instead of a flat list)? Use `peekie tests --attachments export --attachments-to --format json` — each test gains an `attachments[]` array in its JSON node.
## Agent integration
Peekie is intentionally shaped to be reachable by LLM coding agents. The four data-axis subcommands plus `--format json` are orthogonal so an agent can compose calls without inventing arguments.
This repo also ships as a **plugin marketplace**, so you can install the skill in one command.
### Claude Code
```bash
/plugin marketplace add dodobrands/Peekie
/plugin install peekie
```
### Cursor
Teams / Enterprise: add as a team marketplace in settings.
Individual: clone and symlink the rule into your project:
```bash
git clone https://github.com/dodobrands/Peekie.git ~/.peekie-plugin
mkdir -p .cursor/rules
ln -s ~/.peekie-plugin/agent/rules/peekie.mdc .cursor/rules/peekie.mdc
```
The skill lives in [`agent/`](agent/); the marketplace catalog is at [`.claude-plugin/marketplace.json`](.claude-plugin/marketplace.json).
## Library (`PeekieSDK`)
If you need to embed parsing in your own Swift code (instead of shelling out to the CLI), depend on `PeekieSDK`:
```swift
.package(url: "https://github.com/dodobrands/Peekie.git", from: "5.0.0")
```
The model is **File-primary**: `Report.files` is the source of truth; `Report.modules` is a projection grouping files by target name.
```swift
import PeekieSDK
let report = try await Report(xcresultPath: URL(fileURLWithPath: "/path/to.xcresult"))
// All warnings, anywhere in the bundle
for issue in report.warnings {
print("\(issue.type.rawValue): \(issue.message)")
}
// Files in a specific target
let bonusesFiles = report.modules.first { $0.name == "Bonuses" }?.files ?? []
// Files without a known target (test-less targets, project-level issues)
let untargeted = report.files.filter { $0.module == nil }
```
`Report.init` accepts `includeCoverage`, `includeWarnings`, `includeTests` flags (all default `true`). Disable what you don't need to skip the corresponding `xcrun` calls.
For the full model — `File`, `Module`, `Suite`, `Issue.Location`, `IssueType` — see the source under [`Sources/PeekieSDK/Models/`](Sources/PeekieSDK/Models/) and the `tests` / `warnings` / `coverage` formatter implementations under [`Sources/PeekieSDK/Formatters/`](Sources/PeekieSDK/Formatters/).
### Test fixtures
`.xcresult` bundles under [`Tests/PeekieTests/Resources/`](Tests/PeekieTests/Resources/) are generated by the [swift-tests-example](https://github.com/dodobrands/swift-tests-example) repo. To regenerate after Xcode updates, follow that repo's instructions.
## License
This code is released under the Apache License. See [LICENSE](LICENSE) for more information.