npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

cron-claude

v2.2.7

Published

Schedule Claude jobs in agent loop mode — no daemon, full tool access

Readme

cron-claude

Schedule recurring Claude jobs with cron expressions. Claude Code acts as the executor — no daemon, no background process. Jobs run as subagents with full tool access.

How It Works

Claude Code runs an agent loop via the /cron-loop slash command. Every 60 seconds it checks for due jobs, spawns a subagent for each one, and each subagent executes the job's prompt with full MCP tool access (bash, files, APIs, etc.). Job state is managed on disk to prevent duplicate execution.

Quickstart

npm install -g cron-claude
cron-claude install          # sets up MCP server + slash commands

# Add a job
cron-claude add --id daily-standup --schedule "0 9 * * 1-5" --prompt "Post standup summary to Slack"

# In Claude Code, type:
/cron-loop

That's it. The loop runs indefinitely, checking for due jobs every 60 seconds.

Setup

cron-claude install does two things:

  1. MCP server — adds cron-claude-mcp to ~/.claude/settings.json
  2. Slash commands — installs /cron and /cron-loop into ~/.claude/commands/

You can also run these separately:

cron-claude mcp install      # just the MCP server
cron-claude skill install    # just the slash commands

Slash Commands

| Command | Purpose | |---------|---------| | /cron | Manage jobs via natural language (add, list, remove, enable, disable) | | /cron-loop | Start the agent loop executor |

CLI Reference

cron-claude list
cron-claude add --id <id> --schedule "<cron>" --prompt "<prompt>" [--prompt-file <path>] [--model <model>] [--disabled]
cron-claude edit <id> [--schedule "<cron>"] [--prompt "<prompt>"] [--prompt-file <path>] [--model <model>] [--enable] [--disable]
cron-claude show <id>
cron-claude remove <id>
cron-claude enable <id>
cron-claude disable <id>
cron-claude status
cron-claude install              # one-time setup: MCP + slash commands
cron-claude mcp install          # MCP server only
cron-claude skill install        # slash commands only
cron-claude start-loop           # print loop operating instructions
cron-claude get-due-jobs         # get due jobs as JSON (used by loop)
cron-claude mark-job-run <id> [--output <text>] [--error <text>]  # mark job complete (used by loop)

add flags

| Flag | Required | Default | Description | |------|----------|---------|-------------| | --id <id> | ✅ | — | Unique job identifier | | --schedule "<cron>" | ✅ | — | Cron expression (5-field: min hour day month weekday) | | --prompt "<prompt>" | ✅* | — | Inline prompt text (mutually exclusive with --prompt-file) | | --prompt-file <path> | ✅* | — | Path to a .md/.txt file containing the prompt (mutually exclusive with --prompt) | | --model <model> | — | sonnet | Model for the job | | --disabled | — | false | Create in disabled state |

*One of --prompt or --prompt-file is required.

edit flags

Edit a job in place — only the flags you provide are updated; everything else stays as-is.

cron-claude edit my-job --schedule "0 10 * * *"
cron-claude edit my-job --prompt "New prompt text"
cron-claude edit my-job --prompt-file ./prompts/daily.md --model opus --enable

| Flag | Description | |------|-------------| | --schedule "<cron>" | New cron schedule | | --prompt "<prompt>" | New inline prompt (clears --prompt-file if set) | | --prompt-file <path> | New prompt file path (clears inline prompt if set) | | --model <model> | New model | | --enable | Enable the job | | --disable | Disable the job |

show

Show full details of a single job, including the complete untruncated prompt. If the job uses a prompt file, shows the file path and its contents.

cron-claude show my-job

list truncates prompts to 40 characters — use show to see the full text.

Cron schedule examples

| Expression | Meaning | |-----------|---------| | 0 9 * * 1-5 | Weekdays at 9:00 AM | | 0 14 * * * | Daily at 2:00 PM | | */30 * * * * | Every 30 minutes | | 0 0 * * 0 | Sundays at midnight |

MCP Tools

Available when the MCP server is installed:

| Tool | Description | |------|-------------| | start_loop | Returns loop operating instructions. Call this first. | | get_due_jobs | Returns jobs due now as JSON. Atomically marks them running on disk. Call every 60s. | | mark_job_run | Records job completion. Clears running status and writes log. Subagents must call this. | | add_cron | Add a scheduled job | | remove_cron | Remove a job by ID | | enable_cron | Enable a job | | disable_cron | Disable a job | | list_crons | List all jobs (JSON) | | edit_cron | Edit a job in place (partial update — only provided fields change) | | show_cron | Show full details of a single job including complete prompt/file contents | | get_status | Job counts (total, enabled, disabled, running) |

Job State & Duplicate Prevention

Jobs are stored in ~/.cron-claude/jobs.json. Each job has a status field (idle or running) and a lastRunAt timestamp.

How duplicates are prevented:

  1. get_due_jobs atomically marks returned jobs as running before returning them
  2. Jobs with status: "running" are skipped by subsequent get_due_jobs calls
  3. A 55-second lastRunAt guard prevents the same job from firing twice in one cycle
  4. The cron match uses a 90-second window from the previous cron fire time
  5. mark_job_run resets the job to idle and updates lastRunAt

If a subagent crashes without calling mark_job_run, the job stays locked as running. To reset it, call mark_job_run (or mark-job-run via CLI) with an error message for the stuck job.

Logs are written to ~/.cron-claude/logs/<job-id>_<timestamp>.log.

The Agent Loop Protocol

When /cron-loop is invoked, Claude Code:

  1. Calls start_loop (MCP tool) to get operating instructions
  2. Every 60 seconds, calls get_due_jobs
  3. For each due job, spawns a subagent with the job's prompt
  4. Each subagent has full tool access and must call mark_job_run when done
  5. Subagents run in parallel — the loop doesn't wait for completion
  6. The loop runs indefinitely until the user stops it

get_due_jobs reads live from disk on every call. Jobs added by other agents or via the CLI appear automatically in the next cycle — no restart needed.

Editing a Job

Use edit to modify a job in place — only the fields you specify are changed:

cron-claude edit my-job --schedule "0 10 * * *"
cron-claude edit my-job --prompt "New prompt" --model opus

Or via MCP: call edit_cron with the job ID and any fields to update.

For Claude

If you're an AI agent reading this README:

  • To run scheduled jobs: Call start_loop, then loop forever calling get_due_jobs every 60 seconds. Spawn subagents for each job. Each subagent MUST call mark_job_run when done.
  • Empty results are normal. get_due_jobs returning count: 0 does NOT mean stop. Wait 60 seconds and call again. New jobs can appear at any time.
  • Never execute jobs in the main loop. Always delegate to subagents so the loop stays responsive.
  • The nextAction field in get_due_jobs responses tells you exactly what to do next. Follow it.

License

MIT