Background Agents

Background agents are automations the agent sets up for you. Each one is a standing job — a prompt plus an optional schedule or event trigger — that runs on its own, without tying up your chat, and reports progress as it works. They're how Avi does anything recurring, long-running, deferred, or reactive.

Three words carry the whole model:

  • An agent is the template — the instructions, tools, triggers, and budget. A template doesn't succeed or fail; it's the definition the work runs from.
  • An instance is the instance — a continuable thread of work under an agent, with its own name, conversation, and state. The instance is the thing with a status: it's active, it needs you, it succeeded, it failed, or you stopped it.
  • A session is one sitting — a single execution. Sessions are mechanical: one finishes, errors, times out, hits a limit, or is stopped; the instance's verdict never hangs on a single sitting.

Most agents have exactly one instance and you'll rarely think about the distinction. It matters the moment an agent fans out — one instance per customer, per repo, per email thread — because each instance carries its own story and its own verdict.

Creating one

You don't build background agents by hand — you ask for them in chat:

  • "Every morning at 7am, email me a summary of new GitHub issues."
  • "Check if our homepage is up every 15 minutes; page me if not."
  • "Research these five competitors in the background and write up what you find."
  • "Whenever a PR comes in on my repo, triage it — if it needs my review, make a task for it."
  • "Whenever my grandmother emails me, draft a warm reply."
  • "Ask everyone on the team for their shirt size today, then nudge whoever hasn't replied each morning until they all have."

The agent decides whether to answer you right away or hand the work to a background agent, sets the schedule, and confirms. There's deliberately no form to fill in: describe what you want and when, and adjust it the same way ("make that weekly instead", "stop the issue digest").

Agents from apps

Apps can ship ready-made agents. When an app that ships one is enabled in your project, its agents are offered to you — nothing starts running on its own. They appear right in the Background Agents panel alongside your own agents (marked "From the app"; the Source filter separates Created by you from From apps), and in Project Settings → Agents. Add one from either place and it becomes a normal background agent in your project from that point: it runs on its triggers, and you can message it, change its schedule, or stop it like any other. Remove it in Project Settings.

Two things stay the app's: an app agent's instructions, tools, model, and budgets are exactly what the app shipped — the panel shows them read-only — and they update automatically when the app updates. Triggers are yours: change the schedule or subscriptions on your copy any time. Disabling the app stops and removes its agents from your project; re-enabling offers them again.

Tool access

Every newly spawned background agent must declare config.tools, an array of runtime tool names. At run time, the agent receives only the intersection of that allowlist and the project's normally assembled toolset; system_agents-write and system_agents-delete are always removed even if named (a background agent never manages agents). An empty array creates a no-tools agent.

For compatibility, legacy agents with no config.tools key remain unrestricted. A present but malformed value fails closed to zero tools. Rescheduling can replace the allowlist with another array, while tools: null deletes the key and returns the agent to unrestricted access.

The Background Agents panel

Open the Background Agents tile in a project's right sidebar. The panel has two tabs:

Instances — the default view, and the one to watch: every instance in the project, across all your agents, each row showing the instance's name, the agent it belongs to, its state, and its last session. Filter by state (show only what Needs you, only Failed, only what's still Active…), search by name, and the list sorts what needs your attention to the top. Open an instance to see its sessions, its working state, and its instructions — and to message it, answer its question, or stop it.

Agents — the templates: everything you've created plus agents offered by apps, with their triggers and source. Open one to see its configuration (model, triggers, budgets, spend, instructions) and step into its instances from there. Templates don't have a status — a template is a definition, and definitions don't succeed or fail — so this tab is where you manage agents, while the Instances tab is where you follow the work.

Inside an instance:

  • Sessions lists every sitting, newest first — what triggered it, when, and a one-line outcome ("Done", "Error", "Timed out", "Stopped", "Didn't run"). Open a session for its full transcript — every reply and tool call inline — with live progress and a per-session stop while it executes.
  • State shows the instance's private working notes (see Working state).
  • Instructions is the instance's own brief, layered on the agent's instructions.
  • Stop instance ends it for good — see States.

Results also reach you the normal ways: anything an agent produces (notes, emails, messages) lands where it was sent, and its activity is folded into the project's Updates feed.

Messaging an instance

A standing instance isn't fire-and-forget — you can talk to it. Open it in the panel and type into the message box at the bottom ("also include closed PRs", "skip weekends from now on", "why did you email Sam twice?"), or just tell the assistant in chat ("tell the issue-digest agent to also cover the docs repo"). Either way the message lands in that instance's own working conversation:

  • If it's working right now, your message reaches the session(s) in flight — they change course mid-session instead of starting something new.
  • Otherwise it runs once right away to act on it.
  • Future sessions remember it too — a tweak sticks without recreating the agent.
  • A message can even change what triggers the agent ("also run whenever Bob emails me", "stop watching that repo") — the agent updates its own event or feed subscription in response.

Messaging a concluded instance resumes it — the same instance picks back up in the same thread, with your message as its next input (see States). Adding a new question to a finished job is exactly this: message the instance, don't start a duplicate.

When an instance needs you

Sometimes an instance hits a decision that's genuinely yours — "both Tuesday 2pm and Thursday 10am work for everyone; which do you prefer?", "this contact has two emails on file; which is current?" Instead of guessing or silently stalling, it asks:

  • The question lands in your Updates feed (and notifies you) as a "Needs you" item under the instance's own topic. Open it and answer right there — tap one of the offered choices, or type your own answer. The same question, with the same one-tap answer box, also shows on the instance in the Background Agents panel.
  • The instance shows Needs you in the panel until you answer, sorted to the top of the Instances list.
  • Your answer resumes the work immediately — it picks back up in the same thread, with your answer in hand. Replying in plainer ways works too: messaging the instance (in the panel or via chat: "tell the scheduler Tuesday works") counts as the answer.
  • Every question comes with a deadline and a stated fallback — what the instance will do if you never answer ("if I don't hear back in 3 days, I'll propose Tuesday 2pm"). An unanswered question quietly becomes that plan, never a stuck instance. The feed shows how each question resolved: answered, expired into its fallback, or withdrawn (the instance finished or was stopped first). A one-off that asked a question waits for the answer (or the deadline) before it wraps up.

Agents are told to ask sparingly — routine judgment calls stay theirs; questions are for decisions only you can make.

Instances

An agent is a template for work — its instructions, tools, and schedule. The work itself happens in instances — continuable threads under the agent, each with its own conversation, its own working state, its own sessions, and its own status. Every agent has at least its Primary instance; agents that fan out across many things — one per customer, one per repo, one per email address — grow one per slice. Instances run in parallel with each other; within an instance, sessions always run one at a time, in order, each picking up where the last left off. Mint more from the agent's instances list with New instance — give it an identity (an email address, company, repo) and its own instructions: the brief for that scope, layered on the agent's instructions in every one of its sessions and editable any time.

Instances name themselves. After an instance's first session it takes a short plain-language name for what it's actually doing — "Collecting shirt sizes from the team", "Watching the Acme deal thread" — and if the work shifts, the agent renames it so the list always reads like a list of jobs, not identifiers. You can rename one yourself too (open the instance and edit its name); its topic in the Updates feed follows the new name.

Working state

Long-running instances keep private working notes — where they left off in a long job, decisions they've made, and standing directives you've messaged them ("skip weekends from now on") — so nothing important is lost even as old conversation history is condensed over time. This state never touches your Tasks, Drive, or other apps; it belongs to the instance alone. You can inspect it any time under the agent's Instances tab — useful for seeing exactly what a months-old agent believes it's doing next.

States

The status belongs to the instance. An agent (a template) doesn't have one — it's a definition, and a definition can't fail. A session doesn't carry a verdict either — it's one sitting, and a bad sitting doesn't sink the instance. Every instance shows exactly one state, everywhere it appears — the Instances list, the instance's record, and the Updates feed all use the same vocabulary, and the list sorts what needs you above everything else:

  • Needs you — the instance asked you a question and is waiting on the answer (see When an instance needs you). This outranks every other state.
  • Working — a session is executing right now (you can watch it live).
  • Paused — the agent's daily credit budget is spent; new sessions wait for tomorrow. Resumes on its own (or ask in chat to raise the budget).
  • Active — live: watching its triggers or waiting on its schedule, nothing running at this moment.
  • Succeeded — done for good. A one-off instance succeeds when its work does; a standing one succeeds when it decides its job is complete ("watch for X, then report") or when you tell the assistant to mark it done.
  • Failed — done, and something went wrong. Failed instances always show why: the decisive error, or five failed sessions in a row.
  • Stopped — done because you chose to end it (the instance's Stop instance, or ask in chat). Not a failure — just your call.

Succeeded, Failed, and Stopped mean the instance is dormant — its schedule and triggers stop firing, and nothing runs on its own again. But a concluded instance isn't sealed: you can resume it, and the same instance continues — same thread, same working state, same topic in your feed. Message it (the panel's composer works on concluded instances: sending resumes it with your message), hit Resume instance on its record, or ask in chat. Resuming clears a failure and starts the reliability clock fresh; resuming an instance with a schedule arms the schedule again. This is deliberate: one job should live in one instance — resuming keeps search, the Updates feed, and the assistant all pointing at the same story instead of a trail of near-duplicate instances. There is no archive: concluded instances simply live under their states, and the state filter is how you see or skip them.

One instance concluding says nothing about its siblings: an agent watching fifty customers can have one instance fail while forty-nine keep going — the failure is that instance's verdict alone.

When an instance reaches a verdict — Succeeded or Failed — that always lands in the project's Updates feed too. The update's topic names the instance and its agent — "Collecting shirt sizes from the teamTeam assistant" — and its content is a one-line account of the outcome: "Succeeded: what it accomplished", or "Failed: why". You never have to open the panel to learn that a standing job finished or broke, or what it did. (Stopping an instance yourself doesn't post one — that's your choice, not news.)

Budgets

Every agent carries one credit budget — a daily ceiling (default $10) — so nothing can quietly run away, and there's exactly one number to reason about:

  • As a session approaches the day's remaining budget it's told to wind down: it finishes the item in hand, saves its progress, and ends cleanly. Big jobs make progress every day instead of failing mid-flight.
  • Once the day's budget is spent, new sessions are skipped until the next day, and a notice lands in your Updates feed so the pause is never silent. Two things are never lost to a pause: a one-time scheduled run and any message you send the agent — those wait and run once the pause lifts.
  • A session that ignores the wind-down and blows through the ceiling anyway is stopped and marked Failed with a budget-exceeded reason.

The daily budget is also the agent's throughput: an hourly sweep with a $2/day budget does exactly $2 of work a day, spread across sessions, and finishing sooner just means the later sessions are cheap no-ops. Ask in chat to raise or lower it.

Agents no longer expire on a timer — an instance lives until it concludes or you stop it. Budgets and the panel's per-agent cost display are what keep a forgotten agent from becoming a surprise.

Scheduling

Background agents support three kinds of schedule:

  • Recurring at a time of day — "every morning at 9am", "Mondays at 8". Runs on a cron schedule in your local timezone, so it stays correct across daylight-saving changes.
  • Recurring by interval — "every 2 hours". Minimum interval is one hour.
  • One-time — "tonight at 11pm", "in three hours". Runs once, then the agent is done.

An agent with no schedule runs only when spawned or when you hit Run now.

Starting now and staying scheduled

A schedule doesn't have to mean waiting: a two-phase job — "message everyone today, then nudge stragglers each morning" — kicks off its first run immediately and stays on the recurring schedule (often with an event subscription too, so it reacts the moment each reply lands). Just describe the whole job; the agent arms all of it. And if an agent is sitting on its first tick when it should have started already, say so ("kick it off now") — it runs immediately without disturbing the schedule.

Feed subscriptions

Besides (or instead of) a schedule, an agent can subscribe to the project's Updates feed, so it runs the moment something newsworthy lands there — whatever the source (GitHub, email, Slack, AWS, an app):

  • "Triage every PR on my repo" — runs whenever a pull-request update appears or gains activity in the feed, with that update's headline and latest activity as its input.
  • "When anything new lands in the feed, summarize it to Slack" — runs on every new update.

Because the trigger is the curated feed — not raw source events — the agent reacts to the same deduped, living stories you see in the Updates sidebar. Subscriptions can be narrowed by source ("only GitHub activity"), by a specific thing ("only PRs from acme/api"), or by headline keywords, and combined with a schedule (a daily digest that also reacts to PRs). Housekeeping changes that don't add news never wake an agent. If updates land while runs are in flight, they run in parallel up to the agent's concurrency limit (3 by default, adjustable per agent); beyond that they queue and run in order as slots free up. A per-agent hourly run cap keeps a noisy feed from running away.

One thing to know: the feed is curated. An editor decides what's newsworthy enough to appear there, so something low-key — a brief personal note, a routine notification — may never become a feed update at all, and a feed-subscribed agent won't run for it. When the agent must catch a specific occurrence every time, it uses an event subscription instead.

Event subscriptions

An agent can also subscribe directly to the project's event log — the raw record of everything Avi ingests (every email, chat message, calendar change, coding-task update, app event), before any curation:

  • "Whenever my grandmother emails me, draft a reply" — runs on every inbound email from her addresses, even a one-word hello.
  • "When Jane messages me, ping my phone" — runs per message from her handle, on any channel that carries it.
  • "When something lands in #deals, summarize it for me" — runs on posts in that chat channel.
  • "When a meeting with the Acme folks changes, re-check my prep doc" — runs on calendar activity involving those attendees.
  • "On every new support ticket, do a first-pass triage" — runs per ticket event, no editorial gate in between.

Event subscriptions match on the event's envelope, and the filters compose:

  • Type — what kind of event, with wildcards: inbound email, a chat message, a calendar change, a finished coding task.
  • From — the sender's email address(es) or chat handle(s). This is deliberately per-sender, not per-thread: replies get knocked out of threads all the time, but mail from jane@acme.com is mail from Jane wherever it lands. List every address the person writes from.
  • Involving — the person in any role: an email's to/cc, a calendar event's attendees.
  • Channel — the chat channel a message was posted in.
  • Provider — which service carried it ("avi", "slack", "google"). This matters for chat handles, which are only unique within a service: "jane" on Slack and "jane" on avi messages can be different people, so "when Jane messages me on Slack" pins both the handle and the provider. (Email addresses are globally unique, so they rarely need it.)

They're exact and predictable: if the matching event lands, the agent runs; if it doesn't, nothing runs and nothing is spent. That's also why narrow filters matter — every match is a run, and "every inbound email" includes the newsletters. When you name a person or a channel, the agent arms the filter to match just that; describe the trigger as precisely as you'd like the spend to be. Use event subscriptions whenever missing an occurrence isn't acceptable; use feed subscriptions when you want to react to the bigger, curated story. The same queueing and hourly run cap apply, and an agent can never trigger itself: neither the platform's internal events nor the agent's own edits (a note it updates, a task it creates) will re-fire its own subscription.

Webhooks

For triggers the platform doesn't ingest at all — a CI system, a form provider, a partner's outbound webhooks — an agent can be given its own inbound webhook: a secret URL that external systems POST payloads to. Each accepted delivery runs the agent once, with the payload in the run's input, riding the same concurrency and queueing as every other trigger (parallel up to the agent's limit, queued beyond it, hourly run cap as the brake).

Ask for it when creating the agent ("…and give it a webhook") or add one later; the URL is shown in chat when it's armed (ask again to re-display it) — treat it like a password. Delivery is at-least-once and POST-only: a sender that retries may deliver the same payload twice, so agents that act on webhook payloads should be told to skip what they've already handled. Turning the webhook off kills the URL immediately; turning it back on mints a new one (that's also how you rotate a leaked URL). Deliveries for a concluded instance are silently refused while it's dormant — external systems never resume an instance; resume it yourself and deliveries flow again.

Relationship to Tasks

Tasks are to-do items — they track work, they don't run it. Background agents are the engine: when you ask for anything automated, the agent spawns one. (If you had scheduled tasks from before this split, they were converted to background agents automatically — the task remains as a to-do, and its schedule lives on in the Background Agents panel.)

Good uses

  • Daily briefings ("every morning at 7am, email me a summary of new GitHub issues").
  • Monitoring ("every 15 minutes, check if our homepage is up; page me if not").
  • Reacting to activity ("triage every PR from my repo and make a task if it needs my review").
  • Weekly reports.
  • Ad-hoc "work on this in the background and come back with results" jobs.
  • Anything you'd otherwise have to remember to ask for again.