@wonsukchoi/crondex 0.3.0 → 0.5.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/README.md +47 -2
- package/catalog.json +508 -1
- package/jobs/content/robots-txt-check.yaml +30 -0
- package/jobs/content/rss-feed-validate.yaml +32 -0
- package/jobs/content/seo-meta-check.yaml +32 -0
- package/jobs/devops/api-rate-limit-check.yaml +31 -0
- package/jobs/devops/dns-record-check.yaml +32 -0
- package/jobs/devops/queue-depth-check.yaml +35 -0
- package/jobs/finance/invoice-overdue-check.yaml +32 -0
- package/jobs/finance/tax-deadline-reminder.yaml +33 -0
- package/jobs/growth/cart-abandonment-followup.yaml +46 -0
- package/jobs/growth/review-request-nudge.yaml +35 -0
- package/jobs/home/hvac-filter-reminder.yaml +29 -0
- package/jobs/home/plant-watering-reminder.yaml +30 -0
- package/jobs/home/smoke-detector-battery-check.yaml +29 -0
- package/jobs/security/certificate-transparency-watch.yaml +31 -0
- package/jobs/security/firewall-rule-diff.yaml +30 -0
- package/jobs/security/sudo-usage-audit.yaml +35 -0
- package/jobs/team/1on1-prep-reminder.yaml +26 -0
- package/jobs/team/pto-balance-check.yaml +33 -0
- package/jobs/travel/flight-checkin-reminder.yaml +31 -0
- package/jobs/travel/passport-expiry-check.yaml +31 -0
- package/jobs/travel/visa-expiry-check.yaml +32 -0
- package/package.json +1 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
id: robots-txt-check
|
|
2
|
+
version: 1
|
|
3
|
+
name: Robots.txt Blanket-Block Check
|
|
4
|
+
description: >
|
|
5
|
+
Checks that your robots.txt hasn't accidentally blocked every
|
|
6
|
+
crawler from your entire site. Use this if a robots.txt edit has
|
|
7
|
+
ever accidentally tanked your search traffic.
|
|
8
|
+
category: content
|
|
9
|
+
tags: [seo, robots, crawlability]
|
|
10
|
+
schedule: "0 8 * * *"
|
|
11
|
+
timezone: "UTC"
|
|
12
|
+
runner: shell
|
|
13
|
+
command: >
|
|
14
|
+
url={{robots_url}};
|
|
15
|
+
body=$(curl -sL --max-time 10 "$url");
|
|
16
|
+
[ -z "$body" ] && { echo "ERROR: could not fetch $url"; exit 1; };
|
|
17
|
+
if echo "$body" | grep -qiE "^Disallow:[[:space:]]*/[[:space:]]*$"; then
|
|
18
|
+
echo "WARNING: $url has a blanket 'Disallow: /' — this blocks all crawlers from the whole site.";
|
|
19
|
+
exit 1;
|
|
20
|
+
else
|
|
21
|
+
echo "OK: no blanket disallow-all rule found in $url";
|
|
22
|
+
fi
|
|
23
|
+
variables:
|
|
24
|
+
robots_url:
|
|
25
|
+
default: "https://example.com/robots.txt"
|
|
26
|
+
description: Full URL to your site's robots.txt.
|
|
27
|
+
compatible_agents: [generic, claude, codex]
|
|
28
|
+
notes: >
|
|
29
|
+
Zero-token. Only checks for the "block everything" footgun, not full
|
|
30
|
+
robots.txt correctness.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
id: rss-feed-validate
|
|
2
|
+
version: 1
|
|
3
|
+
name: RSS Feed Validation
|
|
4
|
+
description: >
|
|
5
|
+
Checks your RSS/Atom feed is valid XML and shows the most recent
|
|
6
|
+
item's publish date. Use this if you've ever shipped a broken feed
|
|
7
|
+
and only found out when a reader's app stopped updating.
|
|
8
|
+
category: content
|
|
9
|
+
tags: [rss, feed, content]
|
|
10
|
+
schedule: "0 8 * * *"
|
|
11
|
+
timezone: "UTC"
|
|
12
|
+
runner: shell
|
|
13
|
+
command: >
|
|
14
|
+
url={{feed_url}};
|
|
15
|
+
xml=$(curl -sL --max-time 10 "$url");
|
|
16
|
+
[ -z "$xml" ] && { echo "ERROR: could not fetch $url"; exit 1; };
|
|
17
|
+
if command -v xmllint >/dev/null 2>&1; then
|
|
18
|
+
echo "$xml" | xmllint --noout - 2>&1 && echo "OK: valid XML" || { echo "INVALID XML"; exit 1; };
|
|
19
|
+
else
|
|
20
|
+
echo "xmllint not installed, skipping strict XML validation";
|
|
21
|
+
fi;
|
|
22
|
+
pubdate=$(echo "$xml" | grep -oE "<pubDate>[^<]+</pubDate>" | head -n1 | sed 's/<[^>]*>//g');
|
|
23
|
+
echo "Most recent item pubDate: ${pubdate:-unknown}"
|
|
24
|
+
variables:
|
|
25
|
+
feed_url:
|
|
26
|
+
default: "https://example.com/feed.xml"
|
|
27
|
+
description: URL of the RSS/Atom feed to check.
|
|
28
|
+
compatible_agents: [generic, claude, codex]
|
|
29
|
+
notes: >
|
|
30
|
+
Zero-token. Only reports the latest pubDate for you to eyeball —
|
|
31
|
+
doesn't flag "stale" automatically since feed cadences vary too much
|
|
32
|
+
for one threshold. Install `xmllint` (libxml2) for strict validation.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
id: seo-meta-check
|
|
2
|
+
version: 1
|
|
3
|
+
name: SEO Meta Tag Check
|
|
4
|
+
description: >
|
|
5
|
+
Checks a list of pages for missing title, meta description, and
|
|
6
|
+
Open Graph tags. Use this if pages have ever shipped without basic
|
|
7
|
+
SEO/social-preview tags because nobody double-checked.
|
|
8
|
+
category: content
|
|
9
|
+
tags: [seo, content, meta-tags]
|
|
10
|
+
schedule: "0 7 * * 1"
|
|
11
|
+
timezone: "UTC"
|
|
12
|
+
runner: shell
|
|
13
|
+
command: >
|
|
14
|
+
file={{urls_file}};
|
|
15
|
+
[ -f "$file" ] || { echo "ERROR: $file not found"; exit 1; };
|
|
16
|
+
while IFS= read -r url; do
|
|
17
|
+
[ -z "$url" ] && continue;
|
|
18
|
+
html=$(curl -sL --max-time 10 "$url");
|
|
19
|
+
missing="";
|
|
20
|
+
echo "$html" | grep -qi "<title>" || missing="$missing title";
|
|
21
|
+
echo "$html" | grep -qi 'name="description"' || missing="$missing meta-description";
|
|
22
|
+
echo "$html" | grep -qi 'property="og:title"' || missing="$missing og:title";
|
|
23
|
+
if [ -n "$missing" ]; then echo "MISSING on $url:$missing"; else echo "OK: $url"; fi
|
|
24
|
+
done < "$file"
|
|
25
|
+
variables:
|
|
26
|
+
urls_file:
|
|
27
|
+
default: "./pages.txt"
|
|
28
|
+
description: Plain text file with one page URL per line to check.
|
|
29
|
+
compatible_agents: [generic, claude, codex]
|
|
30
|
+
notes: >
|
|
31
|
+
Zero-token. Basic presence check only (does the tag exist), not content
|
|
32
|
+
quality — pair with a fuller SEO audit for anything deeper.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
id: api-rate-limit-check
|
|
2
|
+
version: 1
|
|
3
|
+
name: API Rate Limit Check
|
|
4
|
+
description: >
|
|
5
|
+
Checks how many API requests you have left before hitting a rate
|
|
6
|
+
limit. Use this if you've ever gotten a 429 in production because
|
|
7
|
+
nobody was watching the remaining quota.
|
|
8
|
+
category: devops
|
|
9
|
+
tags: [api, rate-limit, monitoring]
|
|
10
|
+
schedule: "*/15 * * * *"
|
|
11
|
+
timezone: "UTC"
|
|
12
|
+
runner: shell
|
|
13
|
+
command: >
|
|
14
|
+
url={{api_url}};
|
|
15
|
+
headers=$(curl -sI --max-time 10 "$url");
|
|
16
|
+
remaining=$(echo "$headers" | grep -i "^x-ratelimit-remaining:" | awk '{print $2}' | tr -d '\r');
|
|
17
|
+
if [ -z "$remaining" ]; then echo "no rate-limit headers found on $url (nothing to check, or a different header convention)"; exit 0;
|
|
18
|
+
elif [ "$remaining" -le {{warn_threshold}} ]; then echo "WARNING: $url has only $remaining requests remaining"; exit 1;
|
|
19
|
+
else echo "OK: $url has $remaining requests remaining"; fi
|
|
20
|
+
variables:
|
|
21
|
+
api_url:
|
|
22
|
+
default: "https://api.example.com/status"
|
|
23
|
+
description: An endpoint on the API you want to watch — any request that returns rate-limit headers works.
|
|
24
|
+
warn_threshold:
|
|
25
|
+
default: 50
|
|
26
|
+
description: Warn if remaining requests drops to this or below.
|
|
27
|
+
compatible_agents: [generic, claude, codex]
|
|
28
|
+
notes: >
|
|
29
|
+
Assumes the standard `X-RateLimit-Remaining` response header — adjust
|
|
30
|
+
the grep pattern if your API uses a different convention
|
|
31
|
+
(e.g. `RateLimit-Remaining`, a custom header).
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
id: dns-record-check
|
|
2
|
+
version: 1
|
|
3
|
+
name: DNS Record Drift Check
|
|
4
|
+
description: >
|
|
5
|
+
Checks that a DNS record still resolves to the value you expect, and
|
|
6
|
+
flags drift. Use this if you've ever had DNS quietly change (an
|
|
7
|
+
expired record, a misconfigured provider) and only found out when
|
|
8
|
+
something broke.
|
|
9
|
+
category: devops
|
|
10
|
+
tags: [dns, monitoring, drift]
|
|
11
|
+
schedule: "0 */6 * * *"
|
|
12
|
+
timezone: "UTC"
|
|
13
|
+
runner: shell
|
|
14
|
+
command: >
|
|
15
|
+
domain={{domain}}; type={{record_type}}; expected="{{expected_value}}";
|
|
16
|
+
command -v dig >/dev/null 2>&1 || { echo "ERROR: dig not installed"; exit 1; };
|
|
17
|
+
actual=$(dig +short "$domain" "$type" | tr '\n' ' ' | sed 's/ *$//');
|
|
18
|
+
if [ -z "$actual" ]; then echo "ERROR: no $type record found for $domain"; exit 1;
|
|
19
|
+
elif echo "$actual" | grep -qF "$expected"; then echo "OK: $domain $type matches expected ($actual)";
|
|
20
|
+
else echo "DRIFT: $domain $type is '$actual', expected to contain '$expected'"; exit 1; fi
|
|
21
|
+
variables:
|
|
22
|
+
domain:
|
|
23
|
+
default: "example.com"
|
|
24
|
+
description: Domain to check.
|
|
25
|
+
record_type:
|
|
26
|
+
default: "A"
|
|
27
|
+
description: DNS record type (A, CNAME, TXT, MX, etc).
|
|
28
|
+
expected_value:
|
|
29
|
+
default: "93.184.216.34"
|
|
30
|
+
description: Value the record should contain — replace with your actual expected record.
|
|
31
|
+
compatible_agents: [generic, claude, codex]
|
|
32
|
+
notes: Zero-token, deterministic. Requires `dig` (part of dnsutils/bind-tools).
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
id: queue-depth-check
|
|
2
|
+
version: 1
|
|
3
|
+
name: Queue Depth Check
|
|
4
|
+
description: >
|
|
5
|
+
Checks how backed up a job queue is and warns if it crosses a
|
|
6
|
+
threshold. Use this if a stuck worker has ever let a queue silently
|
|
7
|
+
balloon until someone noticed customers weren't getting emails.
|
|
8
|
+
category: devops
|
|
9
|
+
tags: [queue, redis, monitoring]
|
|
10
|
+
schedule: "*/10 * * * *"
|
|
11
|
+
timezone: "UTC"
|
|
12
|
+
runner: shell
|
|
13
|
+
command: >
|
|
14
|
+
command -v redis-cli >/dev/null 2>&1 || { echo "ERROR: redis-cli not installed"; exit 1; };
|
|
15
|
+
depth=$(redis-cli -h {{redis_host}} -p {{redis_port}} llen {{queue_key}} 2>/dev/null);
|
|
16
|
+
if [ -z "$depth" ]; then echo "ERROR: could not read queue depth for {{queue_key}}"; exit 1;
|
|
17
|
+
elif [ "$depth" -ge {{threshold}} ]; then echo "WARNING: queue {{queue_key}} depth is $depth (threshold {{threshold}})"; exit 1;
|
|
18
|
+
else echo "OK: queue {{queue_key}} depth is $depth"; fi
|
|
19
|
+
variables:
|
|
20
|
+
redis_host:
|
|
21
|
+
default: "localhost"
|
|
22
|
+
description: Redis host.
|
|
23
|
+
redis_port:
|
|
24
|
+
default: 6379
|
|
25
|
+
description: Redis port.
|
|
26
|
+
queue_key:
|
|
27
|
+
default: "jobs:pending"
|
|
28
|
+
description: Redis list key backing the queue.
|
|
29
|
+
threshold:
|
|
30
|
+
default: 1000
|
|
31
|
+
description: Warn if the queue depth reaches this many items.
|
|
32
|
+
compatible_agents: [generic, claude, codex]
|
|
33
|
+
notes: >
|
|
34
|
+
Redis list-backed queues only (uses LLEN). Adapt the depth-check
|
|
35
|
+
command for RabbitMQ, SQS, or other queue systems.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
id: invoice-overdue-check
|
|
2
|
+
version: 1
|
|
3
|
+
name: Invoice Overdue Check
|
|
4
|
+
description: >
|
|
5
|
+
Flags invoices that are past due and still unpaid. Use this if you
|
|
6
|
+
freelance or run a small business and invoices have ever slipped
|
|
7
|
+
through the cracks.
|
|
8
|
+
category: finance
|
|
9
|
+
tags: [invoices, accounts-receivable, finance]
|
|
10
|
+
schedule: "0 9 * * *"
|
|
11
|
+
timezone: "UTC"
|
|
12
|
+
runner: shell
|
|
13
|
+
command: >
|
|
14
|
+
file={{invoices_file}};
|
|
15
|
+
[ -f "$file" ] || { echo "ERROR: $file not found"; exit 1; };
|
|
16
|
+
today=$(date +%s);
|
|
17
|
+
tail -n +2 "$file" | while IFS=, read -r id client amount due paid; do
|
|
18
|
+
[ "$paid" = "yes" ] && continue;
|
|
19
|
+
due_epoch=$(date -j -f %Y-%m-%d "$due" +%s 2>/dev/null || date -d "$due" +%s);
|
|
20
|
+
days=$(( (today-due_epoch)/86400 ));
|
|
21
|
+
if [ "$days" -gt 0 ]; then echo "OVERDUE: invoice $id ($client, \$$amount) — $days day(s) past due ($due)"; fi
|
|
22
|
+
done
|
|
23
|
+
variables:
|
|
24
|
+
invoices_file:
|
|
25
|
+
default: "./invoices.csv"
|
|
26
|
+
description: >
|
|
27
|
+
CSV with header "invoice_id,client,amount,due_date,paid"
|
|
28
|
+
(due_date is YYYY-MM-DD, paid is yes/no).
|
|
29
|
+
compatible_agents: [generic, claude, codex]
|
|
30
|
+
notes: >
|
|
31
|
+
Zero-token. You maintain invoices.csv yourself (mark paid=yes once
|
|
32
|
+
settled) — this doesn't connect to any billing/accounting system.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
id: tax-deadline-reminder
|
|
2
|
+
version: 1
|
|
3
|
+
name: Tax Deadline Reminder
|
|
4
|
+
description: >
|
|
5
|
+
Warns you ahead of upcoming tax deadlines you've listed. Use this if
|
|
6
|
+
quarterly estimated payments or annual filing dates have ever snuck
|
|
7
|
+
up on you.
|
|
8
|
+
category: finance
|
|
9
|
+
tags: [tax, deadlines, finance]
|
|
10
|
+
schedule: "0 9 * * *"
|
|
11
|
+
timezone: "UTC"
|
|
12
|
+
runner: shell
|
|
13
|
+
command: >
|
|
14
|
+
file={{deadlines_file}}; warn={{warn_days}};
|
|
15
|
+
[ -f "$file" ] || { echo "ERROR: $file not found"; exit 1; };
|
|
16
|
+
today=$(date +%s);
|
|
17
|
+
tail -n +2 "$file" | while IFS=, read -r label due; do
|
|
18
|
+
[ -z "$due" ] && continue;
|
|
19
|
+
due_epoch=$(date -j -f %Y-%m-%d "$due" +%s 2>/dev/null || date -d "$due" +%s);
|
|
20
|
+
days=$(( (due_epoch-today)/86400 ));
|
|
21
|
+
if [ "$days" -ge 0 ] && [ "$days" -le "$warn" ]; then echo "REMINDER: $label due in $days day(s) ($due)"; fi
|
|
22
|
+
done
|
|
23
|
+
variables:
|
|
24
|
+
deadlines_file:
|
|
25
|
+
default: "./tax-deadlines.csv"
|
|
26
|
+
description: CSV with header "label,date" (date is YYYY-MM-DD), one deadline per row.
|
|
27
|
+
warn_days:
|
|
28
|
+
default: 14
|
|
29
|
+
description: Start warning this many days before a deadline.
|
|
30
|
+
compatible_agents: [generic, claude, codex]
|
|
31
|
+
notes: >
|
|
32
|
+
Zero-token. You maintain tax-deadlines.csv yourself with your actual
|
|
33
|
+
jurisdiction's dates — this job doesn't know tax law or deadlines on its own.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
id: cart-abandonment-followup
|
|
2
|
+
version: 1
|
|
3
|
+
name: Cart Abandonment Follow-up
|
|
4
|
+
description: >
|
|
5
|
+
Finds abandoned shopping carts old enough to follow up on, and can
|
|
6
|
+
draft the follow-up email for you. Use this if abandoned-cart
|
|
7
|
+
recovery is something you know you should do but never get to.
|
|
8
|
+
category: growth
|
|
9
|
+
tags: [growth, ecommerce, cart-recovery]
|
|
10
|
+
schedule: "0 10 * * *"
|
|
11
|
+
timezone: "UTC"
|
|
12
|
+
runner: hybrid
|
|
13
|
+
command: >
|
|
14
|
+
file={{carts_file}}; wait_hours={{wait_hours}};
|
|
15
|
+
[ -f "$file" ] || { echo "ERROR: $file not found"; exit 1; };
|
|
16
|
+
now=$(date +%s);
|
|
17
|
+
tail -n +2 "$file" | while IFS=, read -r id email items abandoned followed; do
|
|
18
|
+
[ "$followed" = "yes" ] && continue;
|
|
19
|
+
a_epoch=$(date -d "$abandoned" +%s 2>/dev/null || date -j -f "%Y-%m-%d %H:%M" "$abandoned" +%s 2>/dev/null);
|
|
20
|
+
hours=$(( (now-a_epoch)/3600 ));
|
|
21
|
+
if [ "$hours" -ge "$wait_hours" ]; then echo "ABANDONED: cart $id ($email) - items: $items - ${hours}h ago"; fi
|
|
22
|
+
done
|
|
23
|
+
prompt: |
|
|
24
|
+
Look at carts abandoned more than {{wait_hours}} hours ago in
|
|
25
|
+
{{carts_file}} (CSV: cart_id,customer_email,items,abandoned_at,followed_up).
|
|
26
|
+
For each one not yet followed up:
|
|
27
|
+
1. Draft a short, friendly follow-up email offering help or a gentle
|
|
28
|
+
nudge to complete checkout.
|
|
29
|
+
2. Keep it under 100 words, no hard-sell tone.
|
|
30
|
+
script_note: >
|
|
31
|
+
`command` lists which carts are abandoned and old enough to follow up
|
|
32
|
+
on, zero tokens. `prompt` actually drafts the follow-up email copy for
|
|
33
|
+
each one.
|
|
34
|
+
variables:
|
|
35
|
+
carts_file:
|
|
36
|
+
default: "./abandoned-carts.csv"
|
|
37
|
+
description: >
|
|
38
|
+
CSV with header "cart_id,customer_email,items,abandoned_at,followed_up"
|
|
39
|
+
(abandoned_at is "YYYY-MM-DD HH:MM", followed_up is yes/no).
|
|
40
|
+
wait_hours:
|
|
41
|
+
default: 24
|
|
42
|
+
description: Wait this many hours after abandonment before flagging for follow-up.
|
|
43
|
+
compatible_agents: [claude, codex, hermes, openclaw, generic]
|
|
44
|
+
notes: >
|
|
45
|
+
You maintain abandoned-carts.csv yourself (or export it from your store
|
|
46
|
+
platform) — mark followed_up=yes after sending.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
id: review-request-nudge
|
|
2
|
+
version: 1
|
|
3
|
+
name: Review Request Nudge
|
|
4
|
+
description: >
|
|
5
|
+
Flags customers who bought a while ago and haven't been asked for a
|
|
6
|
+
review yet. Use this if review requests only happen when someone
|
|
7
|
+
remembers to send them.
|
|
8
|
+
category: growth
|
|
9
|
+
tags: [growth, reviews, ecommerce]
|
|
10
|
+
schedule: "0 9 * * *"
|
|
11
|
+
timezone: "UTC"
|
|
12
|
+
runner: shell
|
|
13
|
+
command: >
|
|
14
|
+
file={{orders_file}}; wait_days={{wait_days}};
|
|
15
|
+
[ -f "$file" ] || { echo "ERROR: $file not found"; exit 1; };
|
|
16
|
+
today=$(date +%s);
|
|
17
|
+
tail -n +2 "$file" | while IFS=, read -r id customer purchased requested; do
|
|
18
|
+
[ "$requested" = "yes" ] && continue;
|
|
19
|
+
p_epoch=$(date -j -f %Y-%m-%d "$purchased" +%s 2>/dev/null || date -d "$purchased" +%s);
|
|
20
|
+
days=$(( (today-p_epoch)/86400 ));
|
|
21
|
+
if [ "$days" -ge "$wait_days" ]; then echo "SEND REVIEW REQUEST: order $id ($customer), purchased $days day(s) ago"; fi
|
|
22
|
+
done
|
|
23
|
+
variables:
|
|
24
|
+
orders_file:
|
|
25
|
+
default: "./orders.csv"
|
|
26
|
+
description: >
|
|
27
|
+
CSV with header "order_id,customer,purchase_date,review_requested"
|
|
28
|
+
(purchase_date is YYYY-MM-DD, review_requested is yes/no).
|
|
29
|
+
wait_days:
|
|
30
|
+
default: 7
|
|
31
|
+
description: Wait this many days after purchase before flagging for a review request.
|
|
32
|
+
compatible_agents: [generic, claude, codex]
|
|
33
|
+
notes: >
|
|
34
|
+
Zero-token. You maintain orders.csv yourself (mark review_requested=yes
|
|
35
|
+
after sending) — doesn't integrate with any store platform directly.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
id: hvac-filter-reminder
|
|
2
|
+
version: 1
|
|
3
|
+
name: HVAC Filter Change Reminder
|
|
4
|
+
description: >
|
|
5
|
+
Reminds you to change your HVAC filter based on how long it's been.
|
|
6
|
+
Use this if you've ever found a filter so clogged you forgot it was
|
|
7
|
+
ever white.
|
|
8
|
+
category: home
|
|
9
|
+
tags: [home, hvac, maintenance]
|
|
10
|
+
schedule: "0 9 1 * *"
|
|
11
|
+
timezone: "America/Los_Angeles"
|
|
12
|
+
runner: shell
|
|
13
|
+
command: >
|
|
14
|
+
last={{last_changed_date}}; interval={{interval_months}};
|
|
15
|
+
last_epoch=$(date -j -f %Y-%m-%d "$last" +%s 2>/dev/null || date -d "$last" +%s);
|
|
16
|
+
today_epoch=$(date +%s);
|
|
17
|
+
days_since=$(( (today_epoch-last_epoch)/86400 ));
|
|
18
|
+
interval_days=$(( interval * 30 ));
|
|
19
|
+
if [ "$days_since" -ge "$interval_days" ]; then echo "REMINDER: HVAC filter last changed $days_since day(s) ago (every ${interval} months) — change it.";
|
|
20
|
+
else echo "OK: filter changed $days_since day(s) ago, due again around day $interval_days."; fi
|
|
21
|
+
variables:
|
|
22
|
+
last_changed_date:
|
|
23
|
+
default: "2026-01-01"
|
|
24
|
+
description: Date (YYYY-MM-DD) you last changed the filter — update this yourself.
|
|
25
|
+
interval_months:
|
|
26
|
+
default: 3
|
|
27
|
+
description: How often to change the filter, in months.
|
|
28
|
+
compatible_agents: [generic, claude, codex]
|
|
29
|
+
notes: Zero-token. You update last_changed_date yourself each time you actually change it.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
id: plant-watering-reminder
|
|
2
|
+
version: 1
|
|
3
|
+
name: Plant Watering Reminder
|
|
4
|
+
description: >
|
|
5
|
+
Reminds you to water a specific plant once it's due. Use this if
|
|
6
|
+
you've ever lost a plant to "I'll water it tomorrow."
|
|
7
|
+
category: home
|
|
8
|
+
tags: [home, plants, reminder]
|
|
9
|
+
schedule: "0 9 * * *"
|
|
10
|
+
timezone: "America/Los_Angeles"
|
|
11
|
+
runner: shell
|
|
12
|
+
command: >
|
|
13
|
+
last={{last_watered_date}}; interval={{water_interval_days}};
|
|
14
|
+
last_epoch=$(date -j -f %Y-%m-%d "$last" +%s 2>/dev/null || date -d "$last" +%s);
|
|
15
|
+
today_epoch=$(date +%s);
|
|
16
|
+
days_since=$(( (today_epoch-last_epoch)/86400 ));
|
|
17
|
+
if [ "$days_since" -ge "$interval" ]; then echo "REMINDER: water {{plant_name}} ($days_since day(s) since last watering, every $interval day(s)).";
|
|
18
|
+
else echo "OK: {{plant_name}} watered $days_since day(s) ago, next due in $(( interval - days_since )) day(s)."; fi
|
|
19
|
+
variables:
|
|
20
|
+
plant_name:
|
|
21
|
+
default: "your plant"
|
|
22
|
+
description: Which plant this reminder is for.
|
|
23
|
+
water_interval_days:
|
|
24
|
+
default: 7
|
|
25
|
+
description: How often to water it, in days.
|
|
26
|
+
last_watered_date:
|
|
27
|
+
default: "2026-01-01"
|
|
28
|
+
description: Date (YYYY-MM-DD) you last watered it — update this yourself.
|
|
29
|
+
compatible_agents: [generic, claude, codex]
|
|
30
|
+
notes: Zero-token. One job per plant — copy it and adjust plant_name/interval for each.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
id: smoke-detector-battery-check
|
|
2
|
+
version: 1
|
|
3
|
+
name: Smoke Detector Battery Check Reminder
|
|
4
|
+
description: >
|
|
5
|
+
Reminds you to test/replace smoke detector batteries on a schedule.
|
|
6
|
+
Use this if the only time you think about smoke detectors is when one
|
|
7
|
+
starts chirping at 3am.
|
|
8
|
+
category: home
|
|
9
|
+
tags: [home, safety, maintenance]
|
|
10
|
+
schedule: "0 9 1 * *"
|
|
11
|
+
timezone: "America/Los_Angeles"
|
|
12
|
+
runner: shell
|
|
13
|
+
command: >
|
|
14
|
+
last={{last_tested_date}}; interval={{interval_months}};
|
|
15
|
+
last_epoch=$(date -j -f %Y-%m-%d "$last" +%s 2>/dev/null || date -d "$last" +%s);
|
|
16
|
+
today_epoch=$(date +%s);
|
|
17
|
+
days_since=$(( (today_epoch-last_epoch)/86400 ));
|
|
18
|
+
interval_days=$(( interval * 30 ));
|
|
19
|
+
if [ "$days_since" -ge "$interval_days" ]; then echo "REMINDER: smoke detectors last tested $days_since day(s) ago (every ${interval} months) — test/replace batteries.";
|
|
20
|
+
else echo "OK: tested $days_since day(s) ago, due again around day $interval_days."; fi
|
|
21
|
+
variables:
|
|
22
|
+
last_tested_date:
|
|
23
|
+
default: "2026-01-01"
|
|
24
|
+
description: Date (YYYY-MM-DD) you last tested/changed batteries — update this yourself.
|
|
25
|
+
interval_months:
|
|
26
|
+
default: 6
|
|
27
|
+
description: How often to test, in months.
|
|
28
|
+
compatible_agents: [generic, claude, codex]
|
|
29
|
+
notes: Zero-token. You update last_tested_date yourself each time you actually test.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
id: certificate-transparency-watch
|
|
2
|
+
version: 1
|
|
3
|
+
name: Certificate Transparency Watch
|
|
4
|
+
description: >
|
|
5
|
+
Checks public Certificate Transparency logs for new TLS certs issued
|
|
6
|
+
for your domain and flags any you didn't expect. Use this if you want
|
|
7
|
+
an early warning for someone issuing a cert for your domain without
|
|
8
|
+
your knowledge (a common precursor to phishing/MITM setups).
|
|
9
|
+
category: security
|
|
10
|
+
tags: [security, tls, certificate-transparency]
|
|
11
|
+
schedule: "0 */12 * * *"
|
|
12
|
+
timezone: "UTC"
|
|
13
|
+
runner: shell
|
|
14
|
+
command: >
|
|
15
|
+
domain={{domain}}; state={{state_file}};
|
|
16
|
+
current=$(curl -s "https://crt.sh/?q=${domain}&output=json" | grep -o '"id":[0-9]*' | sort -u);
|
|
17
|
+
if [ ! -f "$state" ]; then echo "$current" > "$state"; echo "no baseline found — saved current cert IDs as the baseline ($(echo "$current" | wc -l | tr -d ' ') certs)"; exit 0; fi;
|
|
18
|
+
new=$(comm -13 <(sort "$state") <(echo "$current" | sort));
|
|
19
|
+
if [ -n "$new" ]; then echo "NEW CERT(S) issued for $domain since last check:"; echo "$new"; echo "$current" > "$state";
|
|
20
|
+
else echo "OK: no new certs for $domain since last check"; fi
|
|
21
|
+
variables:
|
|
22
|
+
domain:
|
|
23
|
+
default: "example.com"
|
|
24
|
+
description: Domain to watch in Certificate Transparency logs.
|
|
25
|
+
state_file:
|
|
26
|
+
default: "./.ct-watch-state"
|
|
27
|
+
description: File this job uses to remember which cert IDs it's already seen.
|
|
28
|
+
compatible_agents: [generic, claude, codex]
|
|
29
|
+
notes: >
|
|
30
|
+
Zero-token. Uses the public crt.sh API (rate limits may apply).
|
|
31
|
+
Requires bash (process substitution).
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
id: firewall-rule-diff
|
|
2
|
+
version: 1
|
|
3
|
+
name: Firewall Rule Diff
|
|
4
|
+
description: >
|
|
5
|
+
Diffs your current firewall rules against a saved baseline and flags
|
|
6
|
+
any drift. Use this if a firewall rule has ever changed without
|
|
7
|
+
anyone remembering who did it or why.
|
|
8
|
+
category: security
|
|
9
|
+
tags: [security, firewall, drift]
|
|
10
|
+
schedule: "0 6 * * *"
|
|
11
|
+
timezone: "UTC"
|
|
12
|
+
runner: shell
|
|
13
|
+
command: >
|
|
14
|
+
baseline={{baseline_path}};
|
|
15
|
+
if command -v ufw >/dev/null 2>&1; then current=$(sudo ufw status verbose 2>/dev/null);
|
|
16
|
+
elif command -v iptables >/dev/null 2>&1; then current=$(sudo iptables -S 2>/dev/null);
|
|
17
|
+
else echo "ERROR: no supported firewall tool found (ufw/iptables)"; exit 1; fi;
|
|
18
|
+
if [ ! -f "$baseline" ]; then echo "$current" > "$baseline"; echo "no baseline found — saved current rules as the new baseline"; exit 0; fi;
|
|
19
|
+
if diff -q <(echo "$current") "$baseline" >/dev/null 2>&1; then echo "OK: firewall rules match baseline";
|
|
20
|
+
else echo "DRIFT: firewall rules differ from baseline:"; diff <(echo "$current") "$baseline"; exit 1; fi
|
|
21
|
+
variables:
|
|
22
|
+
baseline_path:
|
|
23
|
+
default: "./firewall-baseline.txt"
|
|
24
|
+
description: File storing the known-good firewall rule snapshot.
|
|
25
|
+
compatible_agents: [generic, claude, codex]
|
|
26
|
+
notes: >
|
|
27
|
+
Requires sudo access to read ufw/iptables rules (configure passwordless
|
|
28
|
+
sudo for this specific read-only command if running unattended). First
|
|
29
|
+
run saves the baseline; later runs diff against it. Requires bash
|
|
30
|
+
(process substitution).
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
id: sudo-usage-audit
|
|
2
|
+
version: 1
|
|
3
|
+
name: Sudo Usage Audit
|
|
4
|
+
description: >
|
|
5
|
+
Reports new sudo commands run since the last check. Use this if you
|
|
6
|
+
want to notice unexpected privilege escalation on a shared or
|
|
7
|
+
internet-facing server.
|
|
8
|
+
category: security
|
|
9
|
+
tags: [security, sudo, audit]
|
|
10
|
+
schedule: "0 * * * *"
|
|
11
|
+
timezone: "UTC"
|
|
12
|
+
runner: shell
|
|
13
|
+
command: >
|
|
14
|
+
log={{auth_log_path}}; state={{state_file}};
|
|
15
|
+
[ -f "$log" ] || { echo "ERROR: $log not found"; exit 1; };
|
|
16
|
+
total=$(grep -c "sudo:.*COMMAND=" "$log");
|
|
17
|
+
last=$(cat "$state" 2>/dev/null || echo 0);
|
|
18
|
+
new=$(( total - last ));
|
|
19
|
+
[ "$new" -lt 0 ] && new=0;
|
|
20
|
+
echo "$total" > "$state";
|
|
21
|
+
if [ "$new" -gt 0 ]; then
|
|
22
|
+
echo "New sudo commands since last check ($new):";
|
|
23
|
+
grep "sudo:.*COMMAND=" "$log" | tail -n "$new";
|
|
24
|
+
else echo "OK: no new sudo usage since last check"; fi
|
|
25
|
+
variables:
|
|
26
|
+
auth_log_path:
|
|
27
|
+
default: "/var/log/auth.log"
|
|
28
|
+
description: Path to the auth log (Linux-style).
|
|
29
|
+
state_file:
|
|
30
|
+
default: "./.sudo-audit-state"
|
|
31
|
+
description: File this job uses to remember the last count seen, so it only reports new entries.
|
|
32
|
+
compatible_agents: [generic, claude, codex]
|
|
33
|
+
notes: >
|
|
34
|
+
Linux-oriented (/var/log/auth.log with sudo entries). On macOS use
|
|
35
|
+
`log show --predicate 'process == "sudo"'` instead and adapt the command.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
id: 1on1-prep-reminder
|
|
2
|
+
version: 1
|
|
3
|
+
name: 1:1 Prep Reminder
|
|
4
|
+
description: >
|
|
5
|
+
Nudges you to prep talking points before a recurring 1:1 and shows
|
|
6
|
+
your last notes. Use this if you've ever walked into a 1:1 with
|
|
7
|
+
nothing prepared and just winged it.
|
|
8
|
+
category: team
|
|
9
|
+
tags: [1on1, meetings, team]
|
|
10
|
+
schedule: "0 9 * * 3"
|
|
11
|
+
timezone: "America/Los_Angeles"
|
|
12
|
+
runner: shell
|
|
13
|
+
command: >
|
|
14
|
+
echo "1:1 with {{person_name}} coming up. Jot down talking points.";
|
|
15
|
+
if [ -f "{{notes_file}}" ]; then echo "--- last notes ---"; tail -n 10 "{{notes_file}}"; fi
|
|
16
|
+
variables:
|
|
17
|
+
person_name:
|
|
18
|
+
default: "your manager"
|
|
19
|
+
description: Who the 1:1 is with.
|
|
20
|
+
notes_file:
|
|
21
|
+
default: "./1on1-notes.txt"
|
|
22
|
+
description: Plain text file you append notes/action items to after each 1:1.
|
|
23
|
+
compatible_agents: [generic, claude, codex]
|
|
24
|
+
notes: >
|
|
25
|
+
Zero-token. Adjust the schedule to match your actual 1:1 day/time —
|
|
26
|
+
the default (Wednesday morning) is just a placeholder.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
id: pto-balance-check
|
|
2
|
+
version: 1
|
|
3
|
+
name: PTO Balance Check
|
|
4
|
+
description: >
|
|
5
|
+
Warns you before unused PTO expires or resets. Use this if you've
|
|
6
|
+
ever lost vacation days because you forgot they don't roll over.
|
|
7
|
+
category: team
|
|
8
|
+
tags: [pto, vacation, team]
|
|
9
|
+
schedule: "0 9 1 * *"
|
|
10
|
+
timezone: "America/Los_Angeles"
|
|
11
|
+
runner: shell
|
|
12
|
+
command: >
|
|
13
|
+
today_epoch=$(date +%s);
|
|
14
|
+
expiry_epoch=$(date -j -f %Y-%m-%d "{{expiry_date}}" +%s 2>/dev/null || date -d "{{expiry_date}}" +%s);
|
|
15
|
+
days_left=$(( (expiry_epoch-today_epoch)/86400 ));
|
|
16
|
+
if [ "$days_left" -lt 0 ]; then echo "note: expiry date has passed — update expiry_date for the next period.";
|
|
17
|
+
elif [ "$days_left" -le {{warn_days_before_expiry}} ] && [ {{pto_balance_hours}} -gt 0 ]; then
|
|
18
|
+
echo "REMINDER: {{pto_balance_hours}}h PTO expires in $days_left day(s) (on {{expiry_date}}) — use it or lose it.";
|
|
19
|
+
else echo "OK: {{pto_balance_hours}}h PTO, $days_left day(s) until expiry."; fi
|
|
20
|
+
variables:
|
|
21
|
+
pto_balance_hours:
|
|
22
|
+
default: 40
|
|
23
|
+
description: Your current unused PTO balance, in hours — update this yourself as it changes.
|
|
24
|
+
expiry_date:
|
|
25
|
+
default: "2026-12-31"
|
|
26
|
+
description: Date (YYYY-MM-DD) this PTO expires or resets.
|
|
27
|
+
warn_days_before_expiry:
|
|
28
|
+
default: 30
|
|
29
|
+
description: Start warning this many days before expiry.
|
|
30
|
+
compatible_agents: [generic, claude, codex]
|
|
31
|
+
notes: >
|
|
32
|
+
Zero-token. You maintain pto_balance_hours and expiry_date yourself —
|
|
33
|
+
this doesn't pull from any HR system.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
id: flight-checkin-reminder
|
|
2
|
+
version: 1
|
|
3
|
+
name: Flight Check-in Reminder
|
|
4
|
+
description: >
|
|
5
|
+
Reminds you when online check-in opens for an upcoming flight. Use
|
|
6
|
+
this if you've ever missed the good seats because check-in opened
|
|
7
|
+
while you were asleep.
|
|
8
|
+
category: travel
|
|
9
|
+
tags: [travel, flight, reminder]
|
|
10
|
+
schedule: "0 * * * *"
|
|
11
|
+
timezone: "UTC"
|
|
12
|
+
runner: shell
|
|
13
|
+
command: >
|
|
14
|
+
flight="{{flight_datetime}}"; hours_before={{checkin_hours_before}};
|
|
15
|
+
flight_epoch=$(date -j -f "%Y-%m-%d %H:%M" "$flight" +%s 2>/dev/null || date -d "$flight" +%s);
|
|
16
|
+
now_epoch=$(date +%s);
|
|
17
|
+
hours_left=$(( (flight_epoch-now_epoch)/3600 ));
|
|
18
|
+
if [ "$hours_left" -le 0 ]; then echo "note: flight time has passed — update flight_datetime for your next trip.";
|
|
19
|
+
elif [ "$hours_left" -le "$hours_before" ]; then echo "REMINDER: check in for your flight — departs in ${hours_left}h ($flight).";
|
|
20
|
+
else echo "OK: ${hours_left}h until flight ($flight), check-in opens around ${hours_before}h before departure."; fi
|
|
21
|
+
variables:
|
|
22
|
+
flight_datetime:
|
|
23
|
+
default: "2026-12-31 08:00"
|
|
24
|
+
description: Flight departure date and time ("YYYY-MM-DD HH:MM", local to the schedule's timezone).
|
|
25
|
+
checkin_hours_before:
|
|
26
|
+
default: 24
|
|
27
|
+
description: How many hours before departure check-in typically opens for your airline.
|
|
28
|
+
compatible_agents: [generic, claude, codex]
|
|
29
|
+
notes: >
|
|
30
|
+
Zero-token. Runs hourly since it's a time-sensitive window — update
|
|
31
|
+
flight_datetime for each new trip.
|