@wonsukchoi/crondex 0.21.0 → 0.22.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 +16 -30
- package/catalog.json +2294 -26
- package/jobs/ecommerce/affiliate-commission-payout-check.yaml +38 -0
- package/jobs/ecommerce/back-in-stock-notification-backlog-check.yaml +30 -0
- package/jobs/ecommerce/bundle-component-stock-mismatch-check.yaml +37 -0
- package/jobs/ecommerce/chargeback-fraud-risk-order-review.yaml +43 -0
- package/jobs/ecommerce/competitor-price-watch.yaml +60 -0
- package/jobs/ecommerce/economic-nexus-threshold-check.yaml +43 -0
- package/jobs/ecommerce/failed-payment-dunning-check.yaml +35 -0
- package/jobs/ecommerce/marketplace-listing-sync-drift-check.yaml +48 -0
- package/jobs/ecommerce/product-feed-health-check.yaml +35 -0
- package/jobs/ecommerce/purchase-order-overdue-check.yaml +32 -0
- package/jobs/ecommerce/storefront-ssl-domain-expiry-check.yaml +46 -0
- package/jobs/ecommerce/vip-tier-reclassification-check.yaml +55 -0
- package/jobs/ecommerce/wishlist-abandonment-check.yaml +37 -0
- package/jobs/finance/accounts-payable-aging-check.yaml +40 -0
- package/jobs/finance/bank-statement-reconciliation-check.yaml +40 -0
- package/jobs/finance/budget-vs-actual-variance-report.yaml +38 -0
- package/jobs/finance/contractor-1099-threshold-tracker.yaml +43 -0
- package/jobs/finance/credit-utilization-watch.yaml +40 -0
- package/jobs/finance/duplicate-payment-detection.yaml +43 -0
- package/jobs/finance/expense-report-compliance-check.yaml +46 -0
- package/jobs/finance/late-fee-interest-risk-check.yaml +43 -0
- package/jobs/finance/loan-covenant-compliance-check.yaml +37 -0
- package/jobs/finance/month-end-close-checklist-tracker.yaml +39 -0
- package/jobs/finance/multi-account-cash-position-rollup.yaml +45 -0
- package/jobs/finance/petty-cash-float-reconciliation.yaml +43 -0
- package/jobs/finance/quarterly-estimated-tax-calculator.yaml +66 -0
- package/jobs/finance/vendor-early-pay-discount-tracker.yaml +45 -0
- package/jobs/healthcare/appointment-slot-utilization-check.yaml +56 -0
- package/jobs/healthcare/claims-denial-resubmission-check.yaml +43 -0
- package/jobs/healthcare/clinical-supply-low-stock-check.yaml +30 -0
- package/jobs/healthcare/controlled-substance-inventory-reconciliation.yaml +42 -0
- package/jobs/healthcare/hipaa-access-log-audit.yaml +74 -0
- package/jobs/healthcare/patient-balance-collections-aging-check.yaml +41 -0
- package/jobs/healthcare/patient-immunization-schedule-check.yaml +41 -0
- package/jobs/healthcare/patient-portal-message-backlog-check.yaml +39 -0
- package/jobs/healthcare/patient-satisfaction-survey-tracking.yaml +59 -0
- package/jobs/healthcare/prescription-refill-request-backlog-check.yaml +38 -0
- package/jobs/healthcare/prior-authorization-expiry-check.yaml +53 -0
- package/jobs/healthcare/staff-cme-credit-tracking.yaml +41 -0
- package/jobs/healthcare/telehealth-session-issue-check.yaml +51 -0
- package/jobs/hr/aca-fte-threshold-monitor.yaml +44 -0
- package/jobs/hr/cobra-notification-deadline-tracker.yaml +47 -0
- package/jobs/hr/compliance-training-completion-check.yaml +41 -0
- package/jobs/hr/eeo1-filing-deadline-reminder.yaml +37 -0
- package/jobs/hr/handbook-acknowledgment-tracking.yaml +34 -0
- package/jobs/hr/headcount-budget-variance-check.yaml +37 -0
- package/jobs/hr/leave-of-absence-return-tracker.yaml +42 -0
- package/jobs/hr/org-chart-manager-drift-check.yaml +40 -0
- package/jobs/hr/pay-equity-band-outlier-check.yaml +58 -0
- package/jobs/hr/pto-year-end-use-it-or-lose-it-check.yaml +49 -0
- package/jobs/hr/retirement-plan-enrollment-deadline-check.yaml +40 -0
- package/jobs/hr/workers-comp-claim-status-check.yaml +42 -0
- package/jobs/legal/conflict-of-interest-check-tracker.yaml +38 -0
- package/jobs/legal/corporate-minute-book-completeness-check.yaml +31 -0
- package/jobs/legal/data-privacy-request-deadline-tracker.yaml +61 -0
- package/jobs/legal/entity-authority-document-expiry-check.yaml +37 -0
- package/jobs/legal/legal-document-retention-purge-review.yaml +39 -0
- package/jobs/legal/litigation-hold-acknowledgment-tracker.yaml +40 -0
- package/jobs/legal/non-compete-expiry-tracker.yaml +37 -0
- package/jobs/legal/outside-counsel-invoice-budget-check.yaml +37 -0
- package/jobs/legal/settlement-payment-schedule-tracker.yaml +34 -0
- package/jobs/legal/timekeeper-billable-hours-compliance-check.yaml +39 -0
- package/jobs/legal/trademark-infringement-watch.yaml +43 -0
- package/jobs/legal/vendor-coi-expiry-tracker.yaml +37 -0
- package/jobs/realestate/capital-reserve-fund-threshold-check.yaml +32 -0
- package/jobs/realestate/eviction-notice-deadline-tracker.yaml +37 -0
- package/jobs/realestate/landlord-insurance-claim-status-check.yaml +35 -0
- package/jobs/realestate/lease-renewal-offer-window-check.yaml +35 -0
- package/jobs/realestate/maintenance-request-sla-check.yaml +39 -0
- package/jobs/realestate/move-in-move-out-inspection-tracker.yaml +35 -0
- package/jobs/realestate/rent-increase-notice-deadline-check.yaml +54 -0
- package/jobs/realestate/rent-roll-vacancy-loss-report.yaml +32 -0
- package/jobs/realestate/rental-license-renewal-check.yaml +35 -0
- package/jobs/realestate/security-deposit-return-deadline-check.yaml +38 -0
- package/jobs/realestate/tenant-application-review-backlog-check.yaml +35 -0
- package/jobs/realestate/tenant-renters-insurance-compliance-check.yaml +35 -0
- package/jobs/realestate/utility-billback-reconciliation-check.yaml +41 -0
- package/jobs/sales/champion-departure-watch.yaml +44 -0
- package/jobs/sales/closed-lost-reason-audit.yaml +42 -0
- package/jobs/sales/commission-payout-tracker.yaml +32 -0
- package/jobs/sales/contract-renewal-opportunity-tracker.yaml +28 -0
- package/jobs/sales/discount-approval-pending-check.yaml +31 -0
- package/jobs/sales/forecast-submission-compliance-check.yaml +42 -0
- package/jobs/sales/multi-year-renewal-escalation-tracker.yaml +31 -0
- package/jobs/sales/pipeline-hygiene-audit.yaml +26 -0
- package/jobs/sales/poc-trial-conversion-tracker.yaml +29 -0
- package/jobs/sales/referral-followup-tracker.yaml +40 -0
- package/jobs/sales/territory-coverage-gap-check.yaml +43 -0
- package/lib/duplicates-allowlist.js +5 -0
- package/package.json +2 -2
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
id: affiliate-commission-payout-check
|
|
2
|
+
version: 1
|
|
3
|
+
name: Affiliate Commission Payout Check
|
|
4
|
+
description: >
|
|
5
|
+
Checks commissions owed to affiliates who drive sales to your store
|
|
6
|
+
against your payout schedule and flags anything overdue and still
|
|
7
|
+
unpaid. Use this if an affiliate has ever had to chase you for a
|
|
8
|
+
commission payment because nobody was tracking payout due dates on
|
|
9
|
+
your side.
|
|
10
|
+
category: ecommerce
|
|
11
|
+
tags: [ecommerce, affiliates, commissions, payouts, finance]
|
|
12
|
+
schedule: "0 9 * * 1"
|
|
13
|
+
timezone: "UTC"
|
|
14
|
+
runner: shell
|
|
15
|
+
command: >
|
|
16
|
+
today=$(date +%s);
|
|
17
|
+
awk -F',' -v today="$today" '
|
|
18
|
+
NR==1 {next}
|
|
19
|
+
$4 == "unpaid" {
|
|
20
|
+
cmd = "date -d \"" $3 "\" +%s 2>/dev/null || date -j -f %Y-%m-%d \"" $3 "\" +%s 2>/dev/null";
|
|
21
|
+
cmd | getline due_epoch; close(cmd);
|
|
22
|
+
if (today > due_epoch) {
|
|
23
|
+
overdue_days = (today - due_epoch) / 86400;
|
|
24
|
+
printf "OVERDUE PAYOUT: %s owed $%s — due %s (%d days late)\n", $1, $2, $3, overdue_days;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
' "{{affiliate_commissions_csv_path}}"
|
|
28
|
+
variables:
|
|
29
|
+
affiliate_commissions_csv_path:
|
|
30
|
+
default: "./affiliate-commissions.csv"
|
|
31
|
+
description: "Path to a CSV with columns: affiliate_name,commission_due_usd,due_date (YYYY-MM-DD),status (unpaid/paid)."
|
|
32
|
+
compatible_agents: [generic, claude, codex]
|
|
33
|
+
notes: >
|
|
34
|
+
This is the merchant's side of paying affiliates who sell for the
|
|
35
|
+
store — the reverse direction of `brand-deal-payment-followup-check` in
|
|
36
|
+
the creator category, which tracks a creator waiting to be paid by a
|
|
37
|
+
sponsor. Also distinct from `affiliate-link-expiry-check` in creator,
|
|
38
|
+
which tracks a creator's own link/code expiry, not commission payouts.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
id: back-in-stock-notification-backlog-check
|
|
2
|
+
version: 1
|
|
3
|
+
name: Back-in-Stock Notification Backlog Check
|
|
4
|
+
description: >
|
|
5
|
+
Checks products that customers asked to be notified about against
|
|
6
|
+
current stock levels, and flags any that are back in stock with a
|
|
7
|
+
waiting list that never got notified. Use this if an item has ever
|
|
8
|
+
restocked while a list of interested customers sat unnotified until
|
|
9
|
+
the item sold out again, missing the sale entirely.
|
|
10
|
+
category: ecommerce
|
|
11
|
+
tags: [ecommerce, back-in-stock, notifications, inventory]
|
|
12
|
+
schedule: "0 */3 * * *"
|
|
13
|
+
timezone: "UTC"
|
|
14
|
+
runner: shell
|
|
15
|
+
command: >
|
|
16
|
+
awk -F',' '
|
|
17
|
+
NR==1 {next}
|
|
18
|
+
{
|
|
19
|
+
sku=$1; current_stock=$2; waitlist_count=$3; notified=$4;
|
|
20
|
+
if (current_stock+0 > 0 && waitlist_count+0 > 0 && notified == "no") {
|
|
21
|
+
printf "NOTIFY BACKLOG: %s — %d units in stock, %d customers waiting, not yet notified\n", sku, current_stock, waitlist_count;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
' "{{waitlist_csv_path}}"
|
|
25
|
+
variables:
|
|
26
|
+
waitlist_csv_path:
|
|
27
|
+
default: "./back-in-stock-waitlist.csv"
|
|
28
|
+
description: "Path to a CSV with columns: sku,current_stock,waitlist_count,notified (yes/no) — one row per SKU with an active back-in-stock waitlist."
|
|
29
|
+
compatible_agents: [generic, claude, codex]
|
|
30
|
+
notes: Mark a SKU "notified" once your ESP/app actually sends the alert, so this only ever flags a genuine backlog rather than re-flagging sent notifications every run.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
id: bundle-component-stock-mismatch-check
|
|
2
|
+
version: 1
|
|
3
|
+
name: Bundle Component Stock Mismatch Check
|
|
4
|
+
description: >
|
|
5
|
+
Checks each product bundle/kit against the stock of its individual
|
|
6
|
+
components and flags any bundle still marked in-stock while one of its
|
|
7
|
+
components is actually out. Use this if a bundle has ever sold through
|
|
8
|
+
checkout only for fulfillment to discover one piece of it was
|
|
9
|
+
unavailable, because the bundle's own stock flag wasn't tied to its
|
|
10
|
+
components.
|
|
11
|
+
category: ecommerce
|
|
12
|
+
tags: [ecommerce, bundles, inventory, kitting]
|
|
13
|
+
schedule: "0 6 * * *"
|
|
14
|
+
timezone: "UTC"
|
|
15
|
+
runner: shell
|
|
16
|
+
command: >
|
|
17
|
+
awk -F',' '
|
|
18
|
+
NR==1 {next}
|
|
19
|
+
{
|
|
20
|
+
bundle=$1; component_stock=$3; listed_status=$4;
|
|
21
|
+
if (component_stock+0 <= 0) out_of_stock_component[bundle] = out_of_stock_component[bundle] " " $2;
|
|
22
|
+
bundle_status[bundle] = listed_status;
|
|
23
|
+
}
|
|
24
|
+
END {
|
|
25
|
+
for (b in bundle_status) {
|
|
26
|
+
if (bundle_status[b] == "in-stock" && (b in out_of_stock_component)) {
|
|
27
|
+
printf "MISMATCH: bundle %s is listed in-stock but missing component(s):%s\n", b, out_of_stock_component[b];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
' "{{bundle_components_csv_path}}"
|
|
32
|
+
variables:
|
|
33
|
+
bundle_components_csv_path:
|
|
34
|
+
default: "./bundle-components.csv"
|
|
35
|
+
description: "Path to a CSV with columns: bundle_sku,component_sku,component_stock,bundle_listed_status (in-stock/out-of-stock) — one row per component of each bundle."
|
|
36
|
+
compatible_agents: [generic, claude, codex]
|
|
37
|
+
notes: Distinct from `low-stock-reorder-alert`, which tracks a single SKU's own stock velocity — this checks whether a bundle's listed availability is actually consistent with what it's made of.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
id: chargeback-fraud-risk-order-review
|
|
2
|
+
version: 1
|
|
3
|
+
name: Chargeback Fraud Risk Order Review
|
|
4
|
+
description: >
|
|
5
|
+
Scores new orders against common fraud signals — billing/shipping
|
|
6
|
+
country mismatch, high order value from a first-time customer, and
|
|
7
|
+
rush shipping on an unverified address — and flags the risky ones
|
|
8
|
+
before they ship. Use this if a chargeback has ever landed on an order
|
|
9
|
+
that, in hindsight, had obvious red flags nobody checked before
|
|
10
|
+
fulfillment.
|
|
11
|
+
category: ecommerce
|
|
12
|
+
tags: [ecommerce, fraud, chargebacks, risk, orders]
|
|
13
|
+
schedule: "0 * * * *"
|
|
14
|
+
timezone: "UTC"
|
|
15
|
+
runner: shell
|
|
16
|
+
command: >
|
|
17
|
+
awk -F',' -v minval="{{high_value_threshold}}" '
|
|
18
|
+
NR==1 {next}
|
|
19
|
+
{
|
|
20
|
+
order_id=$1; billing_country=$2; shipping_country=$3;
|
|
21
|
+
value=$4; is_new_customer=$5; shipping_method=$6;
|
|
22
|
+
score=0; reasons="";
|
|
23
|
+
if (billing_country != shipping_country) { score++; reasons = reasons "billing/shipping country mismatch; "; }
|
|
24
|
+
if (value+0 >= minval) { score++; reasons = reasons "high order value; "; }
|
|
25
|
+
if (is_new_customer == "yes") { score++; reasons = reasons "first-time customer; "; }
|
|
26
|
+
if (shipping_method == "rush" || shipping_method == "expedited") { score++; reasons = reasons "rush shipping; "; }
|
|
27
|
+
if (score >= {{flag_score_threshold}}) {
|
|
28
|
+
printf "REVIEW: order %s (score %d) — %s\n", order_id, score, reasons;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
' "{{orders_csv_path}}"
|
|
32
|
+
variables:
|
|
33
|
+
orders_csv_path:
|
|
34
|
+
default: "./new-orders.csv"
|
|
35
|
+
description: "Path to a CSV with columns: order_id,billing_country,shipping_country,order_value,is_new_customer(yes/no),shipping_method."
|
|
36
|
+
high_value_threshold:
|
|
37
|
+
default: 300
|
|
38
|
+
description: Order value in your currency at or above which it counts as a fraud-risk signal.
|
|
39
|
+
flag_score_threshold:
|
|
40
|
+
default: 2
|
|
41
|
+
description: Number of matching risk signals (0-4) required before an order is flagged for manual review.
|
|
42
|
+
compatible_agents: [generic, claude, codex]
|
|
43
|
+
notes: A flag is a prompt for manual review before shipping, not proof of fraud — legitimate customers trigger these signals too (gifts, travel, new-to-you shoppers). Distinct from `return-fraud-pattern-check` in the retail category, which looks at return abuse after the sale, not pre-fulfillment order risk.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
id: competitor-price-watch
|
|
2
|
+
version: 1
|
|
3
|
+
name: Competitor Price Watch
|
|
4
|
+
description: >
|
|
5
|
+
Fetches a competitor's product page for each SKU you're tracking, pulls
|
|
6
|
+
out the price, and flags any SKU where their price has moved enough to
|
|
7
|
+
matter relative to yours. Use this if you've ever found out you were
|
|
8
|
+
underpricing (or getting undercut on) a product only because a customer
|
|
9
|
+
mentioned it.
|
|
10
|
+
category: ecommerce
|
|
11
|
+
tags: [ecommerce, pricing, competitor, monitoring]
|
|
12
|
+
schedule: "0 6 * * *"
|
|
13
|
+
timezone: "UTC"
|
|
14
|
+
runner: hybrid
|
|
15
|
+
command: >
|
|
16
|
+
while IFS=',' read -r sku your_price url; do
|
|
17
|
+
[ "$sku" = "sku" ] && continue;
|
|
18
|
+
[ -z "$url" ] && continue;
|
|
19
|
+
page=$(curl -s -A "Mozilla/5.0" --max-time {{timeout_seconds}} "$url");
|
|
20
|
+
comp_price=$(echo "$page" | grep -oE "{{price_regex}}" | head -n1 | grep -oE "[0-9]+\.[0-9]{2}");
|
|
21
|
+
if [ -z "$comp_price" ]; then
|
|
22
|
+
echo "UNPARSED: $sku — could not extract a price from $url";
|
|
23
|
+
continue;
|
|
24
|
+
fi;
|
|
25
|
+
diff=$(awk -v y="$your_price" -v c="$comp_price" 'BEGIN{d=y-c; if(d<0)d=-d; printf "%.2f", d}');
|
|
26
|
+
if awk -v d="$diff" -v t="{{diff_threshold_usd}}" 'BEGIN{exit !(d >= t)}'; then
|
|
27
|
+
echo "PRICE GAP: $sku — you: \$$your_price, competitor: \$$comp_price (diff \$$diff) at $url";
|
|
28
|
+
fi;
|
|
29
|
+
done < "{{tracked_skus_csv_path}}"
|
|
30
|
+
prompt: |
|
|
31
|
+
The script above tried to scrape a competitor price per SKU from
|
|
32
|
+
{{tracked_skus_csv_path}} using a regex and reported any it couldn't
|
|
33
|
+
parse, plus any SKU with a price gap of at least ${{diff_threshold_usd}}.
|
|
34
|
+
1. For any "UNPARSED" line, open the competitor URL yourself and find
|
|
35
|
+
the current price (the site likely renders price via JavaScript or
|
|
36
|
+
uses a layout the regex doesn't match).
|
|
37
|
+
2. For any "PRICE GAP" line, note whether the competitor is now cheaper
|
|
38
|
+
or more expensive than you, and by what percentage.
|
|
39
|
+
3. Summarize in one short list: which SKUs need a pricing decision this
|
|
40
|
+
week, ranked by gap size.
|
|
41
|
+
script_note: >
|
|
42
|
+
`command` gives you a fast, zero-token first pass using a regex against
|
|
43
|
+
raw HTML — it will miss JS-rendered prices and misses on unusual page
|
|
44
|
+
layouts. `prompt` catches what the regex missed and turns the raw diffs
|
|
45
|
+
into a prioritized, human-readable pricing summary.
|
|
46
|
+
variables:
|
|
47
|
+
tracked_skus_csv_path:
|
|
48
|
+
default: "./competitor-price-tracking.csv"
|
|
49
|
+
description: "Path to a CSV with columns: sku,your_price,competitor_product_url — one row per SKU you want to price-watch."
|
|
50
|
+
price_regex:
|
|
51
|
+
default: "\\$[0-9]+\\.[0-9]{2}"
|
|
52
|
+
description: Regex used to extract a dollar price from the competitor's raw page HTML; adjust per site if it isn't matching.
|
|
53
|
+
diff_threshold_usd:
|
|
54
|
+
default: 2.00
|
|
55
|
+
description: Minimum price difference in dollars worth flagging.
|
|
56
|
+
timeout_seconds:
|
|
57
|
+
default: 10
|
|
58
|
+
description: Seconds to wait for each competitor page before giving up.
|
|
59
|
+
compatible_agents: [claude, codex, hermes, openclaw, generic]
|
|
60
|
+
notes: Respect the target site's robots.txt/terms before scraping. Distinct from `competitor-page-diff-watch` in marketing, which diffs whole-page content/messaging — this is narrowly a per-SKU price comparison against your own price list.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
id: economic-nexus-threshold-check
|
|
2
|
+
version: 1
|
|
3
|
+
name: Economic Nexus Threshold Check
|
|
4
|
+
description: >
|
|
5
|
+
Checks your year-to-date sales revenue and transaction count per state
|
|
6
|
+
against economic nexus thresholds and flags states you're approaching
|
|
7
|
+
or have crossed. Use this if you've ever registered for sales tax in a
|
|
8
|
+
state only after crossing the threshold months earlier, because nobody
|
|
9
|
+
was tracking cumulative sales by state.
|
|
10
|
+
category: ecommerce
|
|
11
|
+
tags: [ecommerce, sales-tax, nexus, compliance, finance]
|
|
12
|
+
schedule: "0 6 1 * *"
|
|
13
|
+
timezone: "UTC"
|
|
14
|
+
runner: shell
|
|
15
|
+
command: >
|
|
16
|
+
awk -F',' -v rev_thresh="{{revenue_threshold_usd}}" -v txn_thresh="{{transaction_threshold}}" -v warn_pct="{{warn_pct}}" '
|
|
17
|
+
NR==1 {next}
|
|
18
|
+
{
|
|
19
|
+
state=$1; revenue=$2; transactions=$3;
|
|
20
|
+
rev_warn = rev_thresh * (1 - warn_pct/100);
|
|
21
|
+
txn_warn = txn_thresh * (1 - warn_pct/100);
|
|
22
|
+
if (revenue+0 >= rev_thresh || transactions+0 >= txn_thresh) {
|
|
23
|
+
printf "NEXUS CROSSED: %s — revenue $%.2f, transactions %d (already registered? verify)\n", state, revenue, transactions;
|
|
24
|
+
} else if (revenue+0 >= rev_warn || transactions+0 >= txn_warn) {
|
|
25
|
+
printf "APPROACHING NEXUS: %s — revenue $%.2f, transactions %d\n", state, revenue, transactions;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
' "{{state_sales_csv_path}}"
|
|
29
|
+
variables:
|
|
30
|
+
state_sales_csv_path:
|
|
31
|
+
default: "./state-sales-ytd.csv"
|
|
32
|
+
description: "Path to a CSV with columns: state,ytd_revenue_usd,ytd_transaction_count — one row per state you ship to."
|
|
33
|
+
revenue_threshold_usd:
|
|
34
|
+
default: 100000
|
|
35
|
+
description: "Default economic nexus revenue threshold (varies by state — check each state's actual rule; $100k/200 transactions is common but not universal)."
|
|
36
|
+
transaction_threshold:
|
|
37
|
+
default: 200
|
|
38
|
+
description: Default economic nexus transaction-count threshold.
|
|
39
|
+
warn_pct:
|
|
40
|
+
default: 20
|
|
41
|
+
description: Percent below the threshold at which a state counts as "approaching" and worth watching.
|
|
42
|
+
compatible_agents: [generic, claude, codex]
|
|
43
|
+
notes: Thresholds genuinely vary by state (some have no transaction-count prong, some use different dollar amounts) — this uses one configurable default across all states as a first-pass filter, not a substitute for checking each state's actual rule before registering or not registering.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
id: failed-payment-dunning-check
|
|
2
|
+
version: 1
|
|
3
|
+
name: Failed Payment Dunning Check
|
|
4
|
+
description: >
|
|
5
|
+
Checks recurring/subscription orders with a failed payment and flags
|
|
6
|
+
ones that have been retrying too long without success, so you can step
|
|
7
|
+
in before the customer silently churns. Use this if a subscriber has
|
|
8
|
+
ever stayed on "payment failed" for weeks with nobody following up,
|
|
9
|
+
quietly costing you recurring revenue.
|
|
10
|
+
category: ecommerce
|
|
11
|
+
tags: [ecommerce, subscriptions, payments, dunning, churn]
|
|
12
|
+
schedule: "0 9 * * *"
|
|
13
|
+
timezone: "UTC"
|
|
14
|
+
runner: shell
|
|
15
|
+
command: >
|
|
16
|
+
awk -F',' -v max_days="{{max_retry_days}}" -v max_attempts="{{max_retry_attempts}}" '
|
|
17
|
+
NR==1 {next}
|
|
18
|
+
$2 == "failed" {
|
|
19
|
+
if ($3+0 >= max_days || $4+0 >= max_attempts) {
|
|
20
|
+
printf "NEEDS ACTION: subscription %s — %d days failing, %d retry attempts\n", $1, $3, $4;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
' "{{subscriptions_csv_path}}"
|
|
24
|
+
variables:
|
|
25
|
+
subscriptions_csv_path:
|
|
26
|
+
default: "./subscriptions.csv"
|
|
27
|
+
description: "Path to a CSV with columns: subscription_id,status (failed/active),days_since_first_failure,retry_attempt_count."
|
|
28
|
+
max_retry_days:
|
|
29
|
+
default: 7
|
|
30
|
+
description: Days a subscription can sit in failed-payment status before it needs a manual touch (update card, human outreach, or cancel).
|
|
31
|
+
max_retry_attempts:
|
|
32
|
+
default: 4
|
|
33
|
+
description: Number of automatic retry attempts before it needs a manual touch instead of another silent retry.
|
|
34
|
+
compatible_agents: [generic, claude, codex]
|
|
35
|
+
notes: This flags when automatic dunning has run its course — pair with an actual outreach step (email, SMS, or account pause) since the job itself only identifies who needs it.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
id: marketplace-listing-sync-drift-check
|
|
2
|
+
version: 1
|
|
3
|
+
name: Marketplace Listing Sync Drift Check
|
|
4
|
+
description: >
|
|
5
|
+
Compares price and stock on your source-of-truth catalog against what's
|
|
6
|
+
actually live on a marketplace (Amazon, eBay, Etsy) and flags any SKU
|
|
7
|
+
that's drifted out of sync. Use this if a marketplace listing has ever
|
|
8
|
+
shown a stale price or "in stock" on an item you'd already sold out of
|
|
9
|
+
on your own store, because the sync job silently failed.
|
|
10
|
+
category: ecommerce
|
|
11
|
+
tags: [ecommerce, marketplace, sync, inventory, pricing]
|
|
12
|
+
schedule: "0 */4 * * *"
|
|
13
|
+
timezone: "UTC"
|
|
14
|
+
runner: shell
|
|
15
|
+
command: >
|
|
16
|
+
awk -F',' '
|
|
17
|
+
FNR==NR {
|
|
18
|
+
if (FNR==1) {next}
|
|
19
|
+
truth_price[$1]=$2; truth_stock[$1]=$3; next
|
|
20
|
+
}
|
|
21
|
+
{
|
|
22
|
+
if (FNR==1) {next}
|
|
23
|
+
sku=$1; mkt_price=$2; mkt_stock=$3; marketplace=$4;
|
|
24
|
+
if (sku in truth_price) {
|
|
25
|
+
price_diff = truth_price[sku] - mkt_price; if (price_diff < 0) price_diff = -price_diff;
|
|
26
|
+
if (price_diff > {{price_tolerance_usd}}) {
|
|
27
|
+
printf "PRICE DRIFT: %s on %s — source: $%.2f, listed: $%.2f\n", sku, marketplace, truth_price[sku], mkt_price;
|
|
28
|
+
}
|
|
29
|
+
if ((truth_stock[sku]+0 <= 0) != (mkt_stock+0 <= 0)) {
|
|
30
|
+
printf "STOCK DRIFT: %s on %s — source stock: %s, listed stock: %s\n", sku, marketplace, truth_stock[sku], mkt_stock;
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
printf "UNMATCHED SKU: %s on %s not found in source-of-truth catalog\n", sku, marketplace;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
' "{{source_of_truth_csv_path}}" "{{marketplace_export_csv_path}}"
|
|
37
|
+
variables:
|
|
38
|
+
source_of_truth_csv_path:
|
|
39
|
+
default: "./catalog-source-of-truth.csv"
|
|
40
|
+
description: "Path to a CSV with columns: sku,price,stock — your own store's authoritative price/stock."
|
|
41
|
+
marketplace_export_csv_path:
|
|
42
|
+
default: "./marketplace-listings.csv"
|
|
43
|
+
description: "Path to a CSV export with columns: sku,listed_price,listed_stock,marketplace — one row per live listing per marketplace."
|
|
44
|
+
price_tolerance_usd:
|
|
45
|
+
default: 1.00
|
|
46
|
+
description: Acceptable price difference in dollars between source and marketplace before flagging drift.
|
|
47
|
+
compatible_agents: [generic, claude, codex]
|
|
48
|
+
notes: Requires both exports to use the same SKU values — normalize SKU formatting on export if a marketplace mangles it (e.g. adds a prefix).
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
id: product-feed-health-check
|
|
2
|
+
version: 1
|
|
3
|
+
name: Product Feed Health Check
|
|
4
|
+
description: >
|
|
5
|
+
Scans your product catalog export for listings that are live but broken
|
|
6
|
+
in some way — missing title, missing description, missing image, a
|
|
7
|
+
zero/blank price, or marked out-of-stock while still visible to
|
|
8
|
+
shoppers. Use this if a product has ever sat on your storefront for
|
|
9
|
+
weeks with a broken image or a $0 price because nobody was checking
|
|
10
|
+
feed quality after the initial upload.
|
|
11
|
+
category: ecommerce
|
|
12
|
+
tags: [ecommerce, product-feed, seo, catalog, data-quality]
|
|
13
|
+
schedule: "0 5 * * *"
|
|
14
|
+
timezone: "UTC"
|
|
15
|
+
runner: shell
|
|
16
|
+
command: >
|
|
17
|
+
awk -F',' '
|
|
18
|
+
NR==1 {next}
|
|
19
|
+
{
|
|
20
|
+
sku=$1; title=$2; description=$3; image_url=$4; price=$5; in_stock=$6; visible=$7;
|
|
21
|
+
issues="";
|
|
22
|
+
if (title == "") issues = issues "missing title; ";
|
|
23
|
+
if (description == "") issues = issues "missing description; ";
|
|
24
|
+
if (image_url == "") issues = issues "missing image; ";
|
|
25
|
+
if (price+0 <= 0) issues = issues "zero/blank price; ";
|
|
26
|
+
if (in_stock == "false" && visible == "true") issues = issues "out-of-stock but still visible; ";
|
|
27
|
+
if (issues != "") printf "ISSUE: %s — %s\n", sku, issues;
|
|
28
|
+
}
|
|
29
|
+
' "{{product_feed_csv_path}}"
|
|
30
|
+
variables:
|
|
31
|
+
product_feed_csv_path:
|
|
32
|
+
default: "./product-feed.csv"
|
|
33
|
+
description: "Path to a CSV export with columns: sku,title,description,image_url,price,in_stock(true/false),visible(true/false)."
|
|
34
|
+
compatible_agents: [generic, claude, codex]
|
|
35
|
+
notes: Export this from whatever generates your storefront/Google Shopping feed on a schedule — the checks are only as fresh as the export. Distinct from `low-stock-reorder-alert`, which tracks stock levels, not listing data quality.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
id: purchase-order-overdue-check
|
|
2
|
+
version: 1
|
|
3
|
+
name: Purchase Order Overdue Check
|
|
4
|
+
description: >
|
|
5
|
+
Checks open purchase orders to suppliers against their expected
|
|
6
|
+
delivery date and flags anything that hasn't arrived on time. Use this
|
|
7
|
+
if a supplier has ever gone quiet on a PO and you only found out stock
|
|
8
|
+
wasn't coming when you were already out of the item.
|
|
9
|
+
category: ecommerce
|
|
10
|
+
tags: [ecommerce, purchase-orders, suppliers, inventory]
|
|
11
|
+
schedule: "0 7 * * *"
|
|
12
|
+
timezone: "UTC"
|
|
13
|
+
runner: shell
|
|
14
|
+
command: >
|
|
15
|
+
today=$(date +%s);
|
|
16
|
+
awk -F',' -v today="$today" '
|
|
17
|
+
NR==1 {next}
|
|
18
|
+
$4 == "pending" {
|
|
19
|
+
cmd = "date -d \"" $3 "\" +%s 2>/dev/null || date -j -f %Y-%m-%d \"" $3 "\" +%s 2>/dev/null";
|
|
20
|
+
cmd | getline expected_epoch; close(cmd);
|
|
21
|
+
if (today > expected_epoch) {
|
|
22
|
+
overdue_days = (today - expected_epoch) / 86400;
|
|
23
|
+
printf "OVERDUE PO: %s from %s — expected %s (%d days late)\n", $1, $2, $3, overdue_days;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
' "{{purchase_orders_csv_path}}"
|
|
27
|
+
variables:
|
|
28
|
+
purchase_orders_csv_path:
|
|
29
|
+
default: "./purchase-orders.csv"
|
|
30
|
+
description: "Path to a CSV with columns: po_id,supplier_name,expected_delivery_date (YYYY-MM-DD),status (pending/received)."
|
|
31
|
+
compatible_agents: [generic, claude, codex]
|
|
32
|
+
notes: Mark a PO "received" as soon as stock lands so this only ever flags genuinely overdue orders. Distinct from `low-stock-reorder-alert` (decides when to place an order) and `shipping-delay-check` (tracks outbound orders to customers) — this tracks inbound supplier orders after they've been placed.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
id: storefront-ssl-domain-expiry-check
|
|
2
|
+
version: 1
|
|
3
|
+
name: Storefront SSL & Domain Expiry Check
|
|
4
|
+
description: >
|
|
5
|
+
Checks your storefront's SSL certificate and domain registration expiry
|
|
6
|
+
dates and flags anything expiring soon. Use this if your store has ever
|
|
7
|
+
gone down — or thrown a scary browser security warning at checkout —
|
|
8
|
+
because an SSL cert or domain renewal quietly lapsed.
|
|
9
|
+
category: ecommerce
|
|
10
|
+
tags: [ecommerce, ssl, domain, uptime, infrastructure]
|
|
11
|
+
schedule: "0 6 * * 1"
|
|
12
|
+
timezone: "UTC"
|
|
13
|
+
runner: shell
|
|
14
|
+
command: >
|
|
15
|
+
domain="{{storefront_domain}}";
|
|
16
|
+
warn_days="{{warn_days}}";
|
|
17
|
+
cert_end=$(echo | openssl s_client -servername "$domain" -connect "$domain":443 2>/dev/null | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2);
|
|
18
|
+
if [ -n "$cert_end" ]; then
|
|
19
|
+
cert_epoch=$(date -d "$cert_end" +%s 2>/dev/null || date -j -f "%b %d %T %Y %Z" "$cert_end" +%s 2>/dev/null);
|
|
20
|
+
now_epoch=$(date +%s);
|
|
21
|
+
cert_days_left=$(( (cert_epoch - now_epoch) / 86400 ));
|
|
22
|
+
if [ "$cert_days_left" -le "$warn_days" ]; then
|
|
23
|
+
echo "SSL WARNING: cert for $domain expires in $cert_days_left days ($cert_end)";
|
|
24
|
+
fi;
|
|
25
|
+
else
|
|
26
|
+
echo "ERROR: could not read SSL cert for $domain";
|
|
27
|
+
fi;
|
|
28
|
+
domain_end=$(whois "$domain" 2>/dev/null | grep -iE "registry expiry|expiration date" | head -n1 | sed -E 's/.*: *//');
|
|
29
|
+
if [ -n "$domain_end" ]; then
|
|
30
|
+
dom_epoch=$(date -d "$domain_end" +%s 2>/dev/null);
|
|
31
|
+
if [ -n "$dom_epoch" ]; then
|
|
32
|
+
dom_days_left=$(( (dom_epoch - now_epoch) / 86400 ));
|
|
33
|
+
if [ "$dom_days_left" -le "$warn_days" ]; then
|
|
34
|
+
echo "DOMAIN WARNING: $domain registration expires in $dom_days_left days ($domain_end)";
|
|
35
|
+
fi;
|
|
36
|
+
fi;
|
|
37
|
+
fi
|
|
38
|
+
variables:
|
|
39
|
+
storefront_domain:
|
|
40
|
+
default: "example.com"
|
|
41
|
+
description: The domain your storefront is served from (no protocol/path).
|
|
42
|
+
warn_days:
|
|
43
|
+
default: 21
|
|
44
|
+
description: Days before SSL cert or domain expiry to start warning.
|
|
45
|
+
compatible_agents: [generic, claude, codex]
|
|
46
|
+
notes: Requires `openssl` and `whois` on the runner; whois output format varies by registrar/TLD, so treat a missing DOMAIN WARNING line as inconclusive rather than "all clear" and spot-check manually a few times after setup.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
id: vip-tier-reclassification-check
|
|
2
|
+
version: 1
|
|
3
|
+
name: VIP Tier Reclassification Check
|
|
4
|
+
description: >
|
|
5
|
+
Checks each customer's year-to-date spend against your VIP tier
|
|
6
|
+
thresholds and flags anyone due to move up or down a tier, drafting a
|
|
7
|
+
short outreach note for new upgrades. Use this if a top customer has
|
|
8
|
+
ever crossed your VIP spend threshold months ago and never got the
|
|
9
|
+
perks (or the acknowledgment) because nobody was tracking tier
|
|
10
|
+
crossings.
|
|
11
|
+
category: ecommerce
|
|
12
|
+
tags: [ecommerce, vip, customers, ltv, segmentation]
|
|
13
|
+
schedule: "0 8 1 * *"
|
|
14
|
+
timezone: "UTC"
|
|
15
|
+
runner: hybrid
|
|
16
|
+
command: >
|
|
17
|
+
awk -F',' -v gold="{{gold_threshold_usd}}" -v platinum="{{platinum_threshold_usd}}" '
|
|
18
|
+
NR==1 {next}
|
|
19
|
+
{
|
|
20
|
+
customer=$1; spend=$2; current_tier=$3;
|
|
21
|
+
new_tier = "standard";
|
|
22
|
+
if (spend+0 >= platinum) new_tier = "platinum";
|
|
23
|
+
else if (spend+0 >= gold) new_tier = "gold";
|
|
24
|
+
if (new_tier != current_tier) {
|
|
25
|
+
printf "TIER CHANGE: %s — %s -> %s (YTD spend $%.2f)\n", customer, current_tier, new_tier, spend;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
' "{{customers_csv_path}}"
|
|
29
|
+
prompt: |
|
|
30
|
+
The script above compared each customer's YTD spend to the VIP tier
|
|
31
|
+
thresholds and listed everyone whose tier should change.
|
|
32
|
+
1. For each upgrade (moving to a higher tier), draft a short, warm
|
|
33
|
+
note acknowledging the milestone and naming the specific new perk
|
|
34
|
+
they've unlocked.
|
|
35
|
+
2. For each downgrade, just list it plainly — no outreach needed, this
|
|
36
|
+
is usually just for internal tracking/perk removal timing.
|
|
37
|
+
3. Group the final output into "Upgrades (draft ready)" and
|
|
38
|
+
"Downgrades (no action needed)".
|
|
39
|
+
script_note: >
|
|
40
|
+
`command` gives you the raw list of who crossed a threshold in either
|
|
41
|
+
direction, at zero token cost. `prompt` adds the human touch: a
|
|
42
|
+
genuine, specific congratulations note for upgrades instead of a
|
|
43
|
+
generic template, which is the part worth spending tokens on.
|
|
44
|
+
variables:
|
|
45
|
+
customers_csv_path:
|
|
46
|
+
default: "./customer-ytd-spend.csv"
|
|
47
|
+
description: "Path to a CSV with columns: customer_name,ytd_spend_usd,current_tier (standard/gold/platinum)."
|
|
48
|
+
gold_threshold_usd:
|
|
49
|
+
default: 500
|
|
50
|
+
description: YTD spend at or above which a customer qualifies for gold tier.
|
|
51
|
+
platinum_threshold_usd:
|
|
52
|
+
default: 2000
|
|
53
|
+
description: YTD spend at or above which a customer qualifies for platinum tier.
|
|
54
|
+
compatible_agents: [claude, codex, hermes, openclaw, generic]
|
|
55
|
+
notes: Distinct from `loyalty-points-expiry-reminder` in retail, which tracks points balances expiring — this tracks total spend against tier thresholds, independent of any points program.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
id: wishlist-abandonment-check
|
|
2
|
+
version: 1
|
|
3
|
+
name: Wishlist Abandonment Check
|
|
4
|
+
description: >
|
|
5
|
+
Checks customer wishlists for items that have sat untouched for a while
|
|
6
|
+
and drafts a nudge email when there's a real reason to reach out — a
|
|
7
|
+
price drop or the item is back in stock — instead of a generic
|
|
8
|
+
"you still want this?" reminder. Use this if you've ever had a wishlist
|
|
9
|
+
feature that quietly collects intent and never converts any of it back
|
|
10
|
+
into a sale.
|
|
11
|
+
category: ecommerce
|
|
12
|
+
tags: [ecommerce, wishlist, recovery, conversion, sales]
|
|
13
|
+
schedule: "0 11 * * 1"
|
|
14
|
+
timezone: "UTC"
|
|
15
|
+
runner: agent-prompt
|
|
16
|
+
prompt: |
|
|
17
|
+
Check {{store_platform}} for wishlist items added at least
|
|
18
|
+
{{min_days_on_wishlist}} days ago that are still in the customer's
|
|
19
|
+
wishlist (not purchased).
|
|
20
|
+
1. For each, check whether the item's price has dropped or it went
|
|
21
|
+
from out-of-stock to in-stock since it was wishlisted.
|
|
22
|
+
2. Only draft an outreach email for items with one of those real
|
|
23
|
+
triggers — skip items where nothing has changed, since a nudge with
|
|
24
|
+
no news performs worse than no email at all.
|
|
25
|
+
3. Draft a short, specific email per triggered item: name the item, the
|
|
26
|
+
specific change (price/stock), and a clear link back to it.
|
|
27
|
+
4. Report how many wishlist items were checked, how many had a real
|
|
28
|
+
trigger, and how many drafts were produced.
|
|
29
|
+
variables:
|
|
30
|
+
store_platform:
|
|
31
|
+
default: "your storefront platform"
|
|
32
|
+
description: Name of the e-commerce platform with wishlist data (e.g. "Shopify", "WooCommerce").
|
|
33
|
+
min_days_on_wishlist:
|
|
34
|
+
default: 14
|
|
35
|
+
description: Minimum days an item must have sat on a wishlist before it's eligible for a re-engagement check.
|
|
36
|
+
compatible_agents: [claude, codex, hermes, openclaw, generic]
|
|
37
|
+
notes: Draft-only — review before sending, and confirm your platform's marketing-consent rules cover wishlist-triggered email. Distinct from `abandoned-cart-recovery-check`, which targets items already added to an active cart; this targets earlier-funnel intent that never reached checkout, and only fires on a real trigger rather than time elapsed alone.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
id: accounts-payable-aging-check
|
|
2
|
+
version: 1
|
|
3
|
+
name: Accounts Payable Aging Check
|
|
4
|
+
description: >
|
|
5
|
+
Buckets bills you owe (not invoices you've sent) into aging ranges —
|
|
6
|
+
current, 30, 60, 90+ days past due — so nothing quietly slips into a
|
|
7
|
+
late-fee zone. Use this if you or your business pay vendors on terms
|
|
8
|
+
and want a standing view of what's coming due versus already overdue.
|
|
9
|
+
category: finance
|
|
10
|
+
tags: [accounts-payable, bills, aging, finance]
|
|
11
|
+
schedule: "0 8 * * *"
|
|
12
|
+
timezone: "UTC"
|
|
13
|
+
runner: shell
|
|
14
|
+
command: >
|
|
15
|
+
file={{payables_file}};
|
|
16
|
+
[ -f "$file" ] || { echo "ERROR: $file not found"; exit 1; };
|
|
17
|
+
today=$(date +%s);
|
|
18
|
+
tail -n +2 "$file" | while IFS=, read -r vendor invoice_id amount due paid; do
|
|
19
|
+
[ "$paid" = "yes" ] && continue;
|
|
20
|
+
due_epoch=$(date -j -f %Y-%m-%d "$due" +%s 2>/dev/null || date -d "$due" +%s);
|
|
21
|
+
days=$(( (today-due_epoch)/86400 ));
|
|
22
|
+
if [ "$days" -le 0 ]; then bucket="current";
|
|
23
|
+
elif [ "$days" -le 30 ]; then bucket="1-30 days";
|
|
24
|
+
elif [ "$days" -le 60 ]; then bucket="31-60 days";
|
|
25
|
+
elif [ "$days" -le 90 ]; then bucket="61-90 days";
|
|
26
|
+
else bucket="90+ days"; fi;
|
|
27
|
+
echo "$bucket | $vendor invoice $invoice_id — \$$amount (due $due)";
|
|
28
|
+
done | sort
|
|
29
|
+
variables:
|
|
30
|
+
payables_file:
|
|
31
|
+
default: "./accounts-payable.csv"
|
|
32
|
+
description: >
|
|
33
|
+
CSV with header "vendor,invoice_id,amount,due_date,paid" (due_date
|
|
34
|
+
is YYYY-MM-DD, paid is yes/no) — bills you owe, not invoices you've
|
|
35
|
+
sent (see invoice-overdue-check for receivables).
|
|
36
|
+
compatible_agents: [generic, claude, codex]
|
|
37
|
+
notes: >
|
|
38
|
+
Zero-token. You maintain accounts-payable.csv yourself (mark paid=yes
|
|
39
|
+
once settled) — this is the payables mirror of invoice-overdue-check,
|
|
40
|
+
which tracks receivables instead.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
id: bank-statement-reconciliation-check
|
|
2
|
+
version: 1
|
|
3
|
+
name: Bank Statement Reconciliation Check
|
|
4
|
+
description: >
|
|
5
|
+
Compares your internal ledger against a bank/card statement export and
|
|
6
|
+
flags transactions present in one but not the other, plus any balance
|
|
7
|
+
mismatch. Use this if your books have ever quietly drifted from what
|
|
8
|
+
the bank actually shows and you only found out at tax time.
|
|
9
|
+
category: finance
|
|
10
|
+
tags: [reconciliation, bookkeeping, bank, finance]
|
|
11
|
+
schedule: "0 9 * * 1"
|
|
12
|
+
timezone: "UTC"
|
|
13
|
+
runner: shell
|
|
14
|
+
command: >
|
|
15
|
+
ledger={{ledger_csv}}; statement={{statement_csv}};
|
|
16
|
+
[ -f "$ledger" ] || { echo "ERROR: $ledger not found"; exit 1; };
|
|
17
|
+
[ -f "$statement" ] || { echo "ERROR: $statement not found"; exit 1; };
|
|
18
|
+
echo "-- in statement but missing from ledger --";
|
|
19
|
+
tail -n +2 "$statement" | cut -d, -f1,3 | sort > /tmp/_stmt_ids.$$;
|
|
20
|
+
tail -n +2 "$ledger" | cut -d, -f1,3 | sort > /tmp/_ledger_ids.$$;
|
|
21
|
+
comm -23 /tmp/_stmt_ids.$$ /tmp/_ledger_ids.$$;
|
|
22
|
+
echo "-- in ledger but missing from statement --";
|
|
23
|
+
comm -13 /tmp/_stmt_ids.$$ /tmp/_ledger_ids.$$;
|
|
24
|
+
rm -f /tmp/_stmt_ids.$$ /tmp/_ledger_ids.$$
|
|
25
|
+
variables:
|
|
26
|
+
ledger_csv:
|
|
27
|
+
default: "./ledger.csv"
|
|
28
|
+
description: >
|
|
29
|
+
CSV with header "date,description,amount" — your internal
|
|
30
|
+
bookkeeping record of transactions.
|
|
31
|
+
statement_csv:
|
|
32
|
+
default: "./bank-statement.csv"
|
|
33
|
+
description: >
|
|
34
|
+
CSV with header "date,description,amount" exported from your bank
|
|
35
|
+
or card provider for the same period.
|
|
36
|
+
compatible_agents: [generic, claude, codex]
|
|
37
|
+
notes: >
|
|
38
|
+
Zero-token, matches on date+amount only (description text often differs
|
|
39
|
+
between ledger and bank export) — near-matches on rounding or
|
|
40
|
+
same-day-different-amount won't be caught, review flagged rows by hand.
|