Skip to content

Agent jobs & delivery

Agent cron jobs with prompts, session targets, model override, allowed-tools, and channel delivery.

A cron job can run a shell command or invoke the Revka agent with a prompt. This page covers agent jobs — how to schedule a prompt, control which session and model it runs in, restrict the tools it may call, and deliver its output to a chat channel after every run.

Use an agent job whenever you want recurring work that needs reasoning or tools — a morning briefing, an alert triage, a scheduled summary posted to your team — rather than a fixed shell command. For the schedule shapes (cron, every, at) and expression syntax, see Cron overview & expressions. For the full CLI reference, see revka cron. For declaring jobs statically, see Declarative jobs & scheduler config.

When an agent job fires, Revka:

  1. Pulls relevant context from the memory store and prepends it to the prompt.
  2. Runs the agent in the configured session target with the configured model and allowed-tools allowlist.
  3. Records the result (status, duration, truncated output) in run history.
  4. If delivery is configured, scans the output for credential leaks and announces it to a channel.

Agent jobs skip the shell command-allowlist validation that shell jobs go through, but they are blocked in read-only autonomy mode and when rate-limited. See Autonomy levels & approvals.

The simplest agent job is a prompt on a schedule. With the CLI, the --agent flag treats the trailing argument as a prompt instead of a shell command:

Terminal window
revka cron add '0 9 * * 1-5' --agent 'Check server health and summarize'

With the cron_add agent tool, set job_type to "agent" (it is also inferred when only prompt is supplied):

{
"name": "morning-brief",
"schedule": { "kind": "cron", "expr": "0 9 * * 1-5", "tz": "America/New_York" },
"job_type": "agent",
"prompt": "Summarize overnight alerts"
}

An agent job runs in one of two session targets, set with the session_target field:

ValueBehavior
isolated (default)Each run starts in a fresh, blank context.
mainThe run shares the same session as your interactive chat.
{ "session_target": "isolated" }

Use main when a job should see recent conversation context — but be aware it can interfere with interactive use. isolated is recommended for most automated jobs.

By default an agent job uses your configured default model. Set the model field to override it per job with any provider/model string the provider router accepts:

{ "model": "anthropic/claude-opus-4-5" }
# Declarative form, in config.toml
[[cron.jobs]]
model = "anthropic/claude-opus-4-5"

Omit model to fall back to the default configured model.

The allowed_tools field restricts which tools the agent may call during the run. When set, only tools whose names appear in the list are available; when omitted (or empty), all tools remain available.

{ "allowed_tools": ["file_read", "web_search"] }

With the CLI, repeat --allowed-tool once per tool:

Terminal window
revka cron add '*/15 * * * *' --agent \
--allowed-tool file_read --allowed-tool web_search \
'Check server health'

After each run, Revka can deliver the job’s output to a chat channel. Configure this with the delivery object on cron_add or cron_update:

{
"delivery": {
"mode": "announce",
"channel": "discord",
"to": "1234567890",
"best_effort": true
}
}
FieldTypeDefaultMeaning
modestringnonenone (no delivery) or announce (send output to a channel)
channelstringTarget channel platform (required for announce)
tostringDestination identifier (required for announce)
best_effortbooltrueWhen false, a failed delivery marks the run as error even if the job itself succeeded

Supported channels: telegram, discord, slack, mattermost, signal, matrix, whatsapp, and qq. The matrix and whatsapp (WhatsApp Web) channels are feature-gated — the binary must be built with the channel-matrix or whatsapp-web Cargo feature, respectively. Using a feature-gated channel without the feature returns a clear error. See Connect a messaging channel and Channels overview.

The to value is the platform-native destination identifier — a Discord channel ID, a Telegram chat ID, a Slack channel name, a Matrix room ID, and so on. The channel itself must already be configured in config.toml; delivery reuses the channel’s existing credentials.

Before any output is sent to a channel, Revka scans it for credential leaks. If secrets are detected, each match is replaced with [REDACTED] and a warning is logged (with the channel, target, and detected patterns) before the message goes out. This redaction is enforced on every outbound delivery path — there is no way to bypass the scan. You do not need to configure anything; it is always on.

cron_add is the preferred primitive for scheduling agent-driven tasks and scheduled channel messages, because it supports agent jobs and channel delivery in a single call. A complete example — daily at 9:00 ET, summarize alerts, post to Discord:

{
"name": "morning-brief",
"schedule": { "kind": "cron", "expr": "0 9 * * 1-5", "tz": "America/New_York" },
"job_type": "agent",
"prompt": "Summarize overnight alerts and post to channel",
"session_target": "isolated",
"model": "anthropic/claude-opus-4-5",
"allowed_tools": ["file_read", "http_request"],
"delivery": { "mode": "announce", "channel": "discord", "to": "1234567890", "best_effort": true }
}

cron_add parameters relevant to agent jobs and delivery:

FieldRequiredNotes
scheduleyescron / at / every object (also tolerates a JSON-stringified object)
job_type"agent" or "shell"; inferred as "agent" when only prompt is given
promptfor agent jobsThe agent prompt
nameHuman-readable label
session_target"isolated" (default) or "main"
modelModel override string
allowed_toolsArray of tool names; empty/omitted = all tools
delivery{ mode, channel, to, best_effort }
delete_after_runDefaults to true for at schedules

The Cron API accepts the same fields in the POST /api/cron body, with one difference: schedule here is a string cron expression (not an object), so the gateway endpoint supports only cron schedules — for at or every, use cron_add or the CLI.

POST /api/cron
Authorization: Bearer <pairing-token>
Content-Type: application/json
{
"schedule": "0 9 * * 1-5",
"job_type": "agent",
"prompt": "Summarize overnight alerts and post to channel",
"session_target": "isolated",
"model": null,
"allowed_tools": null,
"delivery": { "mode": "announce", "channel": "telegram", "to": "123456", "best_effort": true }
}

A successful call returns {"status":"ok","job":{...}}.

Force-run a job on demand to test it without waiting for its schedule, then inspect the recorded output:

// cron_run
{ "job_id": "<uuid>" }
// cron_runs — recent history for one job
{ "job_id": "<uuid>", "limit": 10 }

cron_runs returns timestamps, status (ok / error), duration, and truncated output (500 characters per run in the tool response; the stored record holds up to 16 KB). The same history is available at GET /api/cron/:id/runs?limit=20. For storage limits and pruning, see Declarative jobs & scheduler config.