Personality Engine
Six-system behavior engine that makes any OpenClaw agent feel alive. Editorial voice injects opinions. Selective silence knows when NOT to talk. Variable timing scores urgency with time-of-day awareness. Micro-initiations send ambient pings. Context buffer enables back-references to earlier messages. Response tracker adapts to engagement patterns. Domain-agnostic — works with trading agents, personal assistants, DevOps monitors, or any proactive agent. Part of the OpenClaw Prediction Market Trading Stack with default trading configuration.
安装 / 下载方式
TotalClaw CLI推荐
totalclaw install github:LeoYeAI~openclaw-master-skills~personality-enginecURL直接下载,无需登录
curl -fsSL https://skills.taituai.com/api/skills/github%3ALeoYeAI~openclaw-master-skills~personality-engine/file -o personality-engine.md# Personality Engine — 6-System Behavior Framework
**Goal**: Make any AI agent feel *alive* — opinions, awareness, judgment, memory, timing sense, and engagement sensitivity. Works with trading agents, notification systems, personal assistants, or any proactive agent. Not just data delivery.
## Architecture Overview
```
Trigger fires → engine.py orchestrator
↓
selective_silence (should we stay silent?)
↓
urgency_compute (how urgent is this 0.0-1.0?)
↓
engagement_modifier (adjust for user response patterns)
↓
variable_timing (schedule delivery based on urgency + time of day)
↓
context_buffer (add back-references to earlier messages today)
↓
editorial_voice (inject personality / opinions)
↓
dedup (avoid repeats within rolling window)
↓
send → iMessage (or other transport)
```
Plus two ambient systems:
- **micro_initiations**: Unprompted pings when conditions are met (quiet market, good streak, absence detected)
- **response_tracker**: Monitors engagement; adjusts urgency + suggests tuning
---
## System 1: Editorial Voice — Opinion Injection
**What**: Each trigger type gets a personality — opinions that vary based on market state, portfolio P&L, signal confidence.
**Per-trigger voice pools**:
### cross_platform (Kalshi vs Polymarket divergence)
- **Bullish divergence (>5%)**: "Big divergence. One of these markets is wrong."
- **Mild divergence (2-5%)**: "Mild divergence. Nothing screaming yet."
- **Stale divergence (6+ hours old)**: "Divergence is stale — markets may have already repriced."
### portfolio (user's holdings performance)
- **+15% or better**: "Good day. Portfolio's running."
- **+5% to +15%**: "Solid gains. Steady hand."
- **-5% to +5%**: "Flat day. Markets are grinding."
- **-5% to -15%**: "Rough patch. Check your stops."
- **-15% or worse**: "Heavy day. Buckle up for volatility."
### x_signals (social signal scanner)
- **Confidence ≥0.85 + matched position**: "Strong signal. This feels real."
- **Confidence 0.70-0.85**: "New signal on [topic]. Worth watching."
- **Confidence <0.70**: "Noise signal. Low confidence."
### edge (Kalshi edge detection)
- **Edge >3%**: "Fat edge. Worth a deep look."
- **Edge 1-3%**: "Mild edge. Keeping it on radar."
- **Edge <1%**: "Thin edge. Not worth the friction."
### morning (daily brief)
- **Monday**: "New week. Here's the lay of the land."
- **Friday**: "Friday rundown. What matters before the close."
- **Other**: "Daily digest."
### conflicts (overlapping triggers same hour)
- **2+ conflicts**: "Tomorrow's a mess. Multiple overlaps."
- **Lighter**: "Heads up — couple things hitting together."
**Customization point**: Add trigger types by extending the `VOICE_POOLS` dict in `editorial_voice.py`. Each entry maps `(trigger_name, market_state)` → list of opinion strings.
---
## System 2: Selective Silence — Knowing When NOT to Talk
**What**: Not every trigger fire deserves a message. Silent skips are explicit: "Skipped the brief — nothing worth your attention."
**Content quality checks per trigger**:
- **morning_is_boring**: If market vol <0.5%, no divergences, no edges → skip
- **divergence_is_stale**: If last message on this topic was <3 hours ago AND spread hasn't moved >0.5% → skip
- **signals_are_noise**: If all signals have confidence <0.65 AND no position matches → skip
- **edge_is_weak**: If all edges <1% → skip
- **portfolio_is_flat**: If daily P&L is -2% to +2% AND no major position changes → skip
**Silence cadence**:
- Max 1 silence message per day per user
- Only for *expected* triggers (morning, portfolio check, etc.)
- Never silence micro-initiations (those *are* the value)
- When silent, send explicit message: `"Skipped the brief — nothing worth your attention."`
**Customization point**: Adjust thresholds in `selective_silence.py`:
```python
SILENCE_THRESHOLDS = {
'vol_floor': 0.5, # % vol threshold for morning silence
'divergence_age_limit': 3, # hours
'signal_confidence_floor': 0.65,
'edge_floor': 1.0, # %
'portfolio_flat_range': 2.0 # % P&L range
}
```
---
## System 3: Variable Timing — Urgency Scoring + Time-of-Day Awareness
**What**: Schedule message delivery based on urgency (0.0-1.0) and time of day. A mild divergence at 6 AM gets sent immediately (threshold 0.9 before 7 AM). Same divergence at 10 PM gets held (threshold 0.35).
**Per-trigger urgency base**:
- **cross_platform**: (spread / 10%) * 0.6, capped at 1.0
- 5% spread = 0.3 urgency
- 10% spread = 0.6 urgency
- 15%+ spread = 1.0 urgency
- **portfolio**: (abs(daily_pnl) / 10%) * 0.7, capped at 1.0
- ±5% P&L = 0.35 urgency
- ±15% P&L = 1.0 urgency
- **x_signals**: (confidence * 0.8) + (position_match ? 0.2 : 0), capped at 1.0
- Confidence 0.85 + matched = 0.88 urgency
- Confidence 0.70 + no match = 0.56 urgency
- **edge**: (edge_size / 5%) * 0.8, capped at 1.0
- 2% edge = 0.32 urgency
- 5% edge = 0.8 urgency
- **meeting**: (1.0 - minutes_away / 120) capped at 1.0
- 30 min away = 0.75 urgency
- 5 min away = 0.96 urgency
**Time-of-day delivery thresholds**:
- **Before 7 AM**: threshold 0.90 (almost everything gets sent)
- **7 AM - 9 AM**: threshold 0.75 (morning crunch — moderate bar)
- **9 AM - 10 PM**: threshold 0.45 (daytime — lower bar, let alerts through)
- **10 PM - 11 PM**: threshold 0.35 (wind-down — only high urgency)
- **11 PM - 12 AM**: threshold 0.85 (late night — back to high bar)
- **12 AM - 7 AM**: threshold 0.90 (sleep time — very high bar)
**Modifiers**:
- **Weekend**: +0.10 urgency (weekends are boring, lower bar for engagement)
- **Clustering prevention**: If message sent <10 min ago, -0.20 urgency (space out messages)
- **Daily fatigue**: If 10+ messages today, +0.20 urgency threshold (user tired, fewer but higher-quality alerts)
- **Random jitter**: ±5% urgency (avoid machine-like precision)
**Send logic**:
```
adjusted_urgency = base_urgency * engagement_modifier ± jitter
if adjusted_urgency >= time_of_day_threshold:
schedule_send(now or delayed based on urgency)
else:
hold for next trigger
```
**Customization point**: Modify `TIME_OF_DAY_THRESHOLDS` and modifier constants in `variable_timing.py`:
```python
TIME_OF_DAY_THRESHOLDS = {
(0, 7): 0.90, # midnight - 7 AM
(7, 9): 0.75, # 7 - 9 AM
(9, 22): 0.45, # 9 AM - 10 PM
(22, 23): 0.35, # 10 - 11 PM
(23, 24): 0.85, # 11 PM - midnight
}
MODIFIERS = {
'weekend': 0.10,
'clustering_prevention': 0.20,
'daily_fatigue_step': 0.20,
}
```
---
## System 4: Micro-Initiations — Ambient Awareness Pings
**What**: Unprompted messages when conditions are met. Not triggered by market events — triggered by meta-state.
**Pools**:
| Pool | Trigger | Message |
|------|---------|---------|
| QUIET_MARKET | Vol <0.3% all day, no trades | "Quiet day. Markets are sleeping." |
| WEEKEND | Saturday/Sunday, no meetings | "Weekend vibes. You're off the hook." |
| MONDAY | Monday 6 AM, fresh week | "Monday morning. Week's open for business." |
| FRIDAY | Friday 4 PM, close approaching | "Friday close. Have a good weekend." |
| HOLIDAY_AWARENESS | US holiday today | "Holiday today. Markets are light." |
| GOOD_STREAK | 5+ consecutive +% days | "On a roll. Good week for you." |
| BAD_STREAK | 5+ consecutive -% days | "Rough stretch. It'll turn around." |
| ABSENCE | No user engagement 24+ hours | "Checking in. Things have been quiet." |
**Cadence**:
- Max 2 micro-initiations per week per user
- Skip on busy days (3+ regular alerts already sent that day)
- No repeats within 2 weeks (hash-based dedup: `sha256(pool + date)` in daily context)
**US Holiday calendar** (built-in awareness):
```python
HOLIDAYS = {
(1, 1): "New Year's Day",
(1, 20): "MLK Day",
(2, 17): "Presidents' Day",
(3, 17): "St. Patrick's Day",
(5, 26): "Memorial Day",
(7, 4): "