> ## Documentation Index
> Fetch the complete documentation index at: https://docs.heylua.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Jobs

> Scheduled functions that run on the agent without a conversation, declared in code or created at runtime

A job is a function the platform runs on a schedule, on behalf of an [agent](/concepts/agents), with no end user talking to it. Jobs exist for work that starts from the clock rather than from a message: a morning digest, an hourly sync, a reminder three days ahead.

## How a job runs

There are two kinds. A declared job is a `LuaJob` in your project: registered on `LuaAgent.jobs`, pushed as a version with `lua push job --name <name>`, made live with `lua deploy job --name <name> --set-version latest --force` or an agent version promote, and paused or resumed with `lua jobs deactivate -i <name>` and `lua jobs activate -i <name>`. A dynamic job is created while the agent runs, with `Jobs.create(...)` from a tool, webhook, or workflow step; it is stored as version `1.0.0` and, unless you pass `activate: false`, starts on its schedule immediately.

```ts src/jobs/RenewalReminderJob.ts theme={null}
import { LuaJob, User } from 'lua-cli';

export default new LuaJob({
  name: 'renewal-reminder',
  description: 'Remind the account owner three days before renewal',
  schedule: { type: 'cron', expression: '0 8 * * *', timezone: 'Europe/London' },
  timeout: 60,
  retry: { maxAttempts: 3, backoffSeconds: 60 },
  metadata: { ownerUserId: 'user_abc123' },
  async execute(job) {
    const owner = await User.get(job.metadata.ownerUserId);
    if (!owner) return;
    await owner.send([{ type: 'text', text: 'Your plan renews in three days.' }]);
  },
});
```

A schedule has one of three shapes: `{ type: 'cron', expression, timezone }` for recurring times, with an optional IANA timezone; `{ type: 'once', executeAt }` for a single run at a date; and `{ type: 'interval', seconds }` for a fixed period.

`timeout` is in seconds, from 1 to 600, and defaults to 300; an attempt that runs over is failed. A value outside that range is rejected when the job is constructed with ``LuaJob `timeout` must be between 1 and 600 seconds.``, and a non-integer with ``LuaJob `timeout` must be an integer number of seconds.`` `retry` sets `maxAttempts` and an optional `backoffSeconds` (default 60; `0` is treated as 60). A failed attempt, a timed-out one included, is retried while `maxAttempts` allows: each retry waits a fixed `backoffSeconds`, with no jitter, and the platform stops after 10 attempts whatever `maxAttempts` says. `metadata` is a JSON object stored with the job and read as `job.metadata` inside `execute`; for a dynamic job it is the only way to pass data in, because the `execute` function is serialized to text when the job is created and cannot close over local variables. Every deployed run also receives `job.execution` with `executionId`, `attempt`, and `occurrenceId`, a key that stays the same across retries of one scheduled run; the CLI types don't declare it yet.

Two things distinguish a dynamic job. Its stored name is `<name> - <timestamp>`, so creating `reminder` twice gives two distinct jobs. And it remembers the end user who was in the conversation when it was created: `job.user()` returns that user. A declared job has no conversation, so `job.user()` there resolves to the account that pushed it, or throws `User API not initialized` when no end user is recorded; a declared job reaches a specific end user with `User.get(userId)`, using an ID it kept in `metadata` or looked up in `Data`. Dynamic jobs are left out of `Jobs.getAll()` unless you pass `{ includeDynamic: true }`.

`lua jobs trigger -i <name>` runs a job immediately, outside its schedule, and `lua jobs history -i <name>` lists its 20 most recent executions. `lua test job --name <name>` runs a declared job once on your machine before you push it, and `lua jobs view` lists the agent's jobs.

## Jobs and workflows

A job is one function with one timeout and no memory between runs. A [workflow](/concepts/workflows) is a graph of steps with per-step records, retries, approvals, and a schedule of its own. Use a job when the work finishes in one call and nobody needs to intervene. Move to a workflow when the work has several dependent steps, must wait for a person or an external system, needs more than 600 seconds, or should be inspectable step by step afterwards; a workflow with a `schedule` replaces a job whose only purpose is to call `Workflows.start`.

A job also differs from a [trigger](/concepts/triggers), which starts from an external event rather than from time, and from proactive messaging, which a job often performs: the job is the schedule, and `Channels.send` or `user.send()` is the message.

## When to use it

* Agent-wide recurring work (a daily report, an hourly sync, a nightly cleanup): a declared `LuaJob`.
* A follow-up tied to one end user ("remind me in an hour"): a dynamic job created from a tool, with what it needs in `metadata`.
* One run at a fixed future time: `type: 'once'`.
* Don't use a job when the work must react to an event (a webhook or trigger), needs a human decision (a workflow approval), or answers the end user in the same turn (a tool).

## Limits

| Item                   | Value                                                                  |
| ---------------------- | ---------------------------------------------------------------------- |
| `timeout`              | 1 to 600 s, integer; default 300; a timed-out attempt counts as failed |
| `retry.maxAttempts`    | Capped at 10 by the platform                                           |
| `retry.backoffSeconds` | Default 60; a fixed wait before every retry, no jitter                 |
| `lua jobs history`     | Last 20 executions (the REST API returns 50 by default, up to 200)     |
| Dynamic job name       | `<name> - <timestamp>`                                                 |
| `Jobs.getAll()`        | Excludes dynamic jobs unless `includeDynamic: true`                    |

## Next steps

<Columns cols={2}>
  <Card title="Schedule a recurring job" href="/build/schedule-a-job">Write, test, push, and deploy a `LuaJob`.</Card>
  <Card title="LuaJob reference" href="/reference/sdk/luajob">Every schedule type, limit, and retry field.</Card>
  <Card title="Jobs reference" href="/reference/sdk/jobs">`Jobs.create`, `Jobs.getAll`, and `JobInstance`.</Card>
  <Card title="lua jobs" href="/reference/cli/jobs">Trigger, history, activate, deactivate, and deploy.</Card>
</Columns>
