Like an arcade game's attract mode, this plugin enables your agent to proactively engage with idle communities - authentically, not annoyingly.
Intent > Structure
The character file defines who your agent IS. This plugin just gives them a reason to speak: "Room's been quiet. Get something going."
No marketing copy. No capability lists. Just the character being themselves.
import { attractPlugin } from '@elizaos/plugin-attract';
const character = {
plugins: [attractPlugin],
// ... your character config
};# .env - specify which rooms to monitor
ATTRACT_ALLOWED_ROOMS=welcome,generalThat's it. The plugin is enabled when installed.
- Room goes quiet (configurable idle time, default 4h)
- LLM vibe check: "Should I say something?"
- If YES → generate character-authentic message
- If NO or "..." → stay silent, retry later
ACTIVE ──(idle N hours)──> IDLE ──(cooldown ok)──> READY ──(attract sent)──> ACTIVE
↑ |
└──────────(2+ strikes)──────> MUTED <──────────────┘
ATTRACT_ALLOWED_ROOMS=welcome,general # Required: which rooms to monitor
ATTRACT_BLOCKED_ROOMS=admin-only # Optional: exclude specific rooms
ATTRACT_MIN_IDLE_HOURS=4 # Hours before room is "idle" (default: 4)
ATTRACT_COOLDOWN_HOURS=24 # Hours between attracts per room (default: 24)
ATTRACT_GLOBAL_DAILY_CAP=10 # Max attracts/day across all rooms (default: 10)
ATTRACT_STRIKE_LIMIT=2 # Strikes before auto-mute (default: 2)
ATTRACT_GRAVEYARD_DAYS=7 # Skip rooms dead longer than this (default: 7)
ATTRACT_NEGATIVE_KEYWORDS=shut up,stop # Triggers strikes (has defaults){
"settings": {
"attract": {
"allowedRooms": ["welcome", "general"],
"minIdleHours": 4,
"cooldownHours": 24,
"attractExamples": [
"dead chat needs a vibe - drop a request",
"queue's empty. someone feed me"
]
}
}
}attractExamples are voice hints for the LLM - not templates, just tone guidance.
| Risk | Mitigation |
|---|---|
| Spamming | Room allowlist required, cooldowns, daily cap |
| Bad timing | LLM vibe check before every attract |
| Annoying users | Strike system → auto-mute after 2 complaints |
| Dead channels | Graveyard protection skips rooms idle > 7 days |
| Multi-agent spam | LLM sees all messages including other bots; random jitter staggers timing |
| Wrong channels | Only GROUP, VOICE_GROUP, FEED - never DMs |
When running multiple agents monitoring the same rooms:
- Random jitter (0-30s) staggers when agents check
- LLM vibe check sees ALL messages in the channel, including other bots
If Bot A posts "anyone around?", Bot B's vibe check sees that and says NO.
@YourAgent reset attract mode # Clear strikes, unmute room
Or programmatically:
const attractService = runtime.getService('attract') as AttractService;
await attractService.resetRoom(roomId);Attract not triggering?
- Room in
ATTRACT_ALLOWED_ROOMS? - Room type is GROUP/VOICE_GROUP/FEED?
- Idle time >
ATTRACT_MIN_IDLE_HOURS? - Daily cap not reached?
Too many attracts?
- Lower
ATTRACT_GLOBAL_DAILY_CAP - Increase
ATTRACT_COOLDOWN_HOURS
Room auto-muted?
- Check strikes:
attractService.getRoomTracking(roomId) - Reset if false positive:
@YourAgent reset attract mode
plugin-attract/
├── src/
│ ├── index.ts # Plugin definition, task worker
│ ├── services/attract.ts # FSM, room tracking, sentiment
│ ├── actions/attract.ts # Validation, vibe check, generation
│ ├── actions/attractReset.ts
│ ├── evaluators/attractSentinel.ts # Monitors for negative feedback
│ ├── providers/attract.ts # Context for anti-repetition
│ └── templates/attract.ts # LLM prompts
└── __tests__/
MIT