⏳ A lightweight task scheduler for executing local scripts using Notion database as remote UI. Intended for infrequent jobs. No more cron expressions. Only intuitive control.
-
Deno: Install Deno runtime.
-
Notion:
- Create an empty database. Find
NOTION_DATABASE_IDfrom its URL likehttps://www.notion.so/{workspace}/{database_id}?v={view_id} - Create an internal integration to obtain the secret
NOTION_API_KEY. Configure its "Content access" to enable it for your database. - Copy
.env-exampleas.envin this project directory and fill in yourNOTION_API_KEYandNOTION_DATABASE_ID.
- Create an empty database. Find
-
Local mode (Optional): If you want to bypass Notion and run the orchestrator locally, set
"local_mode": trueinlocal/config.jsoncand manage your jobs by manually editinglocal/queue.json. -
Run:
-
Polling mode:
deno task start --poll
Keep the orchestrator running in a loop. It will poll Notion database / local queue at a specified interval and execute due jobs.
To run continuously in the background, use process managers like PM2, or system services (e.g. systemd on Linux, Task Scheduler on Windows, launchd on macOS).
-
One-off mode:
deno task start --one-off
Execute a single cycle and exit. Ideal when using external schedulers like
cronor system services mentioned above (as timers).
-
-
Add jobs: The first run creates the schema for your Notion database. Add your first job by creating a Notion page (or a JSON entry in
local/queue.json).Required fields:
- script: filename in
scripts/(e.g.backup.sh,sync.ts). - run_at: scheduled time for the job (Date property in Notion, ISO 8601 format for local mode).
Optional fields:
- next_in: interval or macro for rescheduling. Supported format examples:
- Intervals:
1 day,2 weeks,3 months,1 year - Macros:
first monday of month,last day of month,2nd friday of month,last monday of december - None:
neveror empty (default)
- Intervals:
- args: arguments passed to the script, space-separated or JSON array. Default empty.
- deno_args: Deno runtime flags for ts / js scripts (e.g.
--allow-net), space-separated or JSON array. Default empty. - timeout_minutes: execution timeout in minutes. Default unlimited.
- end_on: expiration date / time for recurring jobs. Default no expiration.
- status: leave empty, will be set to
pendingafter validation. - name: human-friendly name for the job. Title of Notion page.
Managed fields: (updated by the orchestrator)
- name: updated with status emoji prefix.
- status: updated to
pending,running,success,failed, etc. - uid: auto-generated unique identifier for the job instance.
- prev_instance / next_instance: relations linking recurring jobs.
- page content: captures the stdout / stderr of the script execution.
- script: filename in
Customize the orchestrator's behavior by creating local/config.jsonc. See src/config.ts for all available options and their default values.
Key settings:
- local_mode: if
true, it bypasses Notion and useslocal/queue.json(default:false). - poll_minutes: how often to fetch and check for due jobs (default:
15). - scripts_dir: directory under project root for storing scripts (default:
scripts). - lookback_minutes: max age of missed jobs to still execute (default:
0for infinite). - runtimes: command mappings for file extensions (default:
deno runforjs/ts,uv runforpy,bashforsh). - env: environment variables to forward to scripts.
- cwd: custom working directories for specific scripts (default: scripts_dir setting).
- pending: Job is validated and waiting for
run_at. - running: ⏳ Script is executing.
- success: ✅ Script executed successfully with zero exit code.
- failed: ❌ Script returned non-zero exit code.
- error: 🚫 Job validation error (e.g. missing script, invalid schedule).
- missed:
‼️ Orchestrator was offline pastrun_atand lookback window. - disabled: 💤 Manually set. Disables the current job and prevents the next instance being scheduled.
- skipped: ⏩ Manually set. Skips the current instance but schedules the next instance as normal.
- Create database views to see jobs on the calendar and apply custom filters.
- Notion text properties automatically convert double dashes
--to—(em dash), creating trouble for command-line arguments. To revert it, pressCtrl / Cmd + Zimmediately after typing--.
This project is not affiliated with or endorsed by Notion Labs, Inc.
It was vibe-coded with human planning and review. Commit message prefixes indicate the model generating the code.
The name chronotion is a blend of Chronos (Ancient Greek personification of time) and Notion (the productivity software). The honorable cron utility shares this etymology with its shortened name. The h returns here as the manifestation of the collective hate for cron's cryptic syntax and limited expressiveness /s. Incidentally, there existed a calendar app named Cron which was acquired by Notion and rebranded as Notion Calendar.