Nova Admin Docs
Concepts

Proactivity (Scheduled Follow-ups)

How an agent schedules its own future follow-up. A one-shot, same-thread continuation via the schedule_follow_up tool. Channel-agnostic, deterministically pinned to the originating thread, gated by an editable config flag.

Proactivity lets an agent wake itself later in the same conversation, e.g. "check back in 2 minutes and tell me if the deploy finished." It is exposed as a single tool, schedule_follow_up, and is off by default.

What it is (and isn't)

schedule_follow_up is a tool, not an agent or a flow. It does not override a channel's manager/IC fleet. When the follow-up fires it re-enters the originating thread and is handled by the normal routing for that thread.

PrimitiveUse for
One-shot, "remind me later in this thread"schedule_follow_up tool (this page)Defer-and-continue in the same conversation
Recurring "every morning…"A cron flow (cron_manage / flow CRUD)Persisted, scheduled, governed
A real calendar eventThe calendar integration (gw_calendar_*)An event on someone's Google Calendar

The router correctly routes "schedule a follow-up" toward the calendar tool. To invoke proactivity, phrase it as a deferred re-check ("wait 2 minutes, then re-check this thread") or name the tool explicitly.

How it works

agent calls schedule_follow_up({ instruction, delayMinutes | runAt })
  → enqueues a Cloud Task (queue: flow-agent-continue) at runAt
  → at runAt, agentFollowUpHandler (OIDC-verified) fires:
      → asserts the outbound allowlist for the origin channel
      → re-dispatches the instruction into the SAME thread (humanInitiated=false)
      → the thread's normal agent runs and posts the result

The tool accepts no destination/channel/recipient parameter — the follow-up always re-dispatches into the originating thread, derived from the run's threadId/source. This is deliberate: it means an agent can never redirect a follow-up to a different channel or person, which is what keeps proactivity safe (see deterministic outbound).

Channel-agnostic

Because it keys off threadId + source and re-dispatches through the shared channel dispatcher, a follow-up fires back on whatever channel it came from:

  • @mention in a Slack thread → posts back into that Slack thread
  • comment on a Linear issue → posts back into that Linear thread
  • a web thread → continues that web thread

Safety rails

  1. No destination param. Pinned to the originating thread by construction.
  2. Outbound allowlist re-assert. Before any post, the handler checks isOutboundDestinationAllowed; if the origin channel is not allowlisted (e.g. #random), it aborts silently and posts nothing.
  3. Delay clamp. 1 minute to 30 days (the 30-day ceiling matches the Cloud Tasks schedule horizon). Longer-horizon reminders need a cron flow, not this tool.

Enabling it

Proactivity is gated by the editable config config/nova-proactivity (read via readEditableConfig, ~60s cache):

{
  "enabled": true,            // master switch, default false
  "allowedAgentIds": []       // empty ⇒ ALL agents; or scope: ["nova-product", "generalist"]
}
  • enabled: false (default) → the tool is never granted; agents have no self-scheduling capability.
  • allowedAgentIds: [] (empty) → granted to every agent.
  • allowedAgentIds: ["…"] → granted only to those agent ids. Grant the routing entry points (router, generalist) and/or specific channel agents. An @mention is often handled by generalist, not the channel-named agent, so scope accordingly.

The tool is injected at runtime by maybeGrantScheduleFollowUpTool; you do not edit each agent's tools[] array.

Tool parameters

ParamTypeNotes
instructionstring (required)What the agent should do when the follow-up fires, in the same thread.
delayMinutesnumberMinutes from now. Clamped to 1 to 43200 (30 days).
runAtISO stringAbsolute time. Same clamp. Use one of delayMinutes / runAt.

There is intentionally no channel, recipient, or destination field.

Examples

Slack — ping when a deploy finishes (in #nova-eng):

@nova wait 2 minutes, then re-check the deploy and reply in this thread with the status.

// the agent's tool call
schedule_follow_up({
  "delayMinutes": 2,
  "instruction": "Re-check whether the deploy finished; summarize status + any errors."
})
// → "Follow-up scheduled for 2026-06-29T17:25:00Z in this thread."
// 2 min later, the agent posts back into the same thread:
// "Deploy follow-up: platform live; Sentry shows 10 unresolved errors, …"

Support — watch a cert (in #nova-support):

@nova check this domain's cert every hour until it's issued, and tell me here when it goes ACTIVE.

DM works the same; the follow-up posts back into the DM thread.

Cost

A follow-up is one ordinary agent run re-dispatched into the thread. Typical cost (Sonnet, ~2 rounds incl. a status-check tool call) ≈ $0.03–0.10; bounded by the per-run cost cap. See service tiers and observability for spend tracking and the budget-policy enforcement that gates it.

Limitations

  • Same thread only, cannot deliver to a different channel, a specific member's DM, email, or an inbox. Those are deliberate enhancements that would each need allowlist/identity gating + HITL.
  • Max horizon 30 days (Cloud Tasks limit). Use a cron flow for longer or recurring schedules.
  • It can @mention a user inside the originating thread (instruction text is free-form); it just can't redirect delivery to them.

On this page