What are jobs?
A job is an autonomous work unit that runs without a human in the loop. Each job has a trigger (cron, chain, or manual), a prompt, an optional agent, and a budget. When the trigger fires, the engine assembles context, invokes the agent, and routes the output.
Jobs are extensions of type job. Like all extensions, they are data stored in SQLite — not compiled code. An agent can create a job mid-conversation and it will start firing on schedule immediately after being enabled.
What does a job look like?
Each job is a directory under jobs/ with two files:
jobs/daily-briefing/
job.yaml ← schema: trigger, agent, budget, outputs
prompt.md ← what the agent is asked to do
A minimal job.yaml:
name: daily-briefing description: Summarize news and send to Slack each morning. enabled: true trigger: type: cron schedule: “0 8 * * 1-5” agent: daemion priority: normal max_duration: 300 context:
- engram: “recent news topics” outputs:
- slack: “#morning-briefing”
Job schema fields
| Field | Type | Description |
|---|---|---|
name | string | Unique kebab-case identifier |
description | string | What this job does |
enabled | boolean | Whether the scheduler considers it |
trigger | object | cron, manual, or chain |
agent | string | Agent name to invoke (defaults to daemion) |
context | array | Additional context sources: Engram recall, file reads, or output from another job |
outputs | array | Where to send results: file, Engram, Slack, or chain to another job |
chains | array | Job names to fire after this job completes |
priority | string | low, normal, high, or urgent |
max_duration | number | Seconds before the job is cancelled |
Source: src/schema/job.ts
Trigger types
cron — fires on a standard 5-field cron schedule. The scheduler ticks every minute and evaluates all enabled jobs.
manual — only fires when explicitly invoked via POST /jobs/:name/run or the engine’s --run flag. Useful for on-demand work.
chain — fires automatically after a named parent job completes. Build multi-step pipelines by chaining jobs together.
How the engine runs jobs
The engine (src/core/engine.ts) runs on each scheduler tick:
- Discover all enabled jobs (from disk and SQLite extension jobs)
- Evaluate triggers — which jobs are due?
- For each due job: assemble context, invoke the agent with the prompt, route outputs
- Record the job run result (success, cost, duration) to SQLite
Each run is logged as a job run record so you can audit what fired, when, and at what cost.
POST /run/:job force-runs any job regardless of its trigger. You can also use the CLI: npx tsx src/core/engine.ts --run=daily-briefing.max_duration seconds and records the run as failed. The scheduler will attempt the job again on its next scheduled tick.type: chain with after: first-job-name. Alternatively, list the second job in the first job's chains array. Both work; the chain trigger approach is more explicit.Like all agent-created extensions, jobs have enabled: false by default. Enable via POST /extensions/:id/toggle or ask Daemion to enable it. A disabled job will never fire regardless of its cron schedule.
For the full autonomous work API — listing runs, triggering jobs, and viewing run history — see Autonomous Work API. For creating jobs as extensions, see Extending: Job.