Skip to main content

Background AI system

TOW runs AI work through configurable Agents and durable Agent Runs.

Runtime shape​

The backend starts background AI work from the FastAPI lifespan in backend/app/main.py.

  1. Built-in Agents are seeded or refreshed.
  2. agent_run_queue.start() starts Agent Run workers.
  3. If operating_background_enabled is true, OperatingBackgroundRunner.run_forever() checks scheduled operating work.
  4. User actions such as check-ins, doc edits, chat turns, snapshots, roadmap generation, and ticket scans enqueue Agent Runs.
  5. Workers load the Agent's published version and run the generic Agent runner. Built-in platform workflows can delegate to deterministic service handlers after the Agent gate is resolved.

Agent Runs are database records, so queued, running, completed, and failed status is auditable across backend restarts.

Status flow​

Frontend status comes from GET /api/agent-runs. The frontend polls active queued and running runs for the signed-in user and shows recent failure counts.

Item responses that start background work include agent_runs for immediate UI indicators.

Agent gating​

Agent availability resolves through server, organisation, project, and user bindings. Any disabled binding disables the Agent. Schedules come from the most specific configured binding, then the Agent version trigger defaults.

Direct AI endpoints check the effective Agent before queuing work. Mixed actions save non-AI data when appropriate and skip the disabled AI follow-up.

See Agent configuration for the admin-facing model and built-in Agent catalog.

Agent Run catalog​

Agent keyTypical triggerTargetOutput
proactive_daily_reviewScheduled daily review and opening Today, only while the AI brief is enabled.daily_sessionUpdates proactive-review sessions and Inbox proposals.
operating_pulseScheduled interval pulse and opening or refreshing Today, only while the AI brief is enabled.daily_sessionUpdates Today pulse context.
today_checkin_processorProject Check-In submitted.daily_sessionCoaching, memory diffs, ticket automation, and proposals.
roadmap_proposal_generatorRoadmap generation request and scheduled daily suggestions for recently active organisations.daily_sessionRoadmap and epic proposals.
docs_memory_reviewerDoc create/update/archive/manual extract.docDoc indexing, references, embeddings, and memory diffs.
snapshot_generatorSnapshot generation request.snapshotSnapshot draft for review.
ticket_conflict_scannerManual ticket conflict scan and scheduled daily scan for recently seen users.ticket_conflicts, daily_sessionDuplicate/conflict proposals and nightly conflict scan summaries.
chat_memory_reviewerChat turn completed.raw_eventPending memory diffs.

AI brief: review and pulse​

The proactive daily review and the operating pulse feed the AI brief on Today. Both are off by default. While features.ai_brief_enabled is false, TOW generates neither: the background runner does not schedule them, opening or refreshing Today queues nothing, runs that were already queued finish as skipped without calling the model, and the AI brief widget is hidden from dashboards. A hidden widget stays in the saved dashboard layout and returns in place when the feature is enabled.

When ai_brief_enabled is true:

  • Opening Today queues whichever of the two is due for that user and scope.
  • Each background tick also queues a due review and pulse, for the organisation and for every active project, for users seen recently (see below).

Every pulse is an AI call per user and per scope on each interval, so the cost grows with the number of recently active users and their projects.

Scheduled AI work follows recent activity​

The background runner queues scheduled AI work only where someone has been seen in a browser session within operating_background_user_activity_window_days:

  • The nightly ticket conflict scan, and the review and pulse while the AI brief is enabled, are queued only for users seen within the window.
  • Scheduled roadmap suggestions are queued only for organisations that have at least one active member seen within the window.

Dormant accounts and organisations are skipped, and the per-tick user limit is spent on recently seen users. Goal reminders, the clean-up of old roadmap suggestions, and scheduled automation flows are not AI work and run regardless. Anything a person starts themselves, such as a manual conflict scan or roadmap generation, is unaffected.

Today reads only the current day's pulse. Hourly pulse sessions and their Agent Runs older than operating_pulse_retention_days are deleted by the background runner, whether or not the AI brief is enabled. Each tick deletes at most 5,000 of each and stops early after about 20 seconds, so an existing backlog drains over many ticks. A pulse that still has a queued or running Agent Run is never deleted. PostgreSQL reuses the freed space but does not return it to the operating system without a VACUUM FULL.

Operational controls​

SettingPurpose
operating_background_enabledEnables or disables the periodic operating background runner.
operating_background_interval_secondsControls how often the background runner scans for scheduled Agent work.
features.ai_brief_enabledTurns on the proactive daily review, the operating pulse, and the AI brief widget. Off by default.
operating_background_user_activity_window_daysHow recently a user must have been seen in a browser session for the background runner to queue scheduled AI work for them or their organisation. Default 7.
operating_pulse_retention_daysDays of hourly pulse sessions and their Agent Runs to keep. Default 30; 0 keeps everything.
ticket_conflict_scan_hour_utcFirst UTC hour when the nightly conflict scan may be queued.
ai_queue_max_concurrencyMaximum number of Agent Runs processed concurrently.
ai_queue_status_retention_secondsStatus retention window used by polling clients.
OPENAI_API_KEYRequired for OpenAI Responses and embedding calls.
openai_reasoning_modelDefault reasoning model for Agent work.
openai_fast_modelDefault model for structured JSON helper calls.
openai_title_modelOptional model used for generated chat titles.
openai_onboarding_modelOptional model used for website scan extraction during organisation onboarding.
openai_embedding_modelEmbedding model used for semantic retrieval and doc indexing.
max_tool_roundsMaximum tool-call rounds per AI response before the model must answer from available tool results.
chat_context_window_tokensOptional total chat token budget; defaults to the reasoning model's known context window.
chat_max_output_tokensOptional per-answer reserve and provider output cap; defaults to the reasoning model's known maximum and scales down with a smaller configured context window.
EXA_API_KEYEnables configured web search and scrape tools.

Troubleshooting​

SymptomWhat to check
Runs stay queuedConfirm the backend lifespan started and Agent Run workers are running. Check ai_queue_max_concurrency.
A run failedCheck /api/agent-runs, backend logs, and the persisted agent_runs.error value.
AI action is disabledCheck the effective Agent row in Server, Organisation, Project, or User Settings.
Expected output is missingCheck Agent Runs, Inbox, Memory Diffs, Today, snapshots, tickets, or roadmap proposals.
Nightly scans or roadmap suggestions never runConfirm background mode, user membership, UTC hour, the Agent's effective daily schedule, and that the user (or a member of the organisation) was seen within the activity window.
No AI brief, pulse, or proactive reviewExpected while features.ai_brief_enabled is false. When it is true, the background runner still skips users not seen within the activity window; opening Today prepares both for them.