@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.
@@ -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.