@wonsukchoi/crondex 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 wonsukchoi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,130 @@
1
+ # crondex
2
+
3
+ A public, growing directory of pre-made cron jobs — built so any AI agent
4
+ (Claude, Codex, Hermes, OpenClaw, or a plain LLM with shell access) can pull
5
+ one, tweak it, and schedule it. Clone it, grab a job, adjust the knobs, run it.
6
+
7
+ ## Quick start
8
+
9
+ ```bash
10
+ git clone https://github.com/wonsukchoi/crondex.git
11
+ cat crondex/catalog.json # browse what's available
12
+ cat crondex/jobs/devops/dependency-audit.yaml # read one job
13
+ ```
14
+
15
+ Give an agent the repo and a goal ("set up something that checks my repo
16
+ health every morning") — it reads `catalog.json`, finds the closest match,
17
+ adjusts `schedule`/`variables`, and wires it into whatever scheduler it has.
18
+
19
+ ## CLI
20
+
21
+ Not yet published to the npm registry, so `npx crondex` doesn't resolve
22
+ publicly yet — for now, run it from a clone:
23
+
24
+ ```bash
25
+ git clone https://github.com/wonsukchoi/crondex.git && cd crondex
26
+ node bin/crondex.js list # browse everything
27
+ node bin/crondex.js list --category devops # filter by category or --tag
28
+ node bin/crondex.js show backup-reminder # print one job's YAML
29
+ node bin/crondex.js add backup-reminder --dest ./cron/backup-reminder.yaml
30
+ ```
31
+
32
+ `add` copies the job's YAML as-is into your project — it's yours to edit
33
+ from there, same as a `git clone` + copy, just one command. Once this is
34
+ published, the same commands work via `npx crondex ...` with no clone
35
+ needed.
36
+
37
+ ## Layout
38
+
39
+ ```
40
+ crondex/
41
+ ├── bin/crondex.js CLI: list / show / add
42
+ ├── catalog.json generated index of every job — read this first
43
+ ├── schema/job.schema.json spec every job file follows
44
+ ├── jobs/
45
+ │ ├── devops/
46
+ │ └── productivity/
47
+ └── scripts/
48
+ ├── build-catalog.js regenerates catalog.json from jobs/**/*.yaml
49
+ └── validate-jobs.js validates every job against the schema
50
+ ```
51
+
52
+ ## Available jobs
53
+
54
+ | id | category | schedule | modes |
55
+ |---|---|---|---|
56
+ | `dependency-audit` | devops | `0 8 * * 1` | script + agent-prompt |
57
+ | `log-cleanup` | devops | `30 3 * * *` | script |
58
+ | `repo-health-check` | devops | `0 9 * * 1-5` | script + agent-prompt |
59
+ | `backup-reminder` | devops | `0 9 * * *` | script |
60
+ | `ssl-cert-expiry-check` | devops | `0 6 * * *` | script |
61
+ | `uptime-ping-check` | devops | `*/15 * * * *` | script |
62
+ | `cost-alert` | devops | `0 7 * * *` | script + agent-prompt |
63
+ | `daily-standup-summary` | productivity | `0 8 * * 1-5` | script + agent-prompt |
64
+ | `inbox-triage` | productivity | `0 7,13 * * 1-5` | agent-prompt only |
65
+ | `weekly-report` | productivity | `0 16 * * 5` | script + agent-prompt |
66
+
67
+ Full details (description, tags, variables) live in `catalog.json` and each
68
+ job's YAML file.
69
+
70
+ ## How a job works
71
+
72
+ Every job is one YAML file with a `runner`:
73
+
74
+ - **`shell`** — run `command` directly. Zero LLM tokens, deterministic, no
75
+ judgment calls.
76
+ - **`agent-prompt`** — hand the `prompt` field to an LLM agent each run.
77
+ Costs tokens, but can synthesize, prioritize, and draft prose.
78
+ - **`hybrid`** — ships both. You (or your agent) pick per run: `command` to
79
+ save tokens and get raw data, or `prompt` when you want the LLM to
80
+ interpret it. `script_note` on the job explains exactly what you trade
81
+ away by choosing the script.
82
+
83
+ `{{placeholders}}` in `command`/`prompt` resolve from `variables`. Each job
84
+ also carries a `version` — bumped whenever `prompt`/`command` behavior
85
+ changes, so if you've already scheduled a job elsewhere you can tell when
86
+ the upstream copy has moved on without you.
87
+
88
+ ```yaml
89
+ id: dependency-audit
90
+ version: 1
91
+ name: Dependency Vulnerability Audit
92
+ description: ...
93
+ category: devops
94
+ tags: [security, dependencies]
95
+ schedule: "0 8 * * 1" # standard 5-field cron
96
+ timezone: "UTC"
97
+ runner: hybrid
98
+ command: |
99
+ ...raw shell audit, zero tokens...
100
+ prompt: |
101
+ ...instructions with {{repo_path}}, LLM synthesizes+prioritizes...
102
+ script_note: what you lose by using `command` instead of `prompt`
103
+ variables:
104
+ repo_path:
105
+ default: "."
106
+ description: ...
107
+ compatible_agents: [claude, codex, hermes, openclaw, generic]
108
+ ```
109
+
110
+ Full spec: [`schema/job.schema.json`](schema/job.schema.json).
111
+
112
+ ## Using a job
113
+
114
+ 1. Pick a job from `catalog.json` — check `modes` to see if it's script-only,
115
+ agent-prompt-only, or both.
116
+ 2. Decide script vs. agent-prompt if the job is `hybrid`: script saves
117
+ tokens, agent-prompt gives you more detail/judgment (see `script_note`).
118
+ 3. Override any `variables` and `schedule` for your case.
119
+ 4. Hand `command` or `prompt` plus `schedule` to your scheduler — system
120
+ crontab, a hosted cron, or your agent's own scheduling mechanism. This
121
+ repo defines *what* to run and *when*, not the executor.
122
+
123
+ ## Contributing a job
124
+
125
+ See [`CONTRIBUTING.md`](CONTRIBUTING.md) — copy `templates/job.template.yaml`,
126
+ fill it in, `npm run validate && npm run build-catalog`, open a PR.
127
+
128
+ ## License
129
+
130
+ [MIT](LICENSE)
package/bin/crondex.js ADDED
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env node
2
+ // CLI over catalog.json — browse jobs, read one, or pull one into your project.
3
+ import { readFileSync, writeFileSync, existsSync } from "node:fs";
4
+ import { join } from "node:path";
5
+
6
+ const ROOT = new URL("..", import.meta.url).pathname;
7
+ const CATALOG = JSON.parse(readFileSync(join(ROOT, "catalog.json"), "utf8"));
8
+ const PKG = JSON.parse(readFileSync(join(ROOT, "package.json"), "utf8"));
9
+
10
+ const [, , cmd, ...args] = process.argv;
11
+
12
+ function flag(name) {
13
+ const i = args.indexOf(`--${name}`);
14
+ return i === -1 ? undefined : args[i + 1];
15
+ }
16
+
17
+ function findJob(id) {
18
+ const meta = CATALOG.jobs.find((j) => j.id === id);
19
+ if (!meta) {
20
+ console.error(`no job named "${id}". Run "crondex list" to see options.`);
21
+ process.exit(1);
22
+ }
23
+ return meta;
24
+ }
25
+
26
+ function printHelp() {
27
+ console.log(`crondex — browse and pull pre-made cron jobs
28
+
29
+ Usage:
30
+ crondex list [--category <name>] [--tag <name>]
31
+ crondex show <id>
32
+ crondex add <id> [--dest <path>]
33
+
34
+ Examples:
35
+ crondex list --category devops
36
+ crondex show dependency-audit
37
+ crondex add backup-reminder --dest ./cron/backup-reminder.yaml
38
+ `);
39
+ }
40
+
41
+ function catalogInfoLine() {
42
+ const viaNpx = process.env.npm_command === "exec";
43
+ const freshness = viaNpx
44
+ ? "running via npx — you're always on the latest catalog."
45
+ : "running from a local/global install — run `npm update -g crondex` (or re-pull) if new jobs seem missing.";
46
+ return `crondex v${PKG.version} — ${CATALOG.count} jobs. ${freshness}`;
47
+ }
48
+
49
+ function list() {
50
+ const category = flag("category");
51
+ const tag = flag("tag");
52
+ const jobs = CATALOG.jobs.filter(
53
+ (j) => (!category || j.category === category) && (!tag || j.tags.includes(tag))
54
+ );
55
+ console.log(catalogInfoLine());
56
+ console.log();
57
+ if (!jobs.length) {
58
+ console.log("no jobs matched.");
59
+ return;
60
+ }
61
+ for (const j of jobs) {
62
+ console.log(`${j.id} [${j.category}] (${j.modes.join(", ")})`);
63
+ console.log(` ${j.description}`);
64
+ console.log();
65
+ }
66
+ }
67
+
68
+ function show(id) {
69
+ console.log(readFileSync(join(ROOT, findJob(id).path), "utf8"));
70
+ }
71
+
72
+ function add(id) {
73
+ const meta = findJob(id);
74
+ const dest = flag("dest") ?? `./${id}.yaml`;
75
+ if (existsSync(dest)) {
76
+ console.error(`${dest} already exists — refusing to overwrite. Pass --dest to choose another path.`);
77
+ process.exit(1);
78
+ }
79
+ writeFileSync(dest, readFileSync(join(ROOT, meta.path), "utf8"));
80
+ console.log(`wrote ${dest}`);
81
+ }
82
+
83
+ switch (cmd) {
84
+ case "list":
85
+ list();
86
+ break;
87
+ case "show":
88
+ if (!args[0]) {
89
+ console.error("usage: crondex show <id>");
90
+ process.exit(1);
91
+ }
92
+ show(args[0]);
93
+ break;
94
+ case "add":
95
+ if (!args[0]) {
96
+ console.error("usage: crondex add <id> [--dest <path>]");
97
+ process.exit(1);
98
+ }
99
+ add(args[0]);
100
+ break;
101
+ default:
102
+ printHelp();
103
+ }
package/catalog.json ADDED
@@ -0,0 +1,263 @@
1
+ {
2
+ "generated_by": "scripts/build-catalog.js",
3
+ "schema": "schema/job.schema.json",
4
+ "count": 10,
5
+ "jobs": [
6
+ {
7
+ "id": "backup-reminder",
8
+ "version": 1,
9
+ "name": "Backup Freshness Check",
10
+ "description": "Checks that your backup file actually got updated recently, and warns you if it's missing or stale. Use this if you have a backup process running somewhere and want to catch it silently failing before you need it.",
11
+ "category": "devops",
12
+ "tags": [
13
+ "backup",
14
+ "reliability",
15
+ "maintenance"
16
+ ],
17
+ "schedule": "0 9 * * *",
18
+ "timezone": "UTC",
19
+ "runner": "shell",
20
+ "modes": [
21
+ "script"
22
+ ],
23
+ "compatible_agents": [
24
+ "generic",
25
+ "claude",
26
+ "codex"
27
+ ],
28
+ "path": "jobs/devops/backup-reminder.yaml"
29
+ },
30
+ {
31
+ "id": "cost-alert",
32
+ "version": 1,
33
+ "name": "Cloud/API Cost Alert",
34
+ "description": "Checks your recent cloud or API spend against a budget and warns you if you're over or on pace to go over. Use this if you've ever been surprised by a bill.",
35
+ "category": "devops",
36
+ "tags": [
37
+ "cost",
38
+ "billing",
39
+ "budget"
40
+ ],
41
+ "schedule": "0 7 * * *",
42
+ "timezone": "UTC",
43
+ "runner": "hybrid",
44
+ "modes": [
45
+ "script",
46
+ "agent-prompt"
47
+ ],
48
+ "compatible_agents": [
49
+ "claude",
50
+ "codex",
51
+ "hermes",
52
+ "openclaw",
53
+ "generic"
54
+ ],
55
+ "path": "jobs/devops/cost-alert.yaml"
56
+ },
57
+ {
58
+ "id": "daily-standup-summary",
59
+ "version": 1,
60
+ "name": "Daily Standup Summary",
61
+ "description": "Pulls together what you did yesterday (commits, closed tasks) plus today's calendar, and drafts a quick 3-line standup update. Use this if you're tired of writing the same \"yesterday / today / blockers\" recap every morning.",
62
+ "category": "productivity",
63
+ "tags": [
64
+ "standup",
65
+ "reporting",
66
+ "daily"
67
+ ],
68
+ "schedule": "0 8 * * 1-5",
69
+ "timezone": "America/Los_Angeles",
70
+ "runner": "hybrid",
71
+ "modes": [
72
+ "script",
73
+ "agent-prompt"
74
+ ],
75
+ "compatible_agents": [
76
+ "claude",
77
+ "codex",
78
+ "hermes",
79
+ "openclaw",
80
+ "generic"
81
+ ],
82
+ "path": "jobs/productivity/daily-standup-summary.yaml"
83
+ },
84
+ {
85
+ "id": "dependency-audit",
86
+ "version": 1,
87
+ "name": "Dependency Vulnerability Audit",
88
+ "description": "Checks your project's dependencies for known security vulnerabilities and packages that are way out of date, then summarizes what to fix first. Use this if you want a heads-up before something exploitable slips into production.",
89
+ "category": "devops",
90
+ "tags": [
91
+ "security",
92
+ "dependencies",
93
+ "maintenance"
94
+ ],
95
+ "schedule": "0 8 * * 1",
96
+ "timezone": "UTC",
97
+ "runner": "hybrid",
98
+ "modes": [
99
+ "script",
100
+ "agent-prompt"
101
+ ],
102
+ "compatible_agents": [
103
+ "claude",
104
+ "codex",
105
+ "hermes",
106
+ "openclaw",
107
+ "generic"
108
+ ],
109
+ "path": "jobs/devops/dependency-audit.yaml"
110
+ },
111
+ {
112
+ "id": "inbox-triage",
113
+ "version": 1,
114
+ "name": "Inbox Triage",
115
+ "description": "Sorts your unread messages into \"needs a reply today\" vs. \"just FYI\" vs. \"spam,\" and drafts quick replies for the easy ones — it never sends anything without you approving it first. Use this if your inbox piles up and you want a head start each morning.",
116
+ "category": "productivity",
117
+ "tags": [
118
+ "email",
119
+ "triage",
120
+ "daily"
121
+ ],
122
+ "schedule": "0 7,13 * * 1-5",
123
+ "timezone": "America/Los_Angeles",
124
+ "runner": "agent-prompt",
125
+ "modes": [
126
+ "agent-prompt"
127
+ ],
128
+ "compatible_agents": [
129
+ "claude",
130
+ "codex",
131
+ "hermes",
132
+ "openclaw",
133
+ "generic"
134
+ ],
135
+ "path": "jobs/productivity/inbox-triage.yaml"
136
+ },
137
+ {
138
+ "id": "log-cleanup",
139
+ "version": 1,
140
+ "name": "Old Log File Cleanup",
141
+ "description": "Deletes old log files so they don't quietly fill up your disk. Use this if your app or server writes logs to a folder and nobody's manually clearing them out.",
142
+ "category": "devops",
143
+ "tags": [
144
+ "housekeeping",
145
+ "disk-space"
146
+ ],
147
+ "schedule": "30 3 * * *",
148
+ "timezone": "UTC",
149
+ "runner": "shell",
150
+ "modes": [
151
+ "script"
152
+ ],
153
+ "compatible_agents": [
154
+ "generic",
155
+ "claude",
156
+ "codex"
157
+ ],
158
+ "path": "jobs/devops/log-cleanup.yaml"
159
+ },
160
+ {
161
+ "id": "repo-health-check",
162
+ "version": 1,
163
+ "name": "Git Repo Health Check",
164
+ "description": "Checks a git repo for branches nobody's touched in a while, uncommitted changes sitting around, and pull requests waiting on review, then reports a short digest. Use this if you want a daily nudge on repo hygiene without checking everything by hand.",
165
+ "category": "devops",
166
+ "tags": [
167
+ "git",
168
+ "ci",
169
+ "maintenance"
170
+ ],
171
+ "schedule": "0 9 * * 1-5",
172
+ "timezone": "UTC",
173
+ "runner": "hybrid",
174
+ "modes": [
175
+ "script",
176
+ "agent-prompt"
177
+ ],
178
+ "compatible_agents": [
179
+ "claude",
180
+ "codex",
181
+ "hermes",
182
+ "openclaw",
183
+ "generic"
184
+ ],
185
+ "path": "jobs/devops/repo-health-check.yaml"
186
+ },
187
+ {
188
+ "id": "ssl-cert-expiry-check",
189
+ "version": 1,
190
+ "name": "SSL Certificate Expiry Check",
191
+ "description": "Checks how many days are left before a website's SSL certificate expires. Use this if you run a site and want a warning before the padlock breaks and visitors start seeing browser security errors.",
192
+ "category": "devops",
193
+ "tags": [
194
+ "ssl",
195
+ "tls",
196
+ "security",
197
+ "uptime"
198
+ ],
199
+ "schedule": "0 6 * * *",
200
+ "timezone": "UTC",
201
+ "runner": "shell",
202
+ "modes": [
203
+ "script"
204
+ ],
205
+ "compatible_agents": [
206
+ "generic",
207
+ "claude",
208
+ "codex"
209
+ ],
210
+ "path": "jobs/devops/ssl-cert-expiry-check.yaml"
211
+ },
212
+ {
213
+ "id": "uptime-ping-check",
214
+ "version": 1,
215
+ "name": "Uptime Ping Check",
216
+ "description": "Pings a URL on a schedule and flags it if it stops responding. Use this if you want a basic \"is my site down\" alert without paying for a monitoring service.",
217
+ "category": "devops",
218
+ "tags": [
219
+ "uptime",
220
+ "monitoring",
221
+ "reliability"
222
+ ],
223
+ "schedule": "*/15 * * * *",
224
+ "timezone": "UTC",
225
+ "runner": "shell",
226
+ "modes": [
227
+ "script"
228
+ ],
229
+ "compatible_agents": [
230
+ "generic",
231
+ "claude",
232
+ "codex"
233
+ ],
234
+ "path": "jobs/devops/uptime-ping-check.yaml"
235
+ },
236
+ {
237
+ "id": "weekly-report",
238
+ "version": 1,
239
+ "name": "Weekly Progress Report",
240
+ "description": "Rolls up a week's worth of commits and progress into a short report you can hand to your team. Use this if you dread writing the Friday status update from scratch every week.",
241
+ "category": "productivity",
242
+ "tags": [
243
+ "reporting",
244
+ "weekly"
245
+ ],
246
+ "schedule": "0 16 * * 5",
247
+ "timezone": "America/Los_Angeles",
248
+ "runner": "hybrid",
249
+ "modes": [
250
+ "script",
251
+ "agent-prompt"
252
+ ],
253
+ "compatible_agents": [
254
+ "claude",
255
+ "codex",
256
+ "hermes",
257
+ "openclaw",
258
+ "generic"
259
+ ],
260
+ "path": "jobs/productivity/weekly-report.yaml"
261
+ }
262
+ ]
263
+ }
@@ -0,0 +1,26 @@
1
+ id: backup-reminder
2
+ version: 1
3
+ name: Backup Freshness Check
4
+ description: >
5
+ Checks that your backup file actually got updated recently, and warns you
6
+ if it's missing or stale. Use this if you have a backup process running
7
+ somewhere and want to catch it silently failing before you need it.
8
+ category: devops
9
+ tags: [backup, reliability, maintenance]
10
+ schedule: "0 9 * * *"
11
+ timezone: "UTC"
12
+ runner: shell
13
+ command: >
14
+ f={{backup_path}}; [ -e "$f" ] || { echo "MISSING: $f not found"; exit 1; };
15
+ age=$(( ( $(date +%s) - $(stat -f %m "$f" 2>/dev/null || stat -c %Y "$f") ) / 86400 ));
16
+ if [ "$age" -gt {{max_age_days}} ]; then echo "STALE: $f last updated $age days ago"; exit 1;
17
+ else echo "OK: $f last updated $age days ago"; fi
18
+ variables:
19
+ backup_path:
20
+ default: "./backups/latest.tar.gz"
21
+ description: File or directory to check the mtime of.
22
+ max_age_days:
23
+ default: 1
24
+ description: Alert if the backup is older than this many days.
25
+ compatible_agents: [generic, claude, codex]
26
+ notes: Exits non-zero on missing/stale so a scheduler can alert on failure. Adjust stat flag for Linux vs macOS if running raw (command above handles both).
@@ -0,0 +1,46 @@
1
+ id: cost-alert
2
+ version: 1
3
+ name: Cloud/API Cost Alert
4
+ description: >
5
+ Checks your recent cloud or API spend against a budget and warns you if
6
+ you're over or on pace to go over. Use this if you've ever been
7
+ surprised by a bill.
8
+ category: devops
9
+ tags: [cost, billing, budget]
10
+ schedule: "0 7 * * *"
11
+ timezone: "UTC"
12
+ runner: hybrid
13
+ command: >
14
+ if command -v aws >/dev/null 2>&1; then
15
+ start=$(date -d "-{{lookback_days}} days" +%Y-%m-%d 2>/dev/null || date -v-{{lookback_days}}d +%Y-%m-%d);
16
+ end=$(date +%Y-%m-%d);
17
+ aws ce get-cost-and-usage --time-period Start=$start,End=$end --granularity DAILY --metrics UnblendedCost 2>/dev/null || echo "aws cost explorer call failed (check credentials/permissions)";
18
+ elif command -v vercel >/dev/null 2>&1; then
19
+ vercel billing 2>/dev/null || echo "vercel CLI present but no billing subcommand available";
20
+ else
21
+ echo "no supported billing CLI found (aws/vercel) — use agent-prompt mode instead";
22
+ fi
23
+ prompt: |
24
+ Check current spend for {{provider_hint}} covering the last {{lookback_days}} days.
25
+ 1. Use whatever billing/cost API, CLI, or dashboard you have access to for this account.
26
+ 2. Compare total spend to the {{budget_usd}} budget.
27
+ 3. If over budget, or on pace to exceed it before the period ends, alert
28
+ with the overage amount and the top 3 cost drivers.
29
+ 4. If under budget, report spend vs. budget in one line.
30
+ script_note: >
31
+ `command` dumps raw provider CLI output (AWS/Vercel only) with no budget
32
+ comparison — parsing arbitrary billing JSON reliably in shell isn't
33
+ practical. `prompt` works with any provider your agent has access to and
34
+ does the budget comparison and driver breakdown.
35
+ variables:
36
+ provider_hint:
37
+ default: "cloud provider"
38
+ description: Name the provider/account to check (e.g. "AWS", "Vercel", "OpenAI API").
39
+ budget_usd:
40
+ default: 100
41
+ description: Budget threshold in USD for the lookback window.
42
+ lookback_days:
43
+ default: 30
44
+ description: Rolling window of spend to evaluate.
45
+ compatible_agents: [claude, codex, hermes, openclaw, generic]
46
+ notes: Script mode only covers AWS/Vercel CLIs out of the box; extend `command` for other providers as needed.
@@ -0,0 +1,39 @@
1
+ id: dependency-audit
2
+ version: 1
3
+ name: Dependency Vulnerability Audit
4
+ description: >
5
+ Checks your project's dependencies for known security vulnerabilities and
6
+ packages that are way out of date, then summarizes what to fix first.
7
+ Use this if you want a heads-up before something exploitable slips into
8
+ production.
9
+ category: devops
10
+ tags: [security, dependencies, maintenance]
11
+ schedule: "0 8 * * 1"
12
+ timezone: "UTC"
13
+ runner: hybrid
14
+ command: >
15
+ cd {{repo_path}} &&
16
+ if [ -f package.json ]; then npm audit;
17
+ elif [ -f requirements.txt ]; then pip-audit -r requirements.txt;
18
+ elif [ -f Cargo.toml ]; then cargo audit;
19
+ else echo "no supported manifest (package.json/requirements.txt/Cargo.toml) found"; fi
20
+ prompt: |
21
+ Run a dependency audit on the repo at {{repo_path}}.
22
+ 1. Detect the package manager(s) in use (npm/pnpm/yarn/pip/cargo/etc).
23
+ 2. Run each manager's native audit command (e.g. `npm audit`, `pip-audit`).
24
+ 3. List vulnerabilities by severity, and packages more than {{staleness_days}}
25
+ days behind latest.
26
+ 4. Summarize findings in under 200 words with a prioritized action list.
27
+ Do not modify any files — report only.
28
+ script_note: >
29
+ `command` prints the raw audit tool output, zero tokens. `prompt` additionally
30
+ flags stale-but-not-vulnerable packages and ranks/prioritizes the findings for you.
31
+ variables:
32
+ repo_path:
33
+ default: "."
34
+ description: Path to the repo to audit.
35
+ staleness_days:
36
+ default: 180
37
+ description: Flag packages whose latest release is older than this many days behind current.
38
+ compatible_agents: [claude, codex, hermes, openclaw, generic]
39
+ notes: Read-only job. Safe to run unattended.
@@ -0,0 +1,26 @@
1
+ id: log-cleanup
2
+ version: 1
3
+ name: Old Log File Cleanup
4
+ description: >
5
+ Deletes old log files so they don't quietly fill up your disk.
6
+ Use this if your app or server writes logs to a folder and nobody's
7
+ manually clearing them out.
8
+ category: devops
9
+ tags: [housekeeping, disk-space]
10
+ schedule: "30 3 * * *"
11
+ timezone: "UTC"
12
+ runner: shell
13
+ command: >
14
+ find {{log_dir}} -type f -name "{{log_pattern}}" -mtime +{{retention_days}} -delete
15
+ variables:
16
+ log_dir:
17
+ default: "./logs"
18
+ description: Directory to clean.
19
+ log_pattern:
20
+ default: "*.log"
21
+ description: Glob pattern for files to consider.
22
+ retention_days:
23
+ default: 14
24
+ description: Delete files last modified more than this many days ago.
25
+ compatible_agents: [generic, claude, codex]
26
+ notes: Destructive job — dry-run with `find ... -print` instead of `-delete` before first use.
@@ -0,0 +1,42 @@
1
+ id: repo-health-check
2
+ version: 1
3
+ name: Git Repo Health Check
4
+ description: >
5
+ Checks a git repo for branches nobody's touched in a while, uncommitted
6
+ changes sitting around, and pull requests waiting on review, then reports
7
+ a short digest. Use this if you want a daily nudge on repo hygiene
8
+ without checking everything by hand.
9
+ category: devops
10
+ tags: [git, ci, maintenance]
11
+ schedule: "0 9 * * 1-5"
12
+ timezone: "UTC"
13
+ runner: hybrid
14
+ command: >
15
+ cd {{repo_path}} && now=$(date +%s) &&
16
+ echo "--- branches stale >{{stale_branch_days}}d ---" &&
17
+ git for-each-ref --format='%(committerdate:unix) %(refname:short)' refs/heads/ |
18
+ while read ts name; do age=$(( (now-ts)/86400 )); [ "$age" -gt {{stale_branch_days}} ] && echo "$name: ${age}d"; done;
19
+ echo "--- uncommitted changes ---"; git status --short;
20
+ command -v gh >/dev/null && { echo "--- open PRs ---"; gh pr list --state open; } || echo "(gh not installed, skipping PR check)"
21
+ prompt: |
22
+ Check the health of the repo at {{repo_path}}.
23
+ 1. List local/remote branches not touched in over {{stale_branch_days}} days.
24
+ 2. Flag any uncommitted changes sitting for more than a day.
25
+ 3. If a CI config exists, report the status of the last run on the default branch.
26
+ 4. List open PRs older than {{stale_pr_days}} days with no recent activity.
27
+ Summarize as a short digest, most actionable item first.
28
+ script_note: >
29
+ `command` prints raw stale-branch/status/PR-list data, zero tokens. `prompt`
30
+ additionally checks CI status and turns it into a prioritized digest.
31
+ variables:
32
+ repo_path:
33
+ default: "."
34
+ description: Path to the repo to check.
35
+ stale_branch_days:
36
+ default: 30
37
+ description: Branches with no commits in this many days are flagged stale.
38
+ stale_pr_days:
39
+ default: 7
40
+ description: Open PRs with no activity in this many days are flagged.
41
+ compatible_agents: [claude, codex, hermes, openclaw, generic]
42
+ notes: Read-only job. Needs `gh` CLI or equivalent for PR/CI data if available.
@@ -0,0 +1,33 @@
1
+ id: ssl-cert-expiry-check
2
+ version: 1
3
+ name: SSL Certificate Expiry Check
4
+ description: >
5
+ Checks how many days are left before a website's SSL certificate expires.
6
+ Use this if you run a site and want a warning before the padlock breaks
7
+ and visitors start seeing browser security errors.
8
+ category: devops
9
+ tags: [ssl, tls, security, uptime]
10
+ schedule: "0 6 * * *"
11
+ timezone: "UTC"
12
+ runner: shell
13
+ command: >
14
+ host={{host}}; port={{port}};
15
+ exp=$(echo | openssl s_client -servername "$host" -connect "$host:$port" 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2);
16
+ [ -z "$exp" ] && { echo "ERROR: could not fetch certificate for $host:$port"; exit 1; };
17
+ exp_epoch=$(date -d "$exp" +%s 2>/dev/null || date -j -f "%b %d %T %Y %Z" "$exp" +%s);
18
+ now=$(date +%s);
19
+ days=$(( (exp_epoch-now)/86400 ));
20
+ if [ "$days" -lt {{warn_days}} ]; then echo "WARNING: $host cert expires in $days days ($exp)"; exit 1;
21
+ else echo "OK: $host cert expires in $days days ($exp)"; fi
22
+ variables:
23
+ host:
24
+ default: "example.com"
25
+ description: Hostname to check.
26
+ port:
27
+ default: 443
28
+ description: Port the TLS service listens on.
29
+ warn_days:
30
+ default: 14
31
+ description: Alert if the cert expires within this many days.
32
+ compatible_agents: [generic, claude, codex]
33
+ notes: Zero-token, deterministic — no LLM mode needed for a plain expiry check.
@@ -0,0 +1,26 @@
1
+ id: uptime-ping-check
2
+ version: 1
3
+ name: Uptime Ping Check
4
+ description: >
5
+ Pings a URL on a schedule and flags it if it stops responding.
6
+ Use this if you want a basic "is my site down" alert without paying for
7
+ a monitoring service.
8
+ category: devops
9
+ tags: [uptime, monitoring, reliability]
10
+ schedule: "*/15 * * * *"
11
+ timezone: "UTC"
12
+ runner: shell
13
+ command: >
14
+ url={{url}}; timeout={{timeout_seconds}};
15
+ code=$(curl -o /dev/null -s -w '%{http_code}' --max-time "$timeout" "$url");
16
+ if [ "$code" -ge 200 ] && [ "$code" -lt 400 ]; then echo "OK: $url returned $code";
17
+ else echo "DOWN: $url returned $code"; exit 1; fi
18
+ variables:
19
+ url:
20
+ default: "https://example.com"
21
+ description: URL to check.
22
+ timeout_seconds:
23
+ default: 10
24
+ description: Max seconds to wait for a response before treating it as down.
25
+ compatible_agents: [generic, claude, codex]
26
+ notes: Zero-token, deterministic. Run at a tighter interval (e.g. every 5-15 min) for real monitoring.
@@ -0,0 +1,38 @@
1
+ id: daily-standup-summary
2
+ version: 1
3
+ name: Daily Standup Summary
4
+ description: >
5
+ Pulls together what you did yesterday (commits, closed tasks) plus
6
+ today's calendar, and drafts a quick 3-line standup update. Use this if
7
+ you're tired of writing the same "yesterday / today / blockers" recap
8
+ every morning.
9
+ category: productivity
10
+ tags: [standup, reporting, daily]
11
+ schedule: "0 8 * * 1-5"
12
+ timezone: "America/Los_Angeles"
13
+ runner: hybrid
14
+ command: >
15
+ cd {{repo_path}} && echo "--- commits last {{lookback_hours}}h ---" &&
16
+ git log --since="{{lookback_hours}} hours ago" --pretty=format:'%h %s'
17
+ prompt: |
18
+ Draft a standup update for {{person_name}}.
19
+ 1. Summarize commits and merged PRs from the last {{lookback_hours}} hours in
20
+ {{repo_path}}.
21
+ 2. List today's calendar events if a calendar source is connected.
22
+ 3. Ask the user (or infer from open tasks) what blockers to mention.
23
+ Output exactly 3 lines: Yesterday / Today / Blockers.
24
+ script_note: >
25
+ `command` dumps the raw commit log, zero tokens. `prompt` additionally pulls
26
+ calendar events, infers blockers, and writes the 3-line Yesterday/Today/Blockers format.
27
+ variables:
28
+ person_name:
29
+ default: "me"
30
+ description: Name to use in the summary.
31
+ repo_path:
32
+ default: "."
33
+ description: Repo to pull commit history from.
34
+ lookback_hours:
35
+ default: 24
36
+ description: Window of history to summarize.
37
+ compatible_agents: [claude, codex, hermes, openclaw, generic]
38
+ notes: Pairs well with a Slack/email delivery step if the agent has that integration.
@@ -0,0 +1,32 @@
1
+ id: inbox-triage
2
+ version: 1
3
+ name: Inbox Triage
4
+ description: >
5
+ Sorts your unread messages into "needs a reply today" vs. "just FYI" vs.
6
+ "spam," and drafts quick replies for the easy ones — it never sends
7
+ anything without you approving it first. Use this if your inbox piles up
8
+ and you want a head start each morning.
9
+ category: productivity
10
+ tags: [email, triage, daily]
11
+ schedule: "0 7,13 * * 1-5"
12
+ timezone: "America/Los_Angeles"
13
+ runner: agent-prompt
14
+ prompt: |
15
+ Triage unread messages in {{inbox_source}} from the last {{lookback_hours}} hours.
16
+ 1. Bucket each into: needs-reply-today, fyi-only, spam/newsletter.
17
+ 2. For anything in needs-reply-today that looks routine (scheduling, simple
18
+ confirmations), draft a short reply but do NOT send — save as a draft.
19
+ 3. Report counts per bucket and list the needs-reply-today items with a
20
+ one-line reason each.
21
+ variables:
22
+ inbox_source:
23
+ default: "primary inbox"
24
+ description: Which inbox/connector to read from.
25
+ lookback_hours:
26
+ default: 18
27
+ description: Window of unread messages to consider.
28
+ compatible_agents: [claude, codex, hermes, openclaw, generic]
29
+ notes: >
30
+ Never auto-send. Draft-only by design — review before sending.
31
+ No script mode: categorization and reply drafting require judgment, and
32
+ inbox access varies too much by connector for a generic shell equivalent.
@@ -0,0 +1,39 @@
1
+ id: weekly-report
2
+ version: 1
3
+ name: Weekly Progress Report
4
+ description: >
5
+ Rolls up a week's worth of commits and progress into a short report you
6
+ can hand to your team. Use this if you dread writing the Friday status
7
+ update from scratch every week.
8
+ category: productivity
9
+ tags: [reporting, weekly]
10
+ schedule: "0 16 * * 5"
11
+ timezone: "America/Los_Angeles"
12
+ runner: hybrid
13
+ command: >
14
+ cd {{repo_path}} && echo "--- shortlog last {{lookback_days}}d ---" &&
15
+ git shortlog -sn --since="{{lookback_days}} days ago" &&
16
+ echo "--- commits ---" && git log --since="{{lookback_days}} days ago" --pretty=format:'%h %an %s'
17
+ prompt: |
18
+ Build a weekly report for {{project_name}} covering the last {{lookback_days}} days.
19
+ 1. Summarize merged PRs / commits in {{repo_path}}.
20
+ 2. Summarize closed tasks/issues if a tracker is connected.
21
+ 3. Note any metrics worth flagging (e.g. errors, usage) if a source is
22
+ connected.
23
+ 4. Write it as 4 sections: Shipped, In Progress, Blocked, Next Week.
24
+ Keep the whole report under 300 words.
25
+ script_note: >
26
+ `command` dumps raw commit/shortlog stats, zero tokens. `prompt` additionally
27
+ pulls tracker/metrics data and writes the narrative Shipped/In Progress/Blocked/Next Week report.
28
+ variables:
29
+ project_name:
30
+ default: "this project"
31
+ description: Name to use in the report header.
32
+ repo_path:
33
+ default: "."
34
+ description: Repo to pull history from.
35
+ lookback_days:
36
+ default: 7
37
+ description: Rolling window the report covers.
38
+ compatible_agents: [claude, codex, hermes, openclaw, generic]
39
+ notes: Schedule for Friday afternoon by default; adjust `schedule` for your team's cadence.
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@wonsukchoi/crondex",
3
+ "version": "0.1.0",
4
+ "description": "A public directory of pre-made, agent-editable cron jobs.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/wonsukchoi/crondex.git"
10
+ },
11
+ "homepage": "https://github.com/wonsukchoi/crondex",
12
+ "keywords": [
13
+ "cron",
14
+ "cron-jobs",
15
+ "ai-agent",
16
+ "claude",
17
+ "codex",
18
+ "automation",
19
+ "scheduler"
20
+ ],
21
+ "bin": {
22
+ "crondex": "bin/crondex.js"
23
+ },
24
+ "files": [
25
+ "bin",
26
+ "jobs",
27
+ "schema",
28
+ "catalog.json"
29
+ ],
30
+ "engines": {
31
+ "node": ">=18"
32
+ },
33
+ "scripts": {
34
+ "build-catalog": "node scripts/build-catalog.js",
35
+ "validate": "node scripts/validate-jobs.js"
36
+ },
37
+ "devDependencies": {
38
+ "ajv": "^8.17.1",
39
+ "js-yaml": "^4.1.0"
40
+ }
41
+ }
@@ -0,0 +1,86 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://github.com/wonsukchoi/crondex/schema/job.schema.json",
4
+ "title": "Crondex Job",
5
+ "description": "One pre-made cron job any AI agent (Claude, Codex, Hermes, OpenClaw, etc.) can pull, adjust, and schedule.",
6
+ "type": "object",
7
+ "required": ["id", "version", "name", "description", "schedule", "runner", "compatible_agents"],
8
+ "properties": {
9
+ "id": {
10
+ "type": "string",
11
+ "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
12
+ "description": "Unique slug, matches filename without extension."
13
+ },
14
+ "version": {
15
+ "type": "integer",
16
+ "minimum": 1,
17
+ "description": "Bump when `prompt` or `command` behavior changes meaningfully, so agents that already scheduled this job know to re-check it. Do not bump for wording-only edits."
18
+ },
19
+ "name": { "type": "string" },
20
+ "description": { "type": "string" },
21
+ "category": { "type": "string" },
22
+ "tags": {
23
+ "type": "array",
24
+ "items": { "type": "string" }
25
+ },
26
+ "schedule": {
27
+ "type": "string",
28
+ "description": "Standard 5-field cron expression, e.g. '0 9 * * 1-5'."
29
+ },
30
+ "timezone": {
31
+ "type": "string",
32
+ "description": "IANA timezone, e.g. 'America/Los_Angeles'. Defaults to system local time if omitted."
33
+ },
34
+ "runner": {
35
+ "type": "string",
36
+ "enum": ["agent-prompt", "shell", "hybrid"],
37
+ "description": "'agent-prompt' hands `prompt` to an LLM agent each run (uses tokens, richer output). 'shell' executes `command` directly (zero tokens). 'hybrid' ships both — pick `command` to save tokens or `prompt` for more detail/judgment."
38
+ },
39
+ "prompt": {
40
+ "type": "string",
41
+ "description": "Task text given to the agent. Supports {{variable}} placeholders resolved from `variables`."
42
+ },
43
+ "command": {
44
+ "type": "string",
45
+ "description": "Shell command to run, for runner: shell or hybrid. Supports {{variable}} placeholders."
46
+ },
47
+ "script_note": {
48
+ "type": "string",
49
+ "description": "For hybrid jobs: what the zero-token `command` gives you vs. what only the LLM `prompt` mode adds (e.g. no narrative synthesis, no judgment calls)."
50
+ },
51
+ "variables": {
52
+ "type": "object",
53
+ "additionalProperties": {
54
+ "type": "object",
55
+ "required": ["default"],
56
+ "properties": {
57
+ "default": {},
58
+ "description": { "type": "string" }
59
+ }
60
+ },
61
+ "description": "User-adjustable knobs, keyed by placeholder name."
62
+ },
63
+ "compatible_agents": {
64
+ "type": "array",
65
+ "items": {
66
+ "type": "string",
67
+ "enum": ["claude", "codex", "hermes", "openclaw", "generic"]
68
+ }
69
+ },
70
+ "notes": { "type": "string" }
71
+ },
72
+ "allOf": [
73
+ {
74
+ "if": { "properties": { "runner": { "const": "agent-prompt" } } },
75
+ "then": { "required": ["prompt"] }
76
+ },
77
+ {
78
+ "if": { "properties": { "runner": { "const": "shell" } } },
79
+ "then": { "required": ["command"] }
80
+ },
81
+ {
82
+ "if": { "properties": { "runner": { "const": "hybrid" } } },
83
+ "then": { "required": ["prompt", "command"] }
84
+ }
85
+ ]
86
+ }