Skip to main content
Abilities can run background threads alongside the main conversation. Add a file called background.py to any Ability folder and it runs automatically when the user connects to a Personality, staying alive as an independent thread for the entire session. No hotword trigger needed.

What this unlocks

  • Background polling — check a file or API on a timer
  • Proactive notifications — interrupt the conversation when something fires
  • Scheduled tasks — monitor for time-based events like alarms
  • Ambient monitoring — watch the live conversation for note-taking or summarization
This is additive. Existing main.py-only Abilities work exactly as before.

The four Ability categories

See Ability Types for the full breakdown. Background Daemons are one of the four.

File structure

Every Ability is built from one or two files, regardless of which category you pick in the Dashboard.

Example: Interactive Combined Ability

The background file must be named exactly background.py. No other filename will be detected by the platform.

main.py vs background.py

These are the most common sources of bugs when writing background daemons. Pay close attention.

New SDK methods

Usage

Background daemon code template

Copy this as your starting point for any background daemon. The call() signature has an extra background_daemon_mode parameter, but the CapabilityWorker constructor is the same as main.py.
Ordering matters. self.worker and self.background_daemon_mode must be set before calling CapabilityWorker(self). The constructor reads from self internally — if these aren’t set first, it will fail.

Key behaviors

Works in sleep mode

Background daemons continue running even when the Personality is in sleep mode. The daemon is an independent thread — it does not depend on the main conversation flow being active. This means your daemon can:
  • Monitor and transcribe ambient audio without a wake word
  • Process conversations happening around the device
  • Interject when it detects something relevant (via send_interrupt_signal())
  • Build RAG-style user context summaries in the background
The only requirement is that the daemon’s main function runs in a never-ending while True loop.

Multiple watchers

You can have multiple background daemons running simultaneously. Each is its own independent thread. For example, you could run an alarm daemon, a note-taking daemon, and a conversation summarizer all at the same time.

Full speak capability

Background daemons have the same ability to speak as interactive Abilities. A watcher can call speak(), play_audio(), text_to_speech(), and all other CapabilityWorker methods. Just call send_interrupt_signal() first to avoid audio overlap with any active conversation.

Coordination pattern

The primary way interactive and background components communicate is through shared persistent file storage. Both files read and write to the same user-scoped files.

Example: Alarm Ability

Sample alarms.json

Best practices

Session tasks ensure proper cleanup when the session ends. asyncio.sleep() can leak.
10–30 seconds is typical. For alarms, 15–30 seconds is fine.
The JSON file may not exist yet if main.py hasn’t been triggered. Always check_if_file_exists() first.
write_file() appends, which corrupts JSON. Always delete, then write the full object.
Background daemons run silently. editor_logging_handler is your only window into what they’re doing.
Otherwise audio overlaps, or the system tries to transcribe your daemon’s output as user input.
Background daemons work even when the Personality is asleep — but only if the main function is a never-ending while True loop.

Templates & resources

The Alarm template is the best reference for the Interactive Combined pattern. Study both main.py and background.py to understand how they coordinate.