RepoPilotOpen in app →

peripheryapp/periphery

A tool to identify unused code in Swift projects.

Healthy

Healthy across all four use cases

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 2w ago
  • 7 active contributors
  • MIT licensed
Show 3 more →
  • CI configured
  • Tests present
  • Single-maintainer risk — top contributor 92% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/peripheryapp/periphery)](https://repopilot.app/r/peripheryapp/periphery)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/peripheryapp/periphery on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: peripheryapp/periphery

Generated by RepoPilot · 2026-05-10 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/peripheryapp/periphery shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • Last commit 2w ago
  • 7 active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Single-maintainer risk — top contributor 92% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live peripheryapp/periphery repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/peripheryapp/periphery.

What it runs against: a local clone of peripheryapp/periphery — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in peripheryapp/periphery | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | Last commit ≤ 44 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>peripheryapp/periphery</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of peripheryapp/periphery. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/peripheryapp/periphery.git
#   cd periphery
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of peripheryapp/periphery and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "peripheryapp/periphery(\\.git)?\\b" \\
  && ok "origin remote is peripheryapp/periphery" \\
  || miss "origin remote is not peripheryapp/periphery (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 44 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~14d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/peripheryapp/periphery"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Periphery is a static analysis tool that identifies unused Swift code (functions, properties, parameters, imports, etc.) by analyzing the Xcode Index Store generated during project builds. It detects dead code across macOS and Linux projects, handling complex scenarios like protocol conformance, Codable synthesis, and Objective-C interop to reduce false positives. Single-package SPM project (Package.swift at root) with Bazel overlay support. Sources/ is organized into functional modules: Configuration/, Extensions/, and unnamed core logic. Build system dual-support via BUILD.bazel and Package.swift. Release infrastructure in .mise/tasks/ (Ruby + Shell scripting) and .github/workflows/ for automated publishing. Baseline scanning logic likely in main Sources/ directory (exact structure not shown but inferred from common Periphery architecture).

👥Who it's for

iOS/macOS developers and build engineers maintaining large Swift codebases who need to identify and remove technical debt; DevOps teams integrating code quality checks into CI/CD pipelines via GitHub Actions or Bazel.

🌱Maturity & risk

Production-ready with active development. The repo uses professional CI/CD (GitHub Actions in .github/workflows/), comprehensive build system support (Bazel, SPM), and distribution via Homebrew and Mint. The codebase is ~800KB of Swift with releases via Bazel Central Registry (BCR). Actively maintained based on recent .mise task infrastructure and bcr integration setup.

Low risk for core functionality but moderate risk for edge cases: static analysis tools are inherently hard to perfect and false positives/negatives vary by codebase pattern. Single maintainer risk indicated by FUNDING.yml. Breaking changes could occur when Index Store format changes with Xcode updates. Dependency on Xcode toolchain availability constrains Linux-only workflows.

Active areas of work

Active infrastructure modernization: .mise.toml task automation replacing raw scripts, Bazel Central Registry integration (MODULE.bazel.lock, .bcr/ with presubmit.yml), and container support (.dockerignore present). Recent work on baseline writing (.mise/tasks/write-baseline-*) and enhanced Linux/Bazel scan modes suggests expanding non-macOS support.

🚀Get running

git clone https://github.com/peripheryapp/periphery.git
cd periphery
sudo mise run build
# Or with SPM:
swift build -c release
# Or with Bazel:
bazel build //Sources:periphery

Daily commands:

# After build completes:
periphery scan --setup
# Or with full options:
periphery scan --project /path/to/project --format json
# CI/CD integration:
periphery scan --configuration baseline.json

🗺️Map of the codebase

  • Sources/Configuration/Configuration.swift: Central configuration object managing CLI arguments, project paths, and analysis options passed through the scan pipeline.
  • Package.swift: SPM manifest defining dependencies, build targets, and executable entrypoint—essential for understanding project structure and library versions.
  • BUILD.bazel: Bazel build configuration enabling reproducible builds and Bazel Central Registry distribution; critical for non-macOS deployments.
  • .github/workflows/test.yml: CI pipeline defining test matrix (macOS, Linux, Bazel variants) and release triggers—reveals how the project is validated before publishing.
  • Sources/Configuration/OutputFormat.swift: Defines output serialization formats (JSON, Xcode, etc.) that users consume; modifying this affects all downstream integrations.
  • .mise/tasks/release: Release orchestration script handling versioning, artifact generation, and publication to Homebrew and BCR.

🛠️How to make changes

Start in Sources/Configuration/ for CLI argument handling and output formatting. Core analysis logic likely in unnamed Sources/ subdirectories (infer from repo conventions: look for Sources/Analysis/, Sources/Graph/, Sources/Index/ or similar). Add new detection rules by extending the analysis phase. For build system support, modify package managers' integration in BUILD.bazel and Package.swift. Tests likely in Tests/ directory (not shown—check structure after cloning).

🪤Traps & gotchas

Xcode Index Store dependency: Periphery requires a built Index Store; raw Swift files won't analyze without a prior build—users must run xcodebuild or equivalent first. macOS vs. Linux divergence: Some features (Interface Builder, Xcode integration) are macOS-only; cross-platform testing required. Swift version sensitivity: Index Store format changes between Xcode versions—older/newer toolchains may produce incompatible indexes. Bazel + SPM parallel state: BUILD.bazel and Package.swift must stay synchronized; version bumps require updates in both (easy to miss). Configuration baseline files: Project-specific baseline.json files are build artifacts that can become stale; document migration path clearly.

💡Concepts to learn

  • Xcode Index Store — Periphery's entire analysis foundation—the Index Store is the compiled metadata (declarations, references, definitions) that Periphery traverses to build its dependency graph; understanding its structure is essential for debugging false positives.
  • Dependency Graph Analysis — Periphery models declarations and references as a directed graph, then performs reachability analysis from entry points (public APIs, mains, tests) to mark reachable vs. unreachable nodes; this algorithm is core to accuracy.
  • Static Analysis Dead Code Detection — The fundamental problem Periphery solves—identifying code unreachable from program entry points without executing the code; requires conservative assumptions (e.g., @objc is always reachable).
  • Protocol Conformance Resolution — Periphery must track implicit protocol method implementations and synthesized methods (e.g., Codable, Equatable); mishandling these causes false positives—a major source of tool unreliability.
  • Build System Abstraction — Periphery supports SPM, Bazel, and raw Xcode—abstracting Index Store generation across build systems requires handling toolchain differences; critical for tool adoption in diverse projects.
  • False Positive Mitigation (Exclusion Rules) — Swift's dynamic features (Objective-C interop, reflection, SPI) cause many apparent unused declarations to actually be live; Periphery uses exclusion heuristics (e.g., @objc, @IBAction) to reduce noise—understanding these rules prevents user frustration.
  • Bazel Central Registry (BCR) Distribution — Periphery publishes via BCR (MODULE.bazel integration); this is a modern supply chain pattern for Bazel-native dependencies and requires understanding Bazel versioning and hermetic builds.
  • apple/swift-syntax — Swift AST parsing library that Periphery may use or could extend for higher-fidelity syntax analysis beyond Index Store.
  • realm/SwiftLint — Complementary Swift linter also using static analysis; Periphery and SwiftLint often run together in CI for comprehensive code quality checks.
  • tuist/tuist — Xcode project management tool; Tuist-generated projects are a primary use case for Periphery to detect dead code in large scaled projects.
  • bazel-contrib/rules_swift — Official Bazel Swift rules that Periphery integrates with; essential for Bazel-based projects using Periphery in CI.
  • peripheryapp/periphery-action — GitHub Actions integration for Periphery (sibling repo); enables CI workflows that automatically scan and report unused code.

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive tests for FilePath+Glob.swift extension

The glob pattern matching functionality in Sources/Extensions/FilePath+Glob.swift is critical for file discovery and exclusion patterns, but there are no visible test files for this module. This is high-risk code that deserves dedicated unit tests covering edge cases like nested globs, exclusion patterns, and symlinks.

  • [ ] Create Tests/Extensions/FilePath+GlobTests.swift with test cases
  • [ ] Test glob patterns: .swift, **/.swift, Sources//Tests/
  • [ ] Test exclusion patterns and negation logic
  • [ ] Test edge cases: empty directories, symlinks, special characters in paths
  • [ ] Verify tests pass on both macOS and Linux (see .mise/tasks/scan-linux)

Add tests for Configuration parsing (Configuration.swift, OutputFormat.swift, ColorOption.swift)

The configuration system in Sources/Configuration/ handles user input parsing and output formatting options. Without visible tests, regressions in config loading could break the CLI experience. This is essential for validating command-line argument handling across different platforms.

  • [ ] Create Tests/Configuration/ConfigurationTests.swift
  • [ ] Test configuration file parsing from YAML/JSON
  • [ ] Test OutputFormat enum cases and serialization (JSON, CSV, Xcode, etc)
  • [ ] Test ColorOption parsing and environment variable overrides
  • [ ] Add tests for invalid configurations and error handling
  • [ ] Ensure tests pass in both test.yml and scan-linux CI workflows

Add integration tests for GuidedSetup.swift and project setup guides

Sources/Frontend/GuidedSetup.swift, BazelProjectSetupGuide.swift, and SPMProjectSetupGuide.swift contain interactive setup logic that's difficult to validate manually. These are user-facing components where bugs directly impact new users. Integration tests would catch regressions in setup workflows.

  • [ ] Create Tests/Frontend/GuidedSetupTests.swift with mock project structures
  • [ ] Test SPMProjectSetupGuide with sample Package.swift files
  • [ ] Test BazelProjectSetupGuide with sample MODULE.bazel and BUILD.bazel files
  • [ ] Test guided setup flows with different project configurations
  • [ ] Mock file system interactions to avoid side effects
  • [ ] Run tests in CI across macOS and Linux environments

🌿Good first issues

  • Add missing unit tests for Sources/Extensions/{Array,Collection}+Extension.swift—these utility modules lack test coverage and are good starter tests for understanding the codebase's extension patterns.
  • Document the Index Store schema and analysis graph algorithm in CONTRIBUTING.md or Architecture.md—new contributors struggle to understand how declarations are indexed and linked, blocking contributions to core analysis logic.
  • Implement JSON Schema validation in Sources/Configuration/Configuration.swift for baseline files—currently no validation of user-provided baseline.json structure, causing cryptic failures; add early-exit error messages.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 9cb8fb5 — Release 3.7.4 (ileitch)
  • 7d09ab3 — Update swift-index-store (#1117) (ileitch)
  • fde1592 — Release 3.7.3 (ileitch)
  • e99f954 — Restore Swift-only index store occurrence filtering. (#1107) (ileitch)
  • 1854716 — Add pro plan suggestion (#1115) (ileitch)
  • 199e224 — Swift 6.3 (#1098) (ileitch)
  • dcd5646 — Release 3.7.2 (ileitch)
  • 5a335c1 — Udate swift-index-store (#1106) (ileitch)
  • 262c509 — Release 3.7.1 (ileitch)
  • 6fd1fe6 — Update CHANGELOG (ileitch)

🔒Security observations

The Periphery codebase demonstrates generally good security posture for a Swift-based static analysis tool. No critical vulnerabilities were identified in the visible file structure. The primary concerns are operational in nature: (1) proper protection of build scripts, (2) control over version information disclosure, and (3) GitHub Actions workflow configuration hardening. The project uses modern build systems (Bazel) and proper dependency management via Package.swift and MODULE.bazel. Recommended actions focus on build-time security and CI/CD pipeline hardening rather than runtime issues.

  • Low · Potential Information Disclosure via Version File — Sources/Frontend/Version.swift, .mise/tasks/scripts/Version.swift.template. The codebase includes version template files (.mise/tasks/scripts/Version.swift.template) and version checking functionality (Sources/Frontend/Version.swift, Sources/Frontend/CheckUpdateCommand.swift). While not inherently vulnerable, ensure version information is not exposed unnecessarily in error messages or logging. Fix: Review version output in logs and error messages to ensure no sensitive build metadata is exposed. Implement proper version disclosure controls.
  • Low · External Script Execution in Build Tasks — .mise/tasks/scripts/helpers.sh, .mise/tasks/scripts/gen_bazel_rules.rb. The .mise/tasks directory contains multiple shell scripts (helpers.sh, gen_bazel_rules.rb) that are executed during build processes. If these scripts can be modified by untrusted actors, they could lead to arbitrary code execution. Fix: Ensure scripts in .mise/tasks are properly protected with appropriate file permissions (644 or more restrictive). Validate all script inputs and consider using cryptographic signatures for critical build scripts.
  • Low · GitHub Actions Workflow Security — .github/workflows/. GitHub Actions workflows are present (.github/workflows/publish.yaml, .github/workflows/test.yml). While the actual workflow files were not provided for review, common issues include: secrets in logs, insecure token permissions, and untrusted action versions. Fix: Review workflow files for: (1) Proper secret masking, (2) Minimal GITHUB_TOKEN permissions, (3) Pinned action versions with commit SHAs, (4) No secrets in environment variables that might be logged.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · peripheryapp/periphery — RepoPilot