Skip to main content
After this guide, your agent runs a function every morning at 09:00 in a timezone you choose, with no end user involved. A declared job is for agent-wide schedules; for a reminder tied to one end user, create a dynamic job from a tool instead (Create a job from a tool). Verified against lua-cli 3.33.0. Before you begin
  • A project created with lua init and signed in with lua auth configure (Install and sign in).
  • Any secret the job needs stored with lua env production -k <KEY> -v <value> (About environments).
1

Create the job

Add a file under src/jobs/. schedule takes a cron expression and an optional IANA timezone; timeout is in seconds, from 1 to 600 (default 300); retry gives a failed or timed-out attempt more tries: each retry waits a fixed backoffSeconds, and the platform stops after 10 attempts (Jobs reference).
src/jobs/DailyDigestJob.ts
A job runs outside any conversation: User.get() with no argument has nobody to return, and job.user() resolves to the user recorded on the job, which for a declared job is never an end user. Reach an end user with User.get(userId) and an ID you stored earlier (Execution contexts).
2

Register it on the agent

Only primitives referenced from LuaAgent are compiled.
src/index.ts
3

Run it once locally

lua test job compiles the project and runs execute on your machine straight away, ignoring the schedule; the platform APIs it calls are real.
Output
4

Release it

lua push uploads a version and changes nothing for end users; lua version create snapshots the agent; lua version promote <n> makes that snapshot live and is also the rollback path (Release an agent to production).
lua version create prints βœ“ Created v<n> (staged); in a script, n=$(lua version list --limit 1 --json --ci | jq -r '.[0].version') then lua version promote "$n". lua push all exits 0 even when a primitive fails; check its output for component(s) failed to push.
From the promote on, the job fires at its next scheduled tick in production. Pause it with lua jobs deactivate -i daily-digest and resume it with lua jobs activate -i daily-digest.
5

Verify

Run the job immediately instead of waiting for 09:00, then read its history.
trigger prints the execution ID and leaves the schedule unchanged. history prints πŸ“Š Execution History for daily-digest and the last 20 runs, newest first, each as a status line such as βœ… COMPLETED, then Started, Completed, Duration, and Result: with the first 100 characters of what execute returned. lua logs --type job --name daily-digest --limit 5 shows what the run logged.

Options you may need

Run once or at an interval

Two other schedule shapes exist: { type: 'once', executeAt: '2026-10-01T09:00:00Z' } runs a single time at a Date or ISO string, and { type: 'interval', seconds: 300 } runs every fixed period.

Create a job from a tool

Jobs.create makes a job while the agent runs, stores it as version 1.0.0, and starts it unless you pass activate: false. Its execute function is sent to the platform as source text, so it cannot read variables from the tool around it: put what it needs in metadata and read job.metadata inside. A dynamic job remembers the end user who was in the conversation, and job.user() returns them.
src/skills/tools/RemindMeTool.ts
The stored name is reminder - <timestamp> (reminder_<timestamp> when the tool runs under lua test), so every call creates a distinct job, and Jobs.getAll() includes dynamic jobs only with { includeDynamic: true }.

Deploy the job on its own

lua deploy job is the single-primitive shortcut: it creates and promotes an agent version scoped to that job, so the job goes live immediately and the version appears in lua version list like any other.

If it isn’t working

Cause lua test job only sees jobs registered on LuaAgent.jobs. Fix Import the job in src/index.ts, add it to jobs, and run the test again.
Cause A declared job has no current user, so User.get() without an argument has nothing to return. Fix Store the user ID when you learn it and call User.get(userId) inside the job; see Send proactive messages.
Cause Jobs.create serializes execute to text and sends nothing it closed over. Fix Pass the values in metadata and read job.metadata inside execute.

Next steps

About jobs

Declared and dynamic jobs, schedules, timeouts, and when a workflow fits better.

LuaJob reference

Every schedule type, limit, and retry field.

Jobs reference

Jobs.create, Jobs.getAll, and JobInstance.

lua jobs

Trigger, history, activate, deactivate, and deploy.