mirror of
https://github.com/open-jarvis/OpenJarvis.git
synced 2026-07-31 03:12:16 +00:00
Add four major components that bring NanoClaw's capabilities into the OpenJarvis framework as native, config-driven modules: - ClaudeCodeAgent: wraps @anthropic-ai/claude-code SDK via Node.js subprocess - WhatsAppBaileysChannel: bidirectional WhatsApp messaging via Baileys protocol - ContainerRunner/SandboxedAgent: Docker sandbox with mount security enforcement - TaskScheduler: cron/interval/once scheduling with SQLite persistence, MCP tools, CLI New config sections: [sandbox], [scheduler], [channel.whatsapp_baileys]. New CLI: jarvis scheduler create|list|pause|resume|cancel|logs|start. 46 files changed, ~5,867 lines. 2078 tests pass (36 skipped). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
241 lines
8.5 KiB
Markdown
241 lines
8.5 KiB
Markdown
# Task Scheduler
|
||
|
||
The task scheduler lets you run agent queries automatically on a schedule -- once at a future time, on a recurring interval, or via a cron expression. Scheduled tasks are persisted in SQLite so they survive process restarts, and execution is handled by a background daemon thread that polls for due tasks every 60 seconds.
|
||
|
||
!!! note "Optional component"
|
||
The scheduler is a standalone module (`openjarvis.scheduler`). It is not wired into the default `Jarvis` / `JarvisSystem` startup. You enable it explicitly via `SystemBuilder` or by starting the CLI daemon with `jarvis scheduler start`.
|
||
|
||
---
|
||
|
||
## Schedule Types
|
||
|
||
| `schedule_type` | `schedule_value` format | Example | Meaning |
|
||
|-----------------|------------------------------------|-----------------------------|-------------------------------------|
|
||
| `once` | ISO 8601 UTC datetime | `"2026-03-01T09:00:00Z"` | Run once at that timestamp |
|
||
| `interval` | Seconds as a string | `"3600"` | Run every hour, starting immediately |
|
||
| `cron` | Standard 5-field cron expression | `"0 9 * * 1-5"` | 09:00 UTC, Monday–Friday |
|
||
|
||
!!! tip "Cron support"
|
||
Full cron expression support requires `croniter` (`pip install croniter`). Without it, the scheduler uses a minimal built-in parser that handles simple `minute hour * * *` patterns only.
|
||
|
||
---
|
||
|
||
## CLI Commands
|
||
|
||
The `jarvis scheduler` subcommand group manages tasks and the daemon from the terminal.
|
||
|
||
### Start the daemon
|
||
|
||
```bash
|
||
jarvis scheduler start
|
||
```
|
||
|
||
Starts the background polling daemon. The daemon runs in the foreground until interrupted (++ctrl+c++). In production, run it under systemd or launchd (see [Deployment](../deployment/systemd.md)).
|
||
|
||
### Create a task
|
||
|
||
```bash
|
||
# Run once at a specific time
|
||
jarvis scheduler create \
|
||
--prompt "Generate the weekly summary report" \
|
||
--type once \
|
||
--value "2026-03-01T09:00:00Z"
|
||
|
||
# Run every hour
|
||
jarvis scheduler create \
|
||
--prompt "Check for new emails and summarize" \
|
||
--type interval \
|
||
--value "3600" \
|
||
--agent orchestrator \
|
||
--tools retrieval,think
|
||
|
||
# Run on a cron schedule
|
||
jarvis scheduler create \
|
||
--prompt "Summarize overnight logs" \
|
||
--type cron \
|
||
--value "0 8 * * 1-5"
|
||
```
|
||
|
||
### List tasks
|
||
|
||
```bash
|
||
# All tasks
|
||
jarvis scheduler list
|
||
|
||
# Active tasks only
|
||
jarvis scheduler list --status active
|
||
|
||
# Paused tasks
|
||
jarvis scheduler list --status paused
|
||
```
|
||
|
||
Example output:
|
||
|
||
```
|
||
ID AGENT TYPE VALUE STATUS NEXT RUN
|
||
a3f9b12c4d8e simple cron 0 8 * * 1-5 active 2026-02-26T08:00:00+00:00
|
||
b7c2e56f1a3d orchestr interval 3600 active 2026-02-25T14:05:00+00:00
|
||
```
|
||
|
||
### Pause and resume tasks
|
||
|
||
```bash
|
||
# Pause a running task
|
||
jarvis scheduler pause a3f9b12c4d8e
|
||
|
||
# Resume -- next_run is recomputed from the current time
|
||
jarvis scheduler resume a3f9b12c4d8e
|
||
```
|
||
|
||
### Cancel a task
|
||
|
||
```bash
|
||
# Permanently cancel (status -> "cancelled", next_run cleared)
|
||
jarvis scheduler cancel a3f9b12c4d8e
|
||
```
|
||
|
||
### View run logs
|
||
|
||
```bash
|
||
# Last 10 executions for a task
|
||
jarvis scheduler logs a3f9b12c4d8e
|
||
```
|
||
|
||
Example output:
|
||
|
||
```
|
||
Run 1: started=2026-02-25T08:00:01Z finished=2026-02-25T08:00:04Z success=True
|
||
Result: Overnight logs contain 3 warnings and no errors.
|
||
Run 2: started=2026-02-24T08:00:00Z finished=2026-02-24T08:00:05Z success=True
|
||
Result: Logs are clean.
|
||
```
|
||
|
||
---
|
||
|
||
## Python API
|
||
|
||
```python title="scheduler_example.py"
|
||
from openjarvis.scheduler.store import SchedulerStore
|
||
from openjarvis.scheduler.scheduler import TaskScheduler
|
||
|
||
# Set up storage
|
||
store = SchedulerStore(db_path="~/.openjarvis/scheduler.db") # (1)!
|
||
|
||
# Wire in a JarvisSystem for task execution
|
||
from openjarvis import Jarvis
|
||
jarvis = Jarvis()
|
||
|
||
scheduler = TaskScheduler(
|
||
store=store,
|
||
system=jarvis, # (2)!
|
||
poll_interval=60, # (3)!
|
||
)
|
||
|
||
# Create tasks
|
||
daily_summary = scheduler.create_task(
|
||
prompt="Summarize the latest news headlines",
|
||
schedule_type="cron",
|
||
schedule_value="0 8 * * *",
|
||
agent="simple",
|
||
)
|
||
print(f"Created task {daily_summary.id}, next run: {daily_summary.next_run}")
|
||
|
||
# List active tasks
|
||
for task in scheduler.list_tasks(status="active"):
|
||
print(f" {task.id}: {task.prompt} @ {task.next_run}")
|
||
|
||
# Manage task state
|
||
scheduler.pause_task(daily_summary.id)
|
||
scheduler.resume_task(daily_summary.id) # next_run recomputed from now
|
||
scheduler.cancel_task(daily_summary.id) # permanent
|
||
|
||
# Start the background thread
|
||
scheduler.start() # (4)!
|
||
|
||
# ... application runs ...
|
||
|
||
scheduler.stop()
|
||
jarvis.close()
|
||
```
|
||
|
||
1. SQLite database storing all task state and run logs.
|
||
2. The scheduler calls `system.ask(task.prompt, agent=task.agent, tools=...)` when a task is due. Pass `system=None` for a dry-run mode that logs what it would execute without calling the agent.
|
||
3. Seconds between polling cycles. Lower values increase responsiveness at the cost of more SQLite reads.
|
||
4. Starts a daemon thread named `"jarvis-scheduler"`. Daemon threads exit automatically when the main process exits.
|
||
|
||
---
|
||
|
||
## ScheduledTask Fields
|
||
|
||
Every task is represented as a `ScheduledTask` dataclass.
|
||
|
||
| Field | Type | Default | Description |
|
||
|------------------|-------------------|---------------|---------------------------------------------------|
|
||
| `id` | `str` | auto (16 hex) | Unique task identifier |
|
||
| `prompt` | `str` | -- | Query sent to the agent on execution |
|
||
| `schedule_type` | `str` | -- | `"cron"`, `"interval"`, or `"once"` |
|
||
| `schedule_value` | `str` | -- | Cron expression, interval seconds, or ISO datetime|
|
||
| `context_mode` | `str` | `"isolated"` | Execution context mode |
|
||
| `status` | `str` | `"active"` | `"active"`, `"paused"`, `"completed"`, `"cancelled"` |
|
||
| `next_run` | `str` or `None` | computed | ISO 8601 UTC datetime of the next execution |
|
||
| `last_run` | `str` or `None` | `None` | ISO 8601 UTC datetime of the last execution |
|
||
| `agent` | `str` | `"simple"` | Agent registry key to use for execution |
|
||
| `tools` | `str` | `""` | Comma-separated tool names for the agent |
|
||
| `metadata` | `dict` | `{}` | Arbitrary metadata for the task |
|
||
|
||
---
|
||
|
||
## Using Scheduler Tools with Agents
|
||
|
||
The five scheduler MCP tools (`schedule_task`, `list_scheduled_tasks`, `pause_scheduled_task`, `resume_scheduled_task`, `cancel_scheduled_task`) can be passed to any `ToolUsingAgent`, allowing an agent to schedule follow-up tasks autonomously.
|
||
|
||
```bash
|
||
# Let the orchestrator schedule its own follow-up
|
||
jarvis ask --agent orchestrator \
|
||
--tools schedule_task,list_scheduled_tasks \
|
||
"Research transformer architectures and schedule a daily summary at 8am"
|
||
```
|
||
|
||
```python
|
||
from openjarvis import Jarvis
|
||
|
||
j = Jarvis()
|
||
response = j.ask(
|
||
"Schedule a weekly digest of research papers every Monday at 9am",
|
||
agent="orchestrator",
|
||
tools=["schedule_task"],
|
||
)
|
||
print(response)
|
||
```
|
||
|
||
See [Scheduler Tools](tools.md#scheduler-tools) for full parameter reference.
|
||
|
||
---
|
||
|
||
## Configuration
|
||
|
||
Scheduler settings live in the `[scheduler]` section of `~/.openjarvis/config.toml`.
|
||
|
||
```toml title="~/.openjarvis/config.toml"
|
||
[scheduler]
|
||
enabled = false
|
||
db_path = "~/.openjarvis/scheduler.db"
|
||
poll_interval = 60
|
||
default_agent = "simple"
|
||
```
|
||
|
||
| Key | Type | Default | Description |
|
||
|------------------|--------|----------------------------------|--------------------------------------------|
|
||
| `enabled` | `bool` | `false` | Start the scheduler daemon automatically |
|
||
| `db_path` | `str` | `~/.openjarvis/scheduler.db` | SQLite database path |
|
||
| `poll_interval` | `int` | `60` | Seconds between polling cycles |
|
||
| `default_agent` | `str` | `"simple"` | Default agent for tasks that omit `agent` |
|
||
|
||
---
|
||
|
||
## See Also
|
||
|
||
- [Scheduler Tools reference](tools.md#scheduler-tools) -- MCP tool parameter details
|
||
- [Architecture: Agentic Logic](../architecture/agents.md) -- how the scheduler integrates with agents
|
||
- [Deployment: systemd](../deployment/systemd.md) -- running the scheduler as a system service
|