Skip to content
Back to skills

Review Scheduler

DSecurity

(macOS only) Spaced repetition review scheduler for Obsidian. Based on the Ebbinghaus forgetting curve, auto-reminds you to review articles at optimal intervals via macOS launchd + screen unlock detection. Triggers: "/review-scheduler", "set up review reminders", "start review scheduler", "stop review scheduler"

  • 3 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 26, 2026
educationpythonswiftbash

Security analysis

D55/100
  • criticalModifies startup scripts or system services for persistence
  • criticalModifies startup scripts or system services for persistence
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 6 files and shows the line behind each finding

Scanned May 27, 2026

npx -y skills add Howie126313/obsidian-vault-kit --skill review-scheduler --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Review Scheduler?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Review Scheduler
[![Security: D — Skills Directory](https://www.skillsdirectory.com/api/skills/howie126313-review-scheduler/badge)](https://www.skillsdirectory.com/skills/howie126313-review-scheduler)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: review-scheduler
description: |
  (macOS only) Spaced repetition review scheduler for Obsidian. Based on the Ebbinghaus forgetting curve, auto-reminds you to review articles at optimal intervals via macOS launchd + screen unlock detection.
  Triggers: "/review-scheduler", "set up review reminders", "start review scheduler", "stop review scheduler"
allowed-tools:
  - Glob
  - Read
  - Write
  - AskUserQuestion
  - Bash(which *)
  - Bash(python3 *)
  - Bash(pip3 *)
  - Bash(swiftc *)
  - Bash(mkdir *)
  - Bash(launchctl *)
---

# Review Scheduler

Manage spaced repetition review reminders for the Obsidian vault.

## Argument Parsing

Parse user input arguments (args) to determine which subcommand to run:
- No args or `start` → execute **Start Flow**
- `stop` → execute **Stop Flow**
- `status` → execute **Status Check**

---

## Start Flow

### Step 0: Platform Check

This skill requires **macOS**. Check the platform first:

```bash
uname -s
```

If the output is not `Darwin`, inform the user that this skill is macOS-only (requires launchd, Swift compiler, and osascript) and stop.

### Step 0.5: Dependency Check

Before any action, run these checks:

```bash
which python3 && python3 --version
python3 -c "import yaml; print('PyYAML OK')"
which swiftc
```

If any dependency is missing, **stop immediately and report to user**:
- Python 3 missing: suggest `brew install python3`
- PyYAML missing: suggest `pip3 install pyyaml`
- swiftc missing: suggest `xcode-select --install`

Proceed only after all checks pass.

### Step 1: Ask User for Scheduled Time

Use AskUserQuestion to ask:
> "What time would you like to receive daily review reminders? (default 9:00, format: 08:30, 21:00)"

Parse user input into Hour and Minute. If user presses enter or says "default", use 9:00.

### Step 2: Check Existing Deployment

```bash
launchctl list 2>/dev/null | grep com.obsidian-vault-kit.review
```

- If already running → inform user "Review scheduler is already active", ask if they want to update the scheduled time
- If user doesn't want to update → end
- If user wants to update → run Stop Flow first, then continue with deployment

### Step 3: Deploy Files

1. **Detect vault path**: follow [../../_shared/common-steps.md](../../_shared/common-steps.md) "Vault Detection" section, store as `$VAULT_ROOT`
2. **Detect vault name**: take the directory name of `$VAULT_ROOT`
3. **Create `.review/` directory**: `mkdir -p $VAULT_ROOT/.review`
4. **Create `reviews/` directory**: `mkdir -p $VAULT_ROOT/reviews`

5. **Deploy review_reminder.py**:
   - Read [references/review_reminder.py](references/review_reminder.py)
   - Replace `{{VAULT_PATH}}` with the actual `$VAULT_ROOT` absolute path
   - Replace `{{VAULT_NAME}}` with the actual vault name
   - Write to `$VAULT_ROOT/.review/review_reminder.py`

6. **Deploy unlock_watcher.swift**:
   - Read [references/unlock_watcher.swift](references/unlock_watcher.swift)
   - Replace `{{PYTHON_PATH}}` with the result of `which python3`
   - Replace `{{SCRIPT_PATH}}` with `$VAULT_ROOT/.review/review_reminder.py`
   - Write to `$VAULT_ROOT/.review/unlock_watcher.swift`
   - Compile: `swiftc $VAULT_ROOT/.review/unlock_watcher.swift -o $VAULT_ROOT/.review/unlock_watcher -framework Cocoa`

7. **Deploy launchd plist (scheduled task)**:
   - Read [references/com.obsidian-vault-kit.review.plist](references/com.obsidian-vault-kit.review.plist)
   - Replace `{{PYTHON_PATH}}`, `{{SCRIPT_PATH}}`, `{{HOUR}}`, `{{MINUTE}}`
   - Write to `~/Library/LaunchAgents/com.obsidian-vault-kit.review.plist`

8. **Deploy launchd plist (unlock watcher)**:
   - Read [references/com.obsidian-vault-kit.review-watcher.plist](references/com.obsidian-vault-kit.review-watcher.plist)
   - Replace `{{WATCHER_PATH}}` with `$VAULT_ROOT/.review/unlock_watcher`
   - Write to `~/Library/LaunchAgents/com.obsidian-vault-kit.review-watcher.plist`

### Step 4: Start Scheduled Tasks

```bash
launchctl load ~/Library/LaunchAgents/com.obsidian-vault-kit.review.plist
launchctl load ~/Library/LaunchAgents/com.obsidian-vault-kit.review-watcher.plist
```

### Step 5: Run Once for Verification

```bash
python3 $VAULT_ROOT/.review/review_reminder.py
```

Check whether a review note was generated (if any articles are due for review today).

### Step 6: Report Results

Report to user:
- Scheduled task is active, daily reminder at HH:MM
- Screen unlock also triggers a check
- Review notes are saved in the `reviews/` directory
- To stop, run `/review-scheduler stop`

---

## Stop Flow

### Step 1: Check If Running

```bash
launchctl list 2>/dev/null | grep com.obsidian-vault-kit.review
```

If not running → inform user "Review scheduler is not active" → end

### Step 2: Unload Tasks

```bash
launchctl unload ~/Library/LaunchAgents/com.obsidian-vault-kit.review.plist 2>/dev/null
launchctl unload ~/Library/LaunchAgents/com.obsidian-vault-kit.review-watcher.plist 2>/dev/null
rm -f ~/Library/LaunchAgents/com.obsidian-vault-kit.review.plist
rm -f ~/Library/LaunchAgents/com.obsidian-vault-kit.review-watcher.plist
```

Note: keep `.review/` directory and existing review notes in `reviews/` — do not delete user data.

### Step 3: Report

Inform user that the scheduled tasks have been stopped. Existing review notes are preserved.

---

## Status Check

```bash
# Check scheduled tasks
launchctl list 2>/dev/null | grep com.obsidian-vault-kit.review
```

```
# Recent review notes (use native Glob, no Bash needed)
Glob("*.md", path="$VAULT_ROOT/reviews")
```

Report to user:
- Whether the scheduled tasks are running
- Most recent review note filenames
- Whether today's review note exists

Files in this skill

  • README.md3.6 KB
  • SKILL.md5.5 KB
  • references/com.obsidian-vault-kit.review-watcher.plist639 B
  • references/com.obsidian-vault-kit.review.plist765 B
  • references/review_reminder.py10.3 KB
  • references/unlock_watcher.swift519 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.