Skip to main content
A backend is where work runs when it does not run inline: queued tool calls, schedules, and agent turns. Three shipped backends implement the same contract — pick one, name its package in the manifest, and run a worker process against it.
Every registered backend needs the worker bus: TAI_BUS_REDIS_URL must be set, or boot is refused. Stacks sharing one Redis must also diverge on TAI_BUS_NAMESPACE (default tai).

arq

The default. Redis-only, no separate broker, and the backend the distribution bundle selects.
manifest.yml
Run the worker:
The worker’s queue name, burst mode, result retention, and poll delay are CLI flags, not environment variables. worker is the only tai backend subcommand this backend accepts — there is no beat or dashboard process, and anything else exits.
ARQ_MANIFEST_KEY, ARQ_TASK_TIMEOUT, and ARQ_TOOL_NAME_ARG mirror the host’s own BACKEND_ group. Change them in lockstep or the worker and the server stop agreeing.

Celery

Choose Celery when you already run RabbitMQ, or when you need beat and flower.
manifest.yml
The concurrency cap of one is load-bearing. Celery’s pool restart is advisory, so a wider prefork pool can miss the turnover confirmation that follows a live config change and turn a bus operation into a failure. Raise CELERY_WORKER_CONCURRENCY only on a deployment that never live-reloads, or move to a threads/gevent pool. TAI_BUS_APPLY_TIMEOUT (default 30.0) sets the confirmation budget.
On macOS, prefer the solo or threads pool — forking around the system resolver deadlocks. backend_list_failed_tasks is not implemented here: Celery keeps no queryable failed-task index.

RQ

Redis-only like arq, with a worker, a scheduler, and the RQ dashboard.
manifest.yml
RQ has no disabled-schedule state, so backend_list_schedules always reports a schedule as enabled, and disabling one deletes it. backend_registered_tasks and backend_list_failed_tasks are not implemented.

See also