TaskPilot is a lightweight automation & task-scheduling toolkit for Python.
Define what should run and when in a simple YAML file, and TaskPilot takes
care of the cron parsing, scheduling loop, execution, error handling and
structured logging — with zero heavy dependencies (just PyYAML).
Think of it as a tiny, hackable cron daemon you can read in an afternoon and extend in minutes.
A self-contained dashboard that visualizes the example schedule in
examples/tasks.yaml: live countdown dials for the
next run of every task, an arm/standby toggle, a manual "run now" trigger and
a scrolling flight log.
Or run it locally — no build step, just open the file:
open docs/dashboard.html # macOS
start docs\dashboard.html # Windows- Real cron expressions —
*, ranges (1-5), lists (1,3,5), steps (*/15) and aliases (@hourly,@daily,@weekly,@monthly). - Pluggable actions — ship-with
log,shell,httpandwebhook, plus a one-line decorator API to register your own. - Config-driven — declare tasks in YAML or JSON; no code required for common automations.
- Friendly CLI —
list,next,run,serveandactionssubcommands. - Testable core — the scheduler is a pure function of the current time, so every behaviour is covered by fast, deterministic unit tests.
- Type-hinted & linted —
mypy+ruffclean, CI across Python 3.9–3.12.
git clone https://github.com/txltedxgod/taskpilot.git
cd taskpilot
pip install -e ".[dev]" # drop [dev] for a runtime-only installCreate a config (or use the provided examples/tasks.yaml):
tasks:
- name: heartbeat
schedule: "*/5 * * * *" # every 5 minutes
action: log
params:
message: "TaskPilot is alive"
- name: nightly-backup
schedule: "@daily" # every day at midnight
action: shell
params:
command: "tar czf /tmp/backup.tgz ./data"Then drive it from the CLI:
# See what is configured
taskpilot list -c examples/tasks.yaml
# Inspect the next scheduled run for each task (JSON)
taskpilot next -c examples/tasks.yaml
# Run a single task right now (great for debugging)
taskpilot run -c examples/tasks.yaml --task heartbeat
# Start the scheduling loop
taskpilot serve -c examples/tasks.yaml --poll 60Tip: add
--dry-runtorunto preview side-effectful actions safely.
Actions are just callables registered by name:
from taskpilot.actions.base import ActionContext, registry
@registry.register("greet")
def greet(context: ActionContext, who: str = "world") -> str:
return f"Hello, {who}!"Reference it from your config:
tasks:
- name: say-hi
schedule: "0 9 * * 1-5"
action: greet
params:
who: "team"from datetime import datetime
from taskpilot import CronSchedule, Task, Scheduler
task = Task(
name="tick",
schedule=CronSchedule.parse("*/5 * * * *"),
action="log",
params={"message": "tick"},
)
scheduler = Scheduler([task])
results = scheduler.run_pending(datetime.now())
for r in results:
print(r.as_dict())taskpilot/
├── src/taskpilot/
│ ├── cron.py # dependency-free cron parser + matcher
│ ├── models.py # Task / TaskResult dataclasses
│ ├── config.py # YAML/JSON loader
│ ├── runner.py # executes a task, captures results
│ ├── scheduler.py # the polling/scheduling loop
│ ├── cli.py # argparse-based command line
│ └── actions/ # built-in + registry-based actions
├── tests/ # pytest suite (cron, config, scheduler, actions)
├── examples/tasks.yaml # sample configuration
└── .github/workflows/ # CI: lint + type-check + tests (3.9–3.12)
ruff check . # lint
mypy # type-check
pytest --cov=taskpilot --cov-report=term-missingContributions are welcome — see CONTRIBUTING.md.
Released under the MIT License.