Home
Softono

Peekie

Open source Apache-2.0 Swift
25
Stars
4
Forks
0
Issues
5
Watchers
3 months
Last Commit

 About Peekie

Swift package for parsing Xcode .xcresult files with support for XCTest and Swift Testing frameworks

Platforms

Web Self-hosted macOS iOS

Languages

Swift

Need Help Installing Peekie?

We provide expert installation service for this software. Our team will install, configure, and secure Peekie on your server. plans start at just $30.

Peekie

Peekie Logo

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.

Table of Contents

Install

The fastest way to get the peekie binary on your PATH is via mise:

mise use github:dodobrands/peekie

Other options: Homebrew tap (coming soon), or download a pre-built binary from the Releases page.

CLI

Five data-axis subcommands. Each runs only the xcrun calls it needs.

peekie tests        <xcresult>  [--format json|list|sonar]  default: list
peekie warnings     <xcresult>  [--format json|list]        default: json
peekie errors       <xcresult>  [--format json|list]        default: json
peekie coverage     <xcresult>  [--format json|list]        default: json
peekie attachments  <xcresult>  --output-dir <dir> [--format json|list]  default: json

peekie tests

Test results, with status filtering and SonarQube export.

# 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

Options: --include (comma-separated statuses), --include-device-details, --tests-path (required with --format sonar), --attachments skip|export + --attachments-to <dir> (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.

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:

errors=$(peekie errors Tests.xcresult | jq 'length')
[ "$errors" -gt 0 ] && exit 1

peekie coverage

# 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).

# Export every attachment in the bundle
peekie attachments Tests.xcresult --output-dir ./attachments
# [
#   {
#     "qualifiedName": "ExamplesTests / ExampleSUITests / withAttachment()",
#     "name": "Calculation Result_0_<uuid>.txt",
#     "exportedFileName": "<uuid>.txt",
#     "path": "./attachments/<uuid>.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 <dir> --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

/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:

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/; the marketplace catalog is at .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:

.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.

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/ and the tests / warnings / coverage formatter implementations under Sources/PeekieSDK/Formatters/.

Test fixtures

.xcresult bundles under Tests/PeekieTests/Resources/ are generated by the 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 for more information.