Use the jobs runtime when you want scheduled, delayed, or manually triggered background work:
term-llm serve jobs --port 8080Jobs V2 API#
Definitions:
POST /v2/jobs- create job definitionGET /v2/jobs- list job definitionsGET /v2/jobs/:id- get definitionPATCH /v2/jobs/:id- update definitionDELETE /v2/jobs/:id- delete definitionPOST /v2/jobs/:id/trigger- trigger manual runPOST /v2/jobs/:id/pause- disable schedulePOST /v2/jobs/:id/resume- re-enable schedule
Runs:
GET /v2/runs- list runs (optionaljob_id)GET /v2/runs/:id- get run detailsGET /v2/runs/:id/events- get run event timelinePOST /v2/runs/:id/cancel- cancel run
Jobs CLI#
Use the first-class CLI for interrogation and queue control:
# Point to a server (or set TERM_LLM_JOBS_SERVER / TERM_LLM_JOBS_TOKEN)
term-llm jobs --server http://127.0.0.1:8080 --token "$TOKEN" list
# Create/update from JSON or YAML
term-llm jobs create --file job.yaml
term-llm jobs update nightly-summary --file update.yaml
# Queue and control execution
term-llm jobs trigger nightly-summary
term-llm jobs pause nightly-summary
term-llm jobs resume nightly-summary
term-llm jobs delete nightly-summary --cancel-active
# Interrogate runs/events
term-llm jobs runs nightly-summary --limit 100
term-llm jobs run get run_abc123
term-llm jobs run events run_abc123
term-llm jobs run cancel run_abc123Trigger Types#
manual: run only when manually triggeredonce: delayed one-off run viatrigger_config.run_at(RFC3339)cron: recurring schedule viatrigger_config.expression+trigger_config.timezone
LLM job persistence and progressive state#
LLM jobs now persist a session trail to the normal sessions SQLite store by default.
LLM jobs must also declare runner_config.cwd. The jobs server may run many jobs
concurrently in one process, so LLM jobs never inherit the server process working
directory and never use a process-wide chdir. Instead, cwd is the run’s
canonical proposed primary workspace and the shell tool’s default exec.Cmd.Dir.
It does not grant file authority. Because jobs are headless, first non-yolo file/path
access inside that proposal fails closed unless the same persisted root session already
has a matching human confirmation or the exact canonical workspace was explicitly
remembered in an earlier interactive session; use explicit read_dir/write_dir
permissions for ordinary unattended jobs. Guardian cannot make the primary workspace
decision. Explicit yolo bypasses confirmation for tool access without prompting or
persisting authority.
That means each LLM run gets a stable session_id, and long-running progressive jobs no longer keep their best-so-far state only in memory.
Practical effects:
GET /v2/runs/:idreturnssession_idfor LLM runs- progressive LLM jobs update
responseduring execution with the latest progressive envelope - you can inspect the full message and tool history in the sessions DB using that
session_id
Default behavior is persistence on. If you explicitly do not want that, set:
{
"runner_type": "llm",
"runner_config": {
"agent_name": "developer",
"instructions": "Do the thing",
"cwd": "/srv/app",
"persist_session": false
}
}You can also provide your own session_id when an integration wants a stable external key:
{
"runner_type": "llm",
"runner_config": {
"agent_name": "developer",
"instructions": "Investigate the failing deploy and summarize it.",
"cwd": "/srv/app",
"session_id": "deploy-investigation-2026-03-14"
}
}Inspecting partial progressive output#
For progressive LLM jobs, the latest update_progress / finalize_progress envelope is written into the run record while the job is still running.
That gives you two inspection paths:
term-llm jobs run get <run-id>for the latest envelope and run metadataterm-llm sessions show <session>or direct SQLite inspection for the full persisted transcript
Retention#
Jobs v2 automatically prunes historical data to avoid unbounded disk growth:
- terminal runs older than 30 days are deleted
- event rows older than 30 days are deleted
- terminal runs are capped to 1000 per job (oldest dropped first)
Example: Daily Midnight (Cron)#
{
"name": "nightly-summary",
"enabled": true,
"runner_type": "llm",
"runner_config": {
"agent_name": "developer",
"instructions": "Summarize today's changes and write a short report.",
"cwd": "/srv/app"
},
"trigger_type": "cron",
"trigger_config": {
"expression": "0 0 * * *",
"timezone": "America/Los_Angeles"
},
"timeout_seconds": 900
}Example: One-Off Delayed Job#
{
"name": "run-once-at-midnight",
"enabled": true,
"runner_type": "program",
"runner_config": {
"command": "echo",
"args": ["hello from delayed run"]
},
"trigger_type": "once",
"trigger_config": {
"run_at": "2026-02-22T00:00:00-08:00"
},
"timeout_seconds": 60
}