Skip to main content
Use dynamic schedules when users choose recurring work, such as a weekly report they can pause or reschedule. Harnest stores each schedule for the active user. For deployment-wide work owned by your application, use Cron schedules. See the harnest.cron API reference for scheduling functions and CronJob methods. Scaffold a dynamic target with harnest add cron reminder --dynamic. It creates cron/reminder.py without a fixed schedule. --dynamic and --schedule are mutually exclusive. Configure shared task/cron storage, then create the user-owned schedule at runtime as shown below.

Setup

Register the same provider with @lifecycle.storage.tasks and @lifecycle.storage.cron (storage setup) and keep harnest serve . running. Expressions use five cron fields in UTC. harnest run does not activate schedules.

Functions and scheduled jobs

cron/ contains schedulable functions. Each stored job supplies a user, timing, arguments, and status; many jobs can target one function. Use cron.list() to inspect the current user’s jobs.

Create a schedule from a Tool

Declare the function once with @cron() in cron/, then select it by its filename without .py. Harnest creates its queued task automatically. No fixed schedule runs until managed code creates one:
1

Declare recurring work

cron/build_report.py
2

Create a schedule for the caller

tools/schedule_report.py
Names resolve to deployed @cron functions in the current application, including fixed schedules. Unknown targets or invalid arguments fail before storage. Choose a stable key for the user’s logical schedule. Repeating the same key and definition returns the existing job, even if paused or cancelled. Reusing the key with different settings conflicts; use update when the user intends to change that schedule.

Limit runs and failures

Pass max_runs to stop after that many occurrences have been queued. Pass max_consecutive_failures to stop after that many occurrences finish in failure. A successful occurrence resets the failure count. These are optional positive integers and are part of the schedule’s definition. The returned job exposes run_count and consecutive_failures.
The decorator’s max_retries controls retries of one occurrence. The schedule failure limit counts only its final failed outcome, after those retries. Reaching either schedule limit cancels future occurrences. Already queued or running work remains independent.

Continue an existing conversation

A dynamic cron job can carry an existing session ID in its arguments. Inside the scheduled task, call context.agent.open_session(session_id) and invoke the agent to add a later turn to that same conversation. The session must still exist and belong to the schedule’s user.
cron/reminder.py
The new turn is saved in that session’s transcript. A chat client must watch the session or deliver the resulting message through its own transport to alert the user immediately.

Reuse an existing Task

Use cron.create(task=existing_task, ...) for registered @task work. Follow the shared-library pattern so the tool and task export share the same callable; separately imported or redecorated copies are rejected.

Let users manage their schedules

Save the job ID to retrieve or change it later. cron.get() and cron.list() check the active user’s ownership on every call. Use pause for a temporary break. Resume starts future runs at the next matching UTC minute. Use cancel when the schedule should stop permanently but you want to retain its record, or delete to remove it. See CronJob methods and return behavior.
Pausing, cancelling, or deleting a schedule affects future occurrences. It does not stop tasks already queued or running. Cancelled schedules cannot be updated or resumed.

Ownership and execution caveats

Create and manage schedules inside a managed Harnest invocation with cron storage enabled. Standalone Python scripts and module imports do not have the active user and runtime required by these APIs. Dynamic schedules run as their creating user with fresh context and empty grants. If the scheduled task invokes an agent that needs governed capabilities, configure an explicit service principal. Keep arguments free of credentials; resolve credentials when work executes. Expressions use UTC, so explain the timezone to users and account for daylight-saving changes. Make task side effects idempotent because workers may retry. For validation failures and conflicting changes, see Cron errors.

API reference

Reference: harnest.agent.