RepoPilotOpen in app →

ephread/Instructions

Create walkthroughs and guided tours (coach marks) in a simple way, with Swift.

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.

  • 13 active contributors
  • MIT licensed
  • CI configured
Show 3 more →
  • Tests present
  • Stale — last commit 2y ago
  • Single-maintainer risk — top contributor 86% 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/ephread/instructions)](https://repopilot.app/r/ephread/instructions)

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/ephread/instructions on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: ephread/Instructions

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/ephread/Instructions 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

  • 13 active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Stale — last commit 2y ago
  • ⚠ Single-maintainer risk — top contributor 86% 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 ephread/Instructions repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/ephread/Instructions.

What it runs against: a local clone of ephread/Instructions — 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 ephread/Instructions | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 734 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>ephread/Instructions</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of ephread/Instructions. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/ephread/Instructions.git
#   cd Instructions
#
# 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 ephread/Instructions and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "ephread/Instructions(\\.git)?\\b" \\
  && ok "origin remote is ephread/Instructions" \\
  || miss "origin remote is not ephread/Instructions (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 main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "Sources/Instructions.swift" \\
  && ok "Sources/Instructions.swift" \\
  || miss "missing critical file: Sources/Instructions.swift"
test -f "Sources/Models/CoachMark.swift" \\
  && ok "Sources/Models/CoachMark.swift" \\
  || miss "missing critical file: Sources/Models/CoachMark.swift"
test -f "Sources/Views/CoachMarkView.swift" \\
  && ok "Sources/Views/CoachMarkView.swift" \\
  || miss "missing critical file: Sources/Views/CoachMarkView.swift"
test -f "Sources/Managers/FlowManager.swift" \\
  && ok "Sources/Managers/FlowManager.swift" \\
  || miss "missing critical file: Sources/Managers/FlowManager.swift"
test -f "Sources/Helpers/LayerRenderer.swift" \\
  && ok "Sources/Helpers/LayerRenderer.swift" \\
  || miss "missing critical file: Sources/Helpers/LayerRenderer.swift"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 734 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~704d)"
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/ephread/Instructions"
  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

Instructions is a Swift library that creates customizable coach marks and guided tours (walkthroughs) for iOS apps with simple, declarative syntax. It highlights specific UI elements sequentially and overlays instructional views to guide users through app features, supporting both iPhone and iPad with animation, positioning customization, and visual effects. Monorepo structure with core library code (not shown in top 60, but inferred from Examples), two distinct example apps (Examples/Example and Examples/App Extensions Example demonstrating coach marks in main app and keyboard extensions), supporting files for assets and storyboards, and CI via .github/workflows/continuous-integration.yml. Core library likely lives in Sources/ directory (not listed) with public CocoaPods/Carthage distribution.

👥Who it's for

iOS developers building apps with UIKit who need to onboard users with interactive guided tours without building coach mark infrastructure from scratch. Primarily used by teams shipping consumer or enterprise iOS apps that require feature discovery or user education flows.

🌱Maturity & risk

Production-ready but deprecated. The library has been maintained since the early SwiftUI era (Xcode 13+, iOS 14.0+) with proper CI/CD via GitHub Actions, code coverage tracking via Slather/CodeClimate, and SwiftLint enforcement. However, the maintainer explicitly deprecated it in favor of Apple's TipKit for SwiftUI projects, meaning no new features are planned—only bug fixes and compatibility updates.

Low technical risk for existing UIKit projects, but strategic risk: the maintainer has deprecated the library in favor of TipKit, signaling iOS ecosystem shift to SwiftUI. Dependency risk is minimal (Swift stdlib primary). Single maintainer (ephread) reduces long-term support certainty. Check CHANGELOG.md for iOS version compatibility before adoption on cutting-edge deployment targets.

Active areas of work

Library is in maintenance mode. No active feature development visible. Focus is on maintaining Swift/Xcode compatibility (currently targets Swift 5+, Xcode 13+) and accepting maintenance PRs. The CHANGELOG.md and migration guide (Documentation/migrating_to_2.0.0.md) suggest a v2.0.0 major release happened; current work is stabilization rather than innovation.

🚀Get running

Clone the repo: git clone https://github.com/ephread/Instructions.git && cd Instructions. Install dependencies via CocoaPods (Podfile present in examples): pod install. Open Instructions.xcworkspace (or example project workspace) in Xcode 13+. Build and run Example app to see coach marks in action. Requires iOS 14.0+ deployment target.

Daily commands: Open Examples/Example/Snapshot Tests or Examples/App Extensions Example in Xcode. Select Example app scheme, then Cmd+R to run simulator. Coach marks trigger on view controller load to demonstrate highlight, positioning, and animation features. CI runs via .github/workflows/continuous-integration.yml (check that file for exact test/lint/coverage commands).

🗺️Map of the codebase

  • Sources/Instructions.swift — Core library entry point and main CoachMarksController implementation—defines the public API and orchestrates the entire coach mark flow.
  • Sources/Models/CoachMark.swift — Data model for individual coach marks—essential for understanding how walkthroughs are defined and stored.
  • Sources/Views/CoachMarkView.swift — Main UI component rendering coach marks on screen—critical for visual presentation and user interaction handling.
  • Sources/Managers/FlowManager.swift — Orchestrates navigation between sequential coach marks—manages state transitions and lifecycle during walkthroughs.
  • Sources/Helpers/LayerRenderer.swift — Handles overlay rendering and spotlight cutout logic—core visual mechanics of the coach mark highlighting system.
  • Examples/Example/Sources/ViewController.swift — Primary example implementation showing typical integration patterns and configuration best practices.
  • CHANGELOG.md — Tracks API changes and deprecations—required reading for understanding version migration and breaking changes.

🧩Components & responsibilities

  • CoachMarksController (UIViewController, delegates, UIView hierarchy) — Central coordinator managing coach mark lifecycle, state, and delegation. Entry point for public API.
    • Failure mode: If lifecycle callbacks are not fired, walkthrough appears broken; if overlay is not attached, highlights are invisible
  • FlowManager (Array indexing, state machine (implicit via index)) — Tracks current step index and orchestrates transitions between sequential coach marks.
    • Failure mode: If step sequencing fails, walkthrough may skip marks or loop infinitely
  • LayerRenderer (CAShapeLayer, UIBezierPath, CGGeometry) — Generates CALayer mask for spotlight effect and calculates overlay geometry.
    • Failure mode: If mask path is incorrect, spotlight may not align with target view or may disappear during rotation
  • CoachMarkView — Composite UIView aggregating arrow, body text,

🛠️How to make changes

Add a new coach mark to a walkthrough

  1. Create a CoachMark instance defining which view to highlight, position, and body text (Sources/Models/CoachMark.swift)
  2. Append the coach mark to your flow array (typically in ViewController setup) (Examples/Example/Sources/ViewController.swift)
  3. Configure appearance via CoachMarkAppearance if custom styling is needed (Sources/Models/CoachMarkAppearance.swift)
  4. Pass the array to CoachMarksController.start(on:coachMarks:) to begin the walkthrough (Sources/Instructions.swift)

Customize the appearance of coach marks

  1. Create or modify a CoachMarkAppearance instance with custom colors, fonts, and sizes (Sources/Models/CoachMarkAppearance.swift)
  2. Set animationOptions to control movement and fade timing (Sources/Models/AnimationOptions.swift)
  3. Assign the appearance instance to CoachMarksController before calling start() (Sources/Instructions.swift)

Create a custom coach mark body view

  1. Create a UIView subclass that conforms to CoachMarkBodyView protocol (Sources/Models/CoachMarkBodyView.swift)
  2. Implement the required properties and methods (body text, dismiss button configuration) (Sources/Views/CoachMarkView.swift)
  3. Set the bodyViewType property on your CoachMark or pass a factory closure (Sources/Models/CoachMark.swift)

Handle coach mark events and callbacks

  1. Implement CoachMarksControllerDelegate in your view controller to receive lifecycle callbacks (Sources/Instructions.swift)
  2. Override methods like didShow(), didSkip(), didFinish() to respond to user interactions (Sources/Managers/FlowManager.swift)
  3. Use the delegate pattern to trigger additional UI updates or analytics tracking (Examples/Example/Sources/ViewController.swift)

🔧Why these technologies

  • UIView overlays with CALayer masks — Enables pixel-perfect spotlight cutouts and smooth animations without heavy WebGL or Metal rendering; sufficient for 2D coach mark visualization
  • Delegate pattern (CoachMarksControllerDelegate) — Provides loose coupling between library and client code; allows flexible event handling without global state
  • Protocol-based view composition (CoachMarkBodyView) — Enables deep customization of coach mark body content while maintaining type safety and testability
  • UIViewController extensions for lifecycle hooks — Seamlessly integrates with view controller rotation and lifecycle events without requiring subclassing

⚖️Trade-offs already made

  • Uses UIKit exclusively (no SwiftUI support in main library)

    • Why: Repo predates modern SwiftUI adoption; existing stable UIKit codebase with broad compatibility
    • Consequence: Not suitable for SwiftUI-only apps; maintainer notes deprecation in favor of TipKit for new projects
  • Spotlight mask calculated in real-time as views move

    • Why: Provides responsive highlight tracking during scroll or layout changes
    • Consequence: May incur layout recalculation overhead on complex UIs; not pre-baked into static images
  • Flow is linear and sequential (no branching or conditional paths)

    • Why: Simpler mental model and API; covers 95% of walkthrough use cases
    • Consequence: Cannot dynamically skip or reorder coach marks mid-flow based on runtime conditions
  • Single-window architecture (coach marks overlay current window)

    • Why: Matches typical app structure; reduces complexity of cross-window state management
    • Consequence: Not suitable for multi-window iPadOS apps where coach marks span windows

🚫Non-goals (don't propose these)

  • Does not support SwiftUI; deprecated in favor of TipKit for new projects
  • Does not provide backend analytics or telemetry—purely client-side presentation layer
  • Does not handle app-wide or persistent walkthrough state—caller responsible for tracking completion
  • Does not support conditional branching or dynamic flow modification during playback
  • Does not provide accessibility (VoiceOver) enhancements beyond default UIKit behavior

🪤Traps & gotchas

No CocoaPods or Carthage manifests shown in top 60 files, so dependency management details hidden—check podspec and Cartfile in repo root. iOS 14.0+ minimum deployment target is strict; cannot backport to iOS 13. App Extension example suggests coach marks need special handling outside main app bundle (UIVisualEffectView may not work in extensions—see partial support note in README). Deprecated status means iOS 18+ compatibility may lag if Apple breaks UIKit APIs. Build requires Ruby version specified in .ruby-version (check that file for exact version).

🏗️Architecture

💡Concepts to learn

  • Coach Marks / Highlights — Core concept of this library—visual highlights that guide users to specific UI elements sequentially; requires understanding frame calculations, hit detection, and animation orchestration
  • Custom Delegate Pattern — Instructions uses delegate callbacks (likely CoachMarkControllerDelegate or similar) to let clients customize positioning, styling, and behavior per coach mark without subclassing
  • UIVisualEffectView / Blur Effects — README notes 'partial UIVisualEffectView support'—the library uses visual effects for dimming/blur overlays behind coach marks, but compatibility is limited in app extensions; critical for visual design decisions
  • Right-to-Left (RTL) Layout — Library explicitly supports RTL languages; requires understanding UIView's layoutDirection property and frame mirroring to position coach marks correctly in Arabic/Hebrew apps
  • App Extensions Sandbox Isolation — Examples include KeyboardViewController demonstrating coach marks in extensions; requires understanding bundle limitations, shared container access, and why UIVisualEffectView fails in some extension contexts
  • Size Transition Handling — Library supports orientation changes and multi-tasking (iPad split screen); requires recalculating highlight frames and reanimating coach marks on viewWillTransition callbacks
  • Core Animation & CABasicAnimation — README lists animatable coach marks as a feature; likely uses CABasicAnimation or UIView.animate for smooth position/opacity transitions during tour progression
  • prine/SwiftUIKit — Alternative SwiftUI-native coach mark library offering similar guided tour functionality for modern iOS projects
  • ABCJournal/Onboarding — UIKit-based onboarding library with coach mark support, represents similar legacy approach pre-TipKit era
  • apple/tipkit — Apple's official TipKit framework (iOS 17+) replacing Instructions—the maintainer's recommended migration path for new projects
  • Carthage/Carthage — Dependency manager supported by Instructions; used to install library alongside CocoaPods as alternative distribution method
  • realm/SwiftLint — Linting tool configured in .swiftlint.yml; enforces code style and quality standards in this codebase

🪄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 snapshot tests for App Extensions Example keyboard extension

The snapshot test suite exists for the main Example app (Examples/Example/Snapshot Tests) with multiple device configurations, but the App Extensions Example lacks any snapshot tests. The KeyboardViewController.swift in the keyboard extension should have visual regression tests to ensure the coach marks render correctly in the constrained environment of a keyboard extension, which has unique layout constraints.

  • [ ] Create Examples/App Extensions Example/Snapshot Tests directory structure mirroring Examples/Example/Snapshot Tests
  • [ ] Add snapshot test file for KeyboardViewController similar to DefaultExampleSnapshotTests.swift
  • [ ] Configure snapshot tests for keyboard extension app extension target in the project
  • [ ] Generate baseline snapshots for keyboard extension on multiple devices (at least iPhone and iPad)
  • [ ] Add supporting test files (Info.plist, extensions for DeviceKit and UIImage helpers)

Add UI tests for CocoaPods and Carthage integration examples

While the CI workflow (continuous-integration.yml) exists, there are no specific integration tests verifying that Instructions works correctly when installed via CocoaPods or Carthage. Given that the README prominently advertises both package managers, adding example projects and CI steps to test these integrations would catch regressions early.

  • [ ] Create Examples/CocoaPods Example directory with a minimal test app using Instructions via Podfile
  • [ ] Create Examples/Carthage Example directory with a minimal test app using Instructions via Cartfile
  • [ ] Add GitHub Actions workflow steps to .github/workflows/continuous-integration.yml to build both example projects
  • [ ] Verify that pod install and carthage update succeed and that the apps build without errors
  • [ ] Document the example projects in CONTRIBUTING.md for maintainers

Add unit tests for coach mark animation and timing edge cases

The snapshot tests cover visual output, but there's no explicit test coverage for animation timing, state transitions, and edge cases (e.g., rapid show/hide calls, orientation changes during animation). Given that Instructions is a UI coach marking library, comprehensive unit tests for animation behavior would improve reliability.

  • [ ] Analyze the core Instructions framework source files to identify animation/timing logic (likely in controller classes)
  • [ ] Create Tests/AnimationTests.swift or similar to test animation state machines
  • [ ] Add tests for edge cases: rapid consecutive show/hide calls, animation cancellation, orientation changes mid-animation
  • [ ] Add tests for timing constraints and completion handler behavior
  • [ ] Update test coverage in .slather.yml configuration if needed to ensure new tests are tracked

🌿Good first issues

  • Add SwiftUI wrapper example: create Examples/Example-SwiftUI demonstrating coach mark integration in a SwiftUI view hierarchy, helping users understand how to bridge UIKit library into SwiftUI-first codebases before migrating to TipKit.
  • Expand app extension documentation: enhance Examples/App Extensions Example README and in-code comments explaining UIVisualEffectView limitations and workarounds for keyboard/share extensions, since the 'partial support' note in README is vague.
  • Add snapshot tests for custom view positioning: create visual regression tests in Examples/Example/Snapshot Tests for edge cases like RTL layout, multi-tasking, and landscape orientation to prevent regressions in size transition support.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 0f3efa7 — Update README.md (ephread)
  • 256f036 — Update README.md (ephread)
  • 5d3f8b3 — fix warning: 'contentEdgeInsets' was deprecated in iOS 15.0 (#308) (tony-yun)
  • 0964edf — Update Ruby dependencies (ephread)
  • 54f50ec — Bump to 2.3.0 and update tests (ephread)
  • 66323ba — Changed FlowManager.currentIndex to be public get, private set (#298) (twomedia)
  • 2a93135 — Convert stored properties into computed properties (#295) (galijot)
  • 682e0c7 — Merge branch 'github-actions' (ephread)
  • dc89678 — Remove Gitter (ephread)
  • c77c163 — Update Gemfile.lock (ephread)

🔒Security observations

The Instructions iOS project demonstrates generally good security posture with no critical vulnerabilities identified in the available file structure. The codebase shows evidence of CI/CD automation and code quality practices (CodeClimate integration, SwiftLint). However, the project is marked as deprecated by its maintainer, which is the primary security concern. No hardcoded secrets, injection vulnerabilities, or obvious misconfigurations are apparent from the provided file listing. The main recommendations are: (1) establish a clear security maintenance plan given the deprecated status, (2) provide and analyze dependency files for known vulnerabilities, and (3) enhance automated security scanning in the CI/CD pipeline. The Swift/iOS nature of the project inherently provides some protection against web-based attack vectors like SQLi and XSS.

  • Low · Deprecated Project Status — README.md. The README indicates that Instructions is now considered deprecated, with the maintainer stating they will 'still fix issues, maintain compatibility with newer versions of' (text appears truncated). Deprecated projects may not receive timely security updates and patches. Fix: Consider migrating to actively maintained alternatives for coach mark/guided tour functionality, or establish a clear security maintenance plan if continuing to use this library.
  • Low · Missing Dependency File Details — Package.swift or Podfile or Package.resolved. The Package.swift or Podfile content was not provided for analysis. Dependency vulnerabilities cannot be assessed without visibility into project dependencies. Fix: Provide dependency files for security scanning. Implement automated dependency vulnerability scanning in CI/CD pipeline using tools like OWASP Dependency-Check or Swift Package Manager vulnerability scanning.
  • Low · Incomplete Security Configuration Review — .swiftlint.yml, .github/workflows/continuous-integration.yml. While .swiftlint.yml and continuous integration workflows are present, specific security-focused linting rules and static analysis configurations are not visible in the file structure. Fix: Enhance SwiftLint configuration with security-focused rules. Integrate static analysis tools like SonarQube, Semgrep, or commercial Swift security scanners into CI/CD pipeline.

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 · ephread/Instructions — RepoPilot