@wonsukchoi/crondex 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/catalog.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "generated_by": "scripts/build-catalog.js",
3
3
  "schema": "schema/job.schema.json",
4
- "count": 56,
4
+ "count": 79,
5
5
  "jobs": [
6
6
  {
7
7
  "id": "1on1-prep-reminder",
@@ -123,6 +123,104 @@
123
123
  ],
124
124
  "path": "jobs/content/broken-link-check.yaml"
125
125
  },
126
+ {
127
+ "id": "budget-overspend-check",
128
+ "version": 1,
129
+ "name": "Budget Overspend Check",
130
+ "description": "Compares this month's spend in a budget category against your limit and warns if you're over. Use this if you set budgets once and then never actually check them until the month's already blown.",
131
+ "category": "finance",
132
+ "tags": [
133
+ "budget",
134
+ "spending",
135
+ "finance"
136
+ ],
137
+ "schedule": "0 9 * * *",
138
+ "timezone": "UTC",
139
+ "runner": "shell",
140
+ "modes": [
141
+ "script"
142
+ ],
143
+ "compatible_agents": [
144
+ "generic",
145
+ "claude",
146
+ "codex"
147
+ ],
148
+ "path": "jobs/finance/budget-overspend-check.yaml"
149
+ },
150
+ {
151
+ "id": "calendar-double-booking-check",
152
+ "version": 1,
153
+ "name": "Calendar Double-Booking Check",
154
+ "description": "Checks today's calendar for overlapping meetings and flags them. Use this if you've ever accepted two invites for the same slot and only noticed when both started ringing.",
155
+ "category": "productivity",
156
+ "tags": [
157
+ "calendar",
158
+ "meetings",
159
+ "productivity"
160
+ ],
161
+ "schedule": "0 7 * * 1-5",
162
+ "timezone": "America/Los_Angeles",
163
+ "runner": "agent-prompt",
164
+ "modes": [
165
+ "agent-prompt"
166
+ ],
167
+ "compatible_agents": [
168
+ "claude",
169
+ "codex",
170
+ "hermes",
171
+ "openclaw",
172
+ "generic"
173
+ ],
174
+ "path": "jobs/productivity/calendar-double-booking-check.yaml"
175
+ },
176
+ {
177
+ "id": "canonical-tag-check",
178
+ "version": 1,
179
+ "name": "Canonical Tag Check",
180
+ "description": "Checks a list of pages for missing or self-conflicting canonical tags. Use this if a templating bug has ever pointed every page's canonical at the homepage (or nowhere at all) without anyone noticing.",
181
+ "category": "content",
182
+ "tags": [
183
+ "seo",
184
+ "canonical",
185
+ "content"
186
+ ],
187
+ "schedule": "0 7 * * 1",
188
+ "timezone": "UTC",
189
+ "runner": "shell",
190
+ "modes": [
191
+ "script"
192
+ ],
193
+ "compatible_agents": [
194
+ "generic",
195
+ "claude",
196
+ "codex"
197
+ ],
198
+ "path": "jobs/content/canonical-tag-check.yaml"
199
+ },
200
+ {
201
+ "id": "car-maintenance-due-reminder",
202
+ "version": 1,
203
+ "name": "Car Maintenance Due Reminder",
204
+ "description": "Warns you when a car maintenance task (oil change, registration, etc.) is coming due by date. Use this if you've ever found out your registration expired because a sticker in the mail got ignored.",
205
+ "category": "home",
206
+ "tags": [
207
+ "home",
208
+ "car",
209
+ "maintenance"
210
+ ],
211
+ "schedule": "0 9 * * 1",
212
+ "timezone": "America/Los_Angeles",
213
+ "runner": "shell",
214
+ "modes": [
215
+ "script"
216
+ ],
217
+ "compatible_agents": [
218
+ "generic",
219
+ "claude",
220
+ "codex"
221
+ ],
222
+ "path": "jobs/home/car-maintenance-due-reminder.yaml"
223
+ },
126
224
  {
127
225
  "id": "cart-abandonment-followup",
128
226
  "version": 1,
@@ -150,6 +248,30 @@
150
248
  ],
151
249
  "path": "jobs/growth/cart-abandonment-followup.yaml"
152
250
  },
251
+ {
252
+ "id": "cert-renewal-reminder",
253
+ "version": 1,
254
+ "name": "Professional Certification Renewal Reminder",
255
+ "description": "Warns you before a professional certification expires or its renewal window opens. Use this if you've ever let a cert lapse and had to retake an exam that a renewal course would've avoided.",
256
+ "category": "learning",
257
+ "tags": [
258
+ "learning",
259
+ "certification",
260
+ "renewal"
261
+ ],
262
+ "schedule": "0 9 1 * *",
263
+ "timezone": "America/Los_Angeles",
264
+ "runner": "shell",
265
+ "modes": [
266
+ "script"
267
+ ],
268
+ "compatible_agents": [
269
+ "generic",
270
+ "claude",
271
+ "codex"
272
+ ],
273
+ "path": "jobs/learning/cert-renewal-reminder.yaml"
274
+ },
153
275
  {
154
276
  "id": "certificate-transparency-watch",
155
277
  "version": 1,
@@ -201,6 +323,60 @@
201
323
  ],
202
324
  "path": "jobs/content/changelog-digest.yaml"
203
325
  },
326
+ {
327
+ "id": "churn-risk-watch",
328
+ "version": 1,
329
+ "name": "Churn Risk Watch",
330
+ "description": "Flags accounts whose usage has dropped off sharply, before they actually cancel. Use this if you only ever find out someone churned after the cancellation email arrives.",
331
+ "category": "growth",
332
+ "tags": [
333
+ "growth",
334
+ "churn",
335
+ "retention"
336
+ ],
337
+ "schedule": "0 9 * * 1",
338
+ "timezone": "UTC",
339
+ "runner": "agent-prompt",
340
+ "modes": [
341
+ "agent-prompt"
342
+ ],
343
+ "compatible_agents": [
344
+ "claude",
345
+ "codex",
346
+ "hermes",
347
+ "openclaw",
348
+ "generic"
349
+ ],
350
+ "path": "jobs/growth/churn-risk-watch.yaml"
351
+ },
352
+ {
353
+ "id": "conference-cfp-deadline-reminder",
354
+ "version": 1,
355
+ "name": "Conference CFP Deadline Reminder",
356
+ "description": "Warns you before a conference's call-for-papers deadline, and can help draft your talk proposal. Use this if you've ever meant to submit a talk and missed the CFP because you found out a week too late.",
357
+ "category": "learning",
358
+ "tags": [
359
+ "learning",
360
+ "conference",
361
+ "cfp",
362
+ "career"
363
+ ],
364
+ "schedule": "0 9 * * 1",
365
+ "timezone": "UTC",
366
+ "runner": "hybrid",
367
+ "modes": [
368
+ "script",
369
+ "agent-prompt"
370
+ ],
371
+ "compatible_agents": [
372
+ "claude",
373
+ "codex",
374
+ "hermes",
375
+ "openclaw",
376
+ "generic"
377
+ ],
378
+ "path": "jobs/learning/conference-cfp-deadline-reminder.yaml"
379
+ },
204
380
  {
205
381
  "id": "cost-alert",
206
382
  "version": 1,
@@ -252,6 +428,32 @@
252
428
  ],
253
429
  "path": "jobs/learning/course-progress-checkin.yaml"
254
430
  },
431
+ {
432
+ "id": "cve-watch",
433
+ "version": 1,
434
+ "name": "CVE Watch",
435
+ "description": "Checks for newly published CVEs affecting packages in your stack. Use this if you want a heads-up on a critical vulnerability before it shows up in a routine dependency audit days later.",
436
+ "category": "security",
437
+ "tags": [
438
+ "security",
439
+ "cve",
440
+ "vulnerabilities"
441
+ ],
442
+ "schedule": "0 8 * * *",
443
+ "timezone": "UTC",
444
+ "runner": "agent-prompt",
445
+ "modes": [
446
+ "agent-prompt"
447
+ ],
448
+ "compatible_agents": [
449
+ "claude",
450
+ "codex",
451
+ "hermes",
452
+ "openclaw",
453
+ "generic"
454
+ ],
455
+ "path": "jobs/security/cve-watch.yaml"
456
+ },
255
457
  {
256
458
  "id": "daily-flashcard-review",
257
459
  "version": 1,
@@ -450,6 +652,33 @@
450
652
  ],
451
653
  "path": "jobs/devops/env-drift-check.yaml"
452
654
  },
655
+ {
656
+ "id": "error-rate-spike-watch",
657
+ "version": 1,
658
+ "name": "Error Rate Spike Watch",
659
+ "description": "Checks your error tracker's recent error count against a threshold and flags a spike. Use this if a bad deploy has ever quietly spiked errors for hours before anyone noticed.",
660
+ "category": "devops",
661
+ "tags": [
662
+ "errors",
663
+ "monitoring",
664
+ "alerting"
665
+ ],
666
+ "schedule": "*/15 * * * *",
667
+ "timezone": "UTC",
668
+ "runner": "hybrid",
669
+ "modes": [
670
+ "script",
671
+ "agent-prompt"
672
+ ],
673
+ "compatible_agents": [
674
+ "claude",
675
+ "codex",
676
+ "hermes",
677
+ "openclaw",
678
+ "generic"
679
+ ],
680
+ "path": "jobs/devops/error-rate-spike-watch.yaml"
681
+ },
453
682
  {
454
683
  "id": "failed-login-watch",
455
684
  "version": 1,
@@ -474,6 +703,32 @@
474
703
  ],
475
704
  "path": "jobs/security/failed-login-watch.yaml"
476
705
  },
706
+ {
707
+ "id": "feature-flag-staleness-audit",
708
+ "version": 1,
709
+ "name": "Feature Flag Staleness Audit",
710
+ "description": "Flags feature flags that have been at 100% (or 0%) rollout for a long time and never cleaned up. Use this if your flag list has become a graveyard of decisions nobody removed the scaffolding for.",
711
+ "category": "devops",
712
+ "tags": [
713
+ "feature-flags",
714
+ "cleanup",
715
+ "tech-debt"
716
+ ],
717
+ "schedule": "0 9 * * 1",
718
+ "timezone": "UTC",
719
+ "runner": "agent-prompt",
720
+ "modes": [
721
+ "agent-prompt"
722
+ ],
723
+ "compatible_agents": [
724
+ "claude",
725
+ "codex",
726
+ "hermes",
727
+ "openclaw",
728
+ "generic"
729
+ ],
730
+ "path": "jobs/devops/feature-flag-staleness-audit.yaml"
731
+ },
477
732
  {
478
733
  "id": "firewall-rule-diff",
479
734
  "version": 1,
@@ -546,6 +801,55 @@
546
801
  ],
547
802
  "path": "jobs/productivity/focus-block-reminder.yaml"
548
803
  },
804
+ {
805
+ "id": "frequent-flyer-miles-expiry",
806
+ "version": 1,
807
+ "name": "Frequent Flyer Miles Expiry Check",
808
+ "description": "Warns you before frequent flyer miles or points expire from inactivity. Use this if you've ever lost a stash of miles just because you didn't fly or transact on the account in time.",
809
+ "category": "travel",
810
+ "tags": [
811
+ "travel",
812
+ "miles",
813
+ "points",
814
+ "loyalty"
815
+ ],
816
+ "schedule": "0 9 1 * *",
817
+ "timezone": "UTC",
818
+ "runner": "shell",
819
+ "modes": [
820
+ "script"
821
+ ],
822
+ "compatible_agents": [
823
+ "generic",
824
+ "claude",
825
+ "codex"
826
+ ],
827
+ "path": "jobs/travel/frequent-flyer-miles-expiry.yaml"
828
+ },
829
+ {
830
+ "id": "fx-rate-watch",
831
+ "version": 1,
832
+ "name": "FX Rate Watch",
833
+ "description": "Checks a currency pair's exchange rate and alerts when it crosses a threshold you set. Use this if you're timing a transfer, payment, or purchase around a favorable rate and don't want to check manually every day.",
834
+ "category": "finance",
835
+ "tags": [
836
+ "finance",
837
+ "currency",
838
+ "fx"
839
+ ],
840
+ "schedule": "0 8 * * *",
841
+ "timezone": "UTC",
842
+ "runner": "shell",
843
+ "modes": [
844
+ "script"
845
+ ],
846
+ "compatible_agents": [
847
+ "generic",
848
+ "claude",
849
+ "codex"
850
+ ],
851
+ "path": "jobs/finance/fx-rate-watch.yaml"
852
+ },
549
853
  {
550
854
  "id": "habit-checkin",
551
855
  "version": 1,
@@ -594,6 +898,31 @@
594
898
  ],
595
899
  "path": "jobs/home/hvac-filter-reminder.yaml"
596
900
  },
901
+ {
902
+ "id": "iam-key-rotation-reminder",
903
+ "version": 1,
904
+ "name": "IAM Key Rotation Reminder",
905
+ "description": "Checks how old your IAM access keys are and flags any past your rotation age. Use this if you've ever found a years-old access key still active because nobody was tracking key age.",
906
+ "category": "security",
907
+ "tags": [
908
+ "security",
909
+ "iam",
910
+ "aws",
911
+ "rotation"
912
+ ],
913
+ "schedule": "0 8 1 * *",
914
+ "timezone": "UTC",
915
+ "runner": "shell",
916
+ "modes": [
917
+ "script"
918
+ ],
919
+ "compatible_agents": [
920
+ "generic",
921
+ "claude",
922
+ "codex"
923
+ ],
924
+ "path": "jobs/security/iam-key-rotation-reminder.yaml"
925
+ },
597
926
  {
598
927
  "id": "inbox-triage",
599
928
  "version": 1,
@@ -718,6 +1047,30 @@
718
1047
  ],
719
1048
  "path": "jobs/personal/meal-plan-reminder.yaml"
720
1049
  },
1050
+ {
1051
+ "id": "medication-refill-reminder",
1052
+ "version": 1,
1053
+ "name": "Medication Refill Reminder",
1054
+ "description": "Reminds you to refill a medication before you run out, based on how many days of supply you have left. Use this if you've ever run out of a prescription over a weekend when the pharmacy's closed.",
1055
+ "category": "personal",
1056
+ "tags": [
1057
+ "health",
1058
+ "medication",
1059
+ "reminder"
1060
+ ],
1061
+ "schedule": "0 9 * * *",
1062
+ "timezone": "America/Los_Angeles",
1063
+ "runner": "shell",
1064
+ "modes": [
1065
+ "script"
1066
+ ],
1067
+ "compatible_agents": [
1068
+ "generic",
1069
+ "claude",
1070
+ "codex"
1071
+ ],
1072
+ "path": "jobs/personal/medication-refill-reminder.yaml"
1073
+ },
721
1074
  {
722
1075
  "id": "net-worth-snapshot",
723
1076
  "version": 1,
@@ -742,6 +1095,30 @@
742
1095
  ],
743
1096
  "path": "jobs/finance/net-worth-snapshot.yaml"
744
1097
  },
1098
+ {
1099
+ "id": "oncall-handoff-reminder",
1100
+ "version": 1,
1101
+ "name": "On-call Handoff Reminder",
1102
+ "description": "Nudges outgoing and incoming on-call to sync before the shift changes. Use this if a handoff has ever happened silently and the new on-call found out about an open incident from a page instead of a briefing.",
1103
+ "category": "team",
1104
+ "tags": [
1105
+ "oncall",
1106
+ "handoff",
1107
+ "team"
1108
+ ],
1109
+ "schedule": "0 9 * * 1",
1110
+ "timezone": "America/Los_Angeles",
1111
+ "runner": "shell",
1112
+ "modes": [
1113
+ "script"
1114
+ ],
1115
+ "compatible_agents": [
1116
+ "generic",
1117
+ "claude",
1118
+ "codex"
1119
+ ],
1120
+ "path": "jobs/team/oncall-handoff-reminder.yaml"
1121
+ },
745
1122
  {
746
1123
  "id": "open-port-check",
747
1124
  "version": 1,
@@ -1009,6 +1386,31 @@
1009
1386
  ],
1010
1387
  "path": "jobs/content/rss-feed-validate.yaml"
1011
1388
  },
1389
+ {
1390
+ "id": "s3-public-bucket-check",
1391
+ "version": 1,
1392
+ "name": "S3 Public Bucket Check",
1393
+ "description": "Checks your S3 buckets for public access and flags any that are exposed. Use this if a misconfigured bucket policy has ever quietly made private data public.",
1394
+ "category": "security",
1395
+ "tags": [
1396
+ "security",
1397
+ "s3",
1398
+ "aws",
1399
+ "exposure"
1400
+ ],
1401
+ "schedule": "0 6 * * *",
1402
+ "timezone": "UTC",
1403
+ "runner": "shell",
1404
+ "modes": [
1405
+ "script"
1406
+ ],
1407
+ "compatible_agents": [
1408
+ "generic",
1409
+ "claude",
1410
+ "codex"
1411
+ ],
1412
+ "path": "jobs/security/s3-public-bucket-check.yaml"
1413
+ },
1012
1414
  {
1013
1415
  "id": "saas-seat-audit",
1014
1416
  "version": 1,
@@ -1108,6 +1510,30 @@
1108
1510
  ],
1109
1511
  "path": "jobs/content/seo-meta-check.yaml"
1110
1512
  },
1513
+ {
1514
+ "id": "sitemap-freshness-check",
1515
+ "version": 1,
1516
+ "name": "Sitemap Freshness Check",
1517
+ "description": "Checks that your sitemap.xml was actually regenerated recently and isn't quietly stuck on an old snapshot. Use this if your sitemap is generated by a build step that's ever silently failed or skipped.",
1518
+ "category": "content",
1519
+ "tags": [
1520
+ "seo",
1521
+ "sitemap",
1522
+ "freshness"
1523
+ ],
1524
+ "schedule": "0 7 * * *",
1525
+ "timezone": "UTC",
1526
+ "runner": "shell",
1527
+ "modes": [
1528
+ "script"
1529
+ ],
1530
+ "compatible_agents": [
1531
+ "generic",
1532
+ "claude",
1533
+ "codex"
1534
+ ],
1535
+ "path": "jobs/content/sitemap-freshness-check.yaml"
1536
+ },
1111
1537
  {
1112
1538
  "id": "smoke-detector-battery-check",
1113
1539
  "version": 1,
@@ -1207,6 +1633,56 @@
1207
1633
  ],
1208
1634
  "path": "jobs/devops/stale-dependency-pr-nudge.yaml"
1209
1635
  },
1636
+ {
1637
+ "id": "stale-post-audit",
1638
+ "version": 1,
1639
+ "name": "Stale Post Audit",
1640
+ "description": "Flags published posts that haven't been touched in a long time, as candidates for a refresh. Use this if old content quietly rots (dead screenshots, outdated advice) while still ranking and getting traffic.",
1641
+ "category": "content",
1642
+ "tags": [
1643
+ "content",
1644
+ "seo",
1645
+ "maintenance"
1646
+ ],
1647
+ "schedule": "0 8 1 * *",
1648
+ "timezone": "UTC",
1649
+ "runner": "agent-prompt",
1650
+ "modes": [
1651
+ "agent-prompt"
1652
+ ],
1653
+ "compatible_agents": [
1654
+ "claude",
1655
+ "codex",
1656
+ "hermes",
1657
+ "openclaw",
1658
+ "generic"
1659
+ ],
1660
+ "path": "jobs/content/stale-post-audit.yaml"
1661
+ },
1662
+ {
1663
+ "id": "stale-todo-sweep",
1664
+ "version": 1,
1665
+ "name": "Stale Todo Sweep",
1666
+ "description": "Finds TODO/FIXME comments in your codebase that have sat untouched for a long time, so you can decide whether to fix, ticket, or delete them. Use this if TODO comments in this repo have basically become permanent decor.",
1667
+ "category": "productivity",
1668
+ "tags": [
1669
+ "todos",
1670
+ "cleanup",
1671
+ "code-hygiene"
1672
+ ],
1673
+ "schedule": "0 9 * * 1",
1674
+ "timezone": "UTC",
1675
+ "runner": "shell",
1676
+ "modes": [
1677
+ "script"
1678
+ ],
1679
+ "compatible_agents": [
1680
+ "generic",
1681
+ "claude",
1682
+ "codex"
1683
+ ],
1684
+ "path": "jobs/productivity/stale-todo-sweep.yaml"
1685
+ },
1210
1686
  {
1211
1687
  "id": "subscription-audit",
1212
1688
  "version": 1,
@@ -1279,6 +1755,105 @@
1279
1755
  ],
1280
1756
  "path": "jobs/finance/tax-deadline-reminder.yaml"
1281
1757
  },
1758
+ {
1759
+ "id": "team-anniversary-reminder",
1760
+ "version": 1,
1761
+ "name": "Team Anniversary Reminder",
1762
+ "description": "Reminds you about teammates' birthdays and work anniversaries coming up this week. Use this if you've ever felt bad realizing a work anniversary passed with zero acknowledgment.",
1763
+ "category": "team",
1764
+ "tags": [
1765
+ "team",
1766
+ "birthdays",
1767
+ "anniversaries"
1768
+ ],
1769
+ "schedule": "0 9 * * 1",
1770
+ "timezone": "America/Los_Angeles",
1771
+ "runner": "shell",
1772
+ "modes": [
1773
+ "script"
1774
+ ],
1775
+ "compatible_agents": [
1776
+ "generic",
1777
+ "claude",
1778
+ "codex"
1779
+ ],
1780
+ "path": "jobs/team/team-anniversary-reminder.yaml"
1781
+ },
1782
+ {
1783
+ "id": "terraform-drift-check",
1784
+ "version": 1,
1785
+ "name": "Terraform Drift Check",
1786
+ "description": "Runs a Terraform plan and flags it if there's drift between your state and actual infrastructure. Use this if you've ever had someone click around in a cloud console and quietly break parity with your IaC.",
1787
+ "category": "devops",
1788
+ "tags": [
1789
+ "terraform",
1790
+ "infrastructure",
1791
+ "drift"
1792
+ ],
1793
+ "schedule": "0 7 * * 1-5",
1794
+ "timezone": "UTC",
1795
+ "runner": "shell",
1796
+ "modes": [
1797
+ "script"
1798
+ ],
1799
+ "compatible_agents": [
1800
+ "generic",
1801
+ "claude",
1802
+ "codex"
1803
+ ],
1804
+ "path": "jobs/devops/terraform-drift-check.yaml"
1805
+ },
1806
+ {
1807
+ "id": "travel-insurance-expiry-check",
1808
+ "version": 1,
1809
+ "name": "Travel Insurance Expiry Check",
1810
+ "description": "Warns you if you have an upcoming trip with no travel insurance policy covering it, or a policy expiring before the trip ends. Use this if you've ever booked a trip and only thought about insurance the night before.",
1811
+ "category": "travel",
1812
+ "tags": [
1813
+ "travel",
1814
+ "insurance",
1815
+ "documents"
1816
+ ],
1817
+ "schedule": "0 9 * * 1",
1818
+ "timezone": "UTC",
1819
+ "runner": "shell",
1820
+ "modes": [
1821
+ "script"
1822
+ ],
1823
+ "compatible_agents": [
1824
+ "generic",
1825
+ "claude",
1826
+ "codex"
1827
+ ],
1828
+ "path": "jobs/travel/travel-insurance-expiry-check.yaml"
1829
+ },
1830
+ {
1831
+ "id": "trial-expiring-nudge",
1832
+ "version": 1,
1833
+ "name": "Trial Expiring Nudge",
1834
+ "description": "Finds trial users about to expire who haven't upgraded yet, and can draft the nudge email. Use this if trial-to-paid conversion nudges only happen when someone remembers to send them.",
1835
+ "category": "growth",
1836
+ "tags": [
1837
+ "growth",
1838
+ "trials",
1839
+ "conversion"
1840
+ ],
1841
+ "schedule": "0 10 * * *",
1842
+ "timezone": "UTC",
1843
+ "runner": "hybrid",
1844
+ "modes": [
1845
+ "script",
1846
+ "agent-prompt"
1847
+ ],
1848
+ "compatible_agents": [
1849
+ "claude",
1850
+ "codex",
1851
+ "hermes",
1852
+ "openclaw",
1853
+ "generic"
1854
+ ],
1855
+ "path": "jobs/growth/trial-expiring-nudge.yaml"
1856
+ },
1282
1857
  {
1283
1858
  "id": "uptime-ping-check",
1284
1859
  "version": 1,
@@ -0,0 +1,25 @@
1
+ id: canonical-tag-check
2
+ version: 1
3
+ name: Canonical Tag Check
4
+ description: >
5
+ Checks a list of pages for missing or self-conflicting canonical tags.
6
+ Use this if a templating bug has ever pointed every page's canonical at
7
+ the homepage (or nowhere at all) without anyone noticing.
8
+ category: content
9
+ tags: [seo, canonical, content]
10
+ schedule: "0 7 * * 1"
11
+ timezone: "UTC"
12
+ runner: shell
13
+ command: >
14
+ while IFS= read -r url; do
15
+ [ -z "$url" ] && continue;
16
+ canonical=$(curl -s "$url" | grep -o '<link[^>]*rel=["'"'"']canonical["'"'"'][^>]*>' | grep -o 'href=["'"'"'][^"'"'"']*' | sed 's/href=["'"'"']//');
17
+ if [ -z "$canonical" ]; then echo "MISSING canonical: $url";
18
+ elif [ "$canonical" != "$url" ]; then echo "MISMATCH: $url -> $canonical"; fi;
19
+ done < {{url_list_file}}
20
+ variables:
21
+ url_list_file:
22
+ default: "urls.txt"
23
+ description: Path to a file with one URL per line to check.
24
+ compatible_agents: [generic, claude, codex]
25
+ notes: Flags any canonical that doesn't exactly match the page URL — cross-check mismatches manually since some (e.g. tracking params stripped) are intentional.