Scheduled Personal Ops¶
This tutorial walks through examples/scheduled_ops/ — three scripts that run autonomous agents on cron-like schedules to handle recurring personal tasks. Together they demonstrate how to combine the Jarvis SDK, the scheduler CLI, and the Python TaskScheduler API to build a personal operations layer that runs in the background.
Prerequisites
- Python 3.10 or later
- OpenJarvis installed:
uv sync --extra devfrom the repository root - An inference engine running (Ollama with
qwen3:8bpulled, or a cloud API key) - For full cron expression support, install
croniter:uv add croniter
The Three Scripts¶
| Script | Agent | Tools | Default Schedule | Purpose |
|---|---|---|---|---|
daily_digest.py |
orchestrator |
web_search, think |
Daily 9:00 AM | Search and summarize top news for chosen topics |
code_review.py |
native_react |
git_log, git_diff, file_read, think |
Monday 8:00 AM | Review the past week of commits in a repository |
gym_scheduler.py |
orchestrator |
web_search, think |
MWF 6:00 AM | Check gym hours and class availability |
Each script follows the same SDK pattern: create a Jarvis instance, call j.ask() with an agent and tools, print the result, and close the instance. The schedule is managed externally by the OpenJarvis scheduler daemon.
Quick Start: Run Scripts Manually¶
Test each script without a running scheduler by invoking it directly:
# Morning news digest for AI and robotics
uv run python examples/scheduled_ops/daily_digest.py --topics "AI,robotics"
# Code review for the current repository (last 7 days of commits)
uv run python examples/scheduled_ops/code_review.py --repo-path .
# Gym schedule check
uv run python examples/scheduled_ops/gym_scheduler.py --gym "24 Hour Fitness"
All scripts accept --model and --engine flags:
uv run python examples/scheduled_ops/daily_digest.py \
--model qwen3:8b --engine ollama --topics "AI,finance"
How the Scheduler Works¶
graph TD
A[jarvis scheduler start] --> B[Scheduler Daemon]
B --> C{Cron trigger fires}
C -->|0 9 * * *| D[daily_digest.py]
C -->|0 8 * * 1| E[code_review.py]
C -->|0 6 * * 1,3,5| F[gym_scheduler.py]
D --> G[OrchestratorAgent]
E --> H[NativeReActAgent]
F --> G
G --> I[web_search + think]
H --> J[git_diff + git_log + file_read + think]
I --> K[Output / Channel]
J --> K
The scheduler daemon reads registered tasks from SQLite, fires them at the correct time, and passes the configured prompt to the agent. Each script can also be run directly — the scheduler is only needed for recurring, unattended operation.
Set Up Schedules with the CLI¶
Register each script as a recurring task using jarvis scheduler create:
# Morning digest every day at 9 AM
jarvis scheduler create "Run daily news digest" \
--type cron --value "0 9 * * *"
# Weekly code review every Monday at 8 AM
jarvis scheduler create "Run weekly code review" \
--type cron --value "0 8 * * 1"
# Gym check on Monday, Wednesday, Friday at 6 AM
jarvis scheduler create "Check gym schedule" \
--type cron --value "0 6 * * 1,3,5"
Then start the scheduler daemon in the foreground (or as a background service):
List registered tasks at any time:
Cron expression syntax
OpenJarvis uses standard five-field cron syntax: minute hour day-of-month month day-of-week. Install croniter (uv add croniter) for full expression support including ranges and step values. Without it, basic hour:minute patterns still work.
Configure Schedules with TOML¶
The schedules.toml file in examples/scheduled_ops/ defines all three schedules declaratively. This is convenient for version-controlling your personal ops configuration or sharing it across machines:
[schedules.daily_digest]
type = "cron"
value = "0 9 * * *"
description = "Morning news and social media digest"
script = "daily_digest.py"
[schedules.code_review]
type = "cron"
value = "0 8 * * 1"
description = "Weekly code review"
script = "code_review.py"
[schedules.gym_scheduler]
type = "cron"
value = "0 6 * * 1,3,5"
description = "Gym hours and class check"
script = "gym_scheduler.py"
Point your own tooling or a custom loader at this file to register tasks in bulk.
Register Tasks via the Python API¶
The gym_scheduler.py script includes a --register flag that demonstrates programmatic task registration using TaskScheduler directly:
The equivalent Python code:
from openjarvis.scheduler import TaskScheduler
from openjarvis.scheduler.store import SchedulerStore
store = SchedulerStore()
scheduler = TaskScheduler(store)
task = scheduler.create_task( # (1)!
prompt="Check gym schedule for 'Planet Fitness'",
schedule_type="cron",
schedule_value="0 6 * * 1,3,5",
agent="orchestrator",
tools="web_search,think",
)
print(f"Task registered: {task.id}")
print(f"Next run: {task.next_run}")
create_task()persists the task to SQLite and computes the next trigger time. The scheduler daemon picks it up without a restart.
The Daily Digest Script¶
The digest script is the simplest of the three. It builds a date-stamped prompt and passes it to an orchestrator with web_search and think:
from openjarvis import Jarvis
j = Jarvis() # uses defaults from ~/.openjarvis/config.toml
response = j.ask(
f"Today is {today}. Search and summarize the top news on: {topics}",
agent="orchestrator",
tools=["web_search", "think"],
)
j.close()
The orchestrator searches for each topic in a separate turn, uses think to synthesize across topics, and returns a structured digest with bullet-point summaries and a one-paragraph outlook.
Send Results to a Channel¶
To route script output to Slack or any other supported channel, pipe stdout through jarvis channel send:
uv run python examples/scheduled_ops/daily_digest.py \
--topics "AI,finance" | jarvis channel send slack
Or add channel output inside the script:
from openjarvis.channels import ChannelRegistry
channel = ChannelRegistry.create("slack", webhook_url="https://hooks.slack.com/...")
channel.send(response)
List all available channels:
Channel credentials
Live channel output requires channel-specific credentials. Run jarvis add slack (or the relevant provider) to set up the MCP server and credential store, then configure environment variables in your .env file before starting the scheduler daemon.
Customization Tips¶
- Change topics: Pass
--topics "finance,healthcare,sports"todaily_digest.pyfor a different digest. - Review window: Pass
--days 14tocode_review.pyfor a two-week review cycle instead of one week. - Swap agents: Replace
orchestratorwithnative_reactin any script to compare agent behavior on the same task. - Add file output: Append
"file_write"to thetoolslist and update the prompt to save reports to disk instead of printing them. - One-time tasks: Use
--type once --value "2026-04-01T09:00:00"withjarvis scheduler createfor non-recurring tasks.
See Also¶
- Architecture: Agents —
OrchestratorAgentandNativeReActAgentinternals - Architecture: Tools and Memory — tool registry and
ToolExecutor - Getting Started: Configuration — engine and model defaults