streak-tracker
Generates a streak tracking system with timezone-aware day boundaries, streak freeze protection, and streak-at-risk push notifications. Use when user wants daily/weekly engagement streaks, consecutive day tracking, or habit tracking.
What this skill does
# Streak Tracker Generator
Generate a production streak tracking system that records consecutive days of user activity, calculates current and longest streaks, handles timezone-aware day boundaries, supports streak freeze/protection passes, and schedules streak-at-risk local notifications.
## When This Skill Activates
Use this skill when the user:
- Asks to "add streaks" or "daily streak" tracking
- Wants "streak tracking" or "consecutive days" counting
- Mentions "engagement streaks" or "habit tracking"
- Asks about "streak freeze" or "streak protection"
- Wants "streak-at-risk" notifications or reminders
- Mentions "login streak" or "activity streak"
## Pre-Generation Checks
### 1. Project Context Detection
- [ ] Check Swift version (requires Swift 5.9+)
- [ ] Check deployment target (iOS 17+ / macOS 14+ for @Observable and SwiftData)
- [ ] Check for SwiftData availability and existing model container setup
- [ ] Identify source file locations
### 2. Conflict Detection
Search for existing streak or habit tracking:
```
Glob: **/*Streak*.swift, **/*Habit*.swift, **/*DailyTrack*.swift
Grep: "streak" or "consecutiveDays" or "habitTrack" or "dailyStreak"
```
If existing streak/habit system found:
- Ask if user wants to replace or extend it
- If extending, generate only the missing components
### 3. Platform Detection
Determine if generating for iOS (UNUserNotificationCenter) or macOS (UNUserNotificationCenter available on macOS 11+) or both.
## Configuration Questions
Ask user via AskUserQuestion:
1. **Streak type?**
- Daily (consecutive calendar days) -- recommended
- Weekly (at least one activity per calendar week)
- Custom interval (every N hours/days)
2. **Storage backend?**
- SwiftData (recommended for iOS 17+ / macOS 14+)
- UserDefaults (lightweight, no model container needed)
3. **Include streak freeze/protection?**
- Yes — users get limited freeze passes to preserve streaks on missed days
- No — strict consecutive tracking only
4. **Streak-at-risk notifications?**
- Yes — schedule a local notification (e.g., 8 PM) if no activity recorded today
- No — no notifications
5. **Additional features?** (multi-select)
- Calendar heat map view (visual grid of activity days)
- Streak badge view (compact count with animation)
- Milestone celebrations (7-day, 30-day, 100-day, etc.)
## Generation Process
### Step 1: Read Templates
Read `templates.md` for production Swift code.
### Step 2: Create Core Files
Generate these files:
1. `StreakRecord.swift` — SwiftData @Model for activity records
2. `StreakManager.swift` — @Observable class: record activity, calculate streaks, manage freezes
3. `StreakError.swift` — Error types for streak operations
### Step 3: Create UI Files
4. `StreakCalendarView.swift` — Grid showing days with/without activity
5. `StreakBadgeView.swift` — Compact badge with streak count and animation
### Step 4: Create Optional Files
Based on configuration:
- `StreakFreeze.swift` — If streak freeze selected
- `StreakNotificationScheduler.swift` — If notifications selected
### Step 5: Determine File Location
Check project structure:
- If `Sources/` exists -> `Sources/StreakTracking/`
- If `App/` exists -> `App/StreakTracking/`
- Otherwise -> `StreakTracking/`
## Output Format
After generation, provide:
### Files Created
```
StreakTracking/
├── StreakRecord.swift # SwiftData model for activity records
├── StreakManager.swift # Core streak calculation engine
├── StreakError.swift # Error types
├── StreakCalendarView.swift # Calendar heat map view
├── StreakBadgeView.swift # Compact animated badge
├── StreakFreeze.swift # Freeze/protection passes (optional)
└── StreakNotificationScheduler.swift # Streak-at-risk reminders (optional)
```
### Integration Steps
**Set up the model container (SwiftData):**
```swift
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(for: [StreakRecord.self, StreakFreeze.self])
}
}
```
**Record activity on user action:**
```swift
struct LessonCompleteView: View {
@Environment(\.modelContext) private var modelContext
@State private var streakManager: StreakManager?
var body: some View {
Button("Complete Lesson") {
Task {
try await streakManager?.recordActivity(type: "lesson")
}
}
.onAppear {
streakManager = StreakManager(modelContext: modelContext)
}
}
}
```
**Display the current streak:**
```swift
struct ProfileView: View {
@Environment(\.modelContext) private var modelContext
@State private var streakManager: StreakManager?
var body: some View {
VStack {
if let manager = streakManager {
StreakBadgeView(streak: manager.currentStreak)
Text("Longest: \(manager.longestStreak) days")
.foregroundStyle(.secondary)
}
}
.onAppear {
streakManager = StreakManager(modelContext: modelContext)
Task { await streakManager?.refresh() }
}
}
}
```
**Show the calendar heat map:**
```swift
struct StatsView: View {
@Environment(\.modelContext) private var modelContext
@State private var streakManager: StreakManager?
var body: some View {
if let manager = streakManager {
StreakCalendarView(manager: manager)
}
}
}
```
**Use a streak freeze:**
```swift
Button("Use Streak Freeze") {
if streakManager.useStreakFreeze() {
// Freeze applied — streak preserved
} else {
// No freezes available
}
}
```
### Testing
```swift
import Testing
import SwiftData
@Test
func recordingActivityIncrementsStreak() async throws {
let container = try ModelContainer(
for: StreakRecord.self, StreakFreeze.self,
configurations: ModelConfiguration(isStoredInMemoryOnly: true)
)
let context = ModelContext(container)
let manager = StreakManager(modelContext: context)
// Record activity for today
try await manager.recordActivity(type: "workout")
await manager.refresh()
#expect(manager.currentStreak == 1)
}
@Test
func consecutiveDaysBuildStreak() async throws {
let container = try ModelContainer(
for: StreakRecord.self, StreakFreeze.self,
configurations: ModelConfiguration(isStoredInMemoryOnly: true)
)
let context = ModelContext(container)
let manager = StreakManager(modelContext: context)
// Simulate 3 consecutive days
let calendar = Calendar.current
for daysAgo in (0...2).reversed() {
let date = calendar.date(byAdding: .day, value: -daysAgo, to: .now)!
try await manager.recordActivity(type: "workout", date: date)
}
await manager.refresh()
#expect(manager.currentStreak == 3)
#expect(manager.longestStreak == 3)
}
@Test
func missedDayBreaksStreak() async throws {
let container = try ModelContainer(
for: StreakRecord.self, StreakFreeze.self,
configurations: ModelConfiguration(isStoredInMemoryOnly: true)
)
let context = ModelContext(container)
let manager = StreakManager(modelContext: context)
let calendar = Calendar.current
// Day 3 ago and Day 2 ago (streak of 2), then skip Day 1, record today
let threeDaysAgo = calendar.date(byAdding: .day, value: -3, to: .now)!
let twoDaysAgo = calendar.date(byAdding: .day, value: -2, to: .now)!
try await manager.recordActivity(type: "workout", date: threeDaysAgo)
try await manager.recordActivity(type: "workout", date: twoDaysAgo)
try await manager.recordActivity(type: "workout", date: .now)
await manager.refresh()
#expect(manager.currentStreak == 1) // Gap broke the streak
#expect(manager.longestStreak == 2) // Previous streak preserved
}
@Test
func streakFreezePreservesStreak() async throws {
Related in Data & Analytics
clawarr-suite
IncludedComprehensive management for self-hosted media stacks (Sonarr, Radarr, Lidarr, Readarr, Prowlarr, Bazarr, Overseerr, Plex, Tautulli, SABnzbd, Recyclarr, Unpackerr, Notifiarr, Maintainerr, Kometa, FlareSolverr). Deep library exploration, analytics, dashboard generation, content management, request handling, subtitle management, indexer control, download monitoring, quality profile sync, library cleanup automation, notification routing, collection/overlay management, and media tracker integration (Trakt, Letterboxd, Simkl).
querying-soql
IncludedSOQL query generation, optimization, and analysis with 100-point scoring. Use this skill when the user needs SOQL/SOSL authoring or optimization: natural-language-to-query generation, relationship queries, aggregates, query-plan analysis, and performance or safety improvements for Salesforce queries. TRIGGER when: user writes, optimizes, or debugs SOQL/SOSL queries, touches .soql files, or asks about relationship queries, aggregates, or query performance. DO NOT TRIGGER when: bulk data operations (use handling-sf-data), Apex DML logic (use generating-apex), or report/dashboard queries.
app-store-optimization
IncludedApp Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklists, and tracking ranking changes.
habit-flow
IncludedAI-powered atomic habit tracker with natural language logging, streak tracking, smart reminders, and coaching. Use for creating habits, logging completions naturally ("I meditated today"), viewing progress, and getting personalized coaching.
app-store-optimization
IncludedApp Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklists, and tracking ranking changes.
visualizing-data
IncludedBuilds dashboards, reports, and data-driven interfaces requiring charts, graphs, or visual analytics. Provides systematic framework for selecting appropriate visualizations based on data characteristics and analytical purpose. Includes 24+ visualization types organized by purpose (trends, comparisons, distributions, relationships, flows, hierarchies, geospatial), accessibility patterns (WCAG 2.1 AA compliance), colorblind-safe palettes, and performance optimization strategies. Use when creating visualizations, choosing chart types, displaying data graphically, or designing data interfaces.