🎁 Get the FREE AI Skills Starter Guide β€” Subscribe β†’
BytesAgainBytesAgain
πŸ¦€ ClawHub

Personality Engine

by @kingmadellc

Six-system behavior engine that makes any OpenClaw agent feel alive. Editorial voice injects opinions. Selective silence knows when NOT to talk. Variable tim...

Versionv1.1.0
Downloads588
Installs2
TERMINAL
clawhub install personality-engine

πŸ“– About This Skill


name: Personality Engine description: "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."

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:

    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:

    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):

    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): "Independence Day",
        (9, 1): "Labor Day",
        (10, 13): "Columbus Day",
        (11, 11): "Veterans Day",
        (11, 27): "Thanksgiving",
        (12, 25): "Christmas",
    }
    

    Customization point: Add pools in micro_initiations.py:

    MICRO_POOLS = {
        'QUIET_MARKET': {
            'condition': lambda ctx: ctx.vol < 0.3 and ctx.trade_count == 0,
            'messages': ["Quiet day. Markets are sleeping.", "No action today."],
        },
        'YOUR_POOL': {
            'condition': lambda ctx: your_logic_here(),
            'messages': ["Message 1", "Message 2"],
        }
    }
    


    System 5: Context Buffer β€” Daily Memory + Back-References

    What: Messages can reference earlier messages from today. "That Kalshi/PM divergence I flagged at 9 AM widened to 15%." This makes the agent feel like it's *thinking about* past events, not just firing isolated alerts.

    Per-trigger back-reference generation:

  • cross_platform: If divergence was flagged earlier, compare current spread to earlier spread
  • portfolio: If earlier portfolio message, show change since then
  • x_signals: If same signal fired earlier, acknowledge the repeat with new data
  • edge: Compare edge size to earlier edge on same market
  • Persistence: JSON file at ~/.openclaw/state/daily_context.json:

    {
      "date": "2026-03-09",
      "messages": [
        {
          "time": "09:15",
          "trigger": "cross_platform",
          "spread": 7.2,
          "markets": ["kalshi", "polymarket"],
          "message_id": "msg_abc123"
        },
        {
          "time": "14:30",
          "trigger": "portfolio",
          "pnl": 12.5,
          "message_id": "msg_def456"
        }
      ],
      "silence_count": 1,
      "micro_count": 0,
      "sent_count": 5
    }
    

    Auto-reset: At midnight (UTC), clear context for fresh day.

    Back-reference example:

    Earlier (9:15 AM):  "Mild divergence. Kalshi 52%, Poly 48%."
    Later (2:30 PM):    "That Kalshi/Poly spread I flagged this morning widened to 7% β€” now 55/48. Worth watching."
    

    Customization point: Add back-reference logic for new trigger types in context_buffer.py:

    def generate_backreference(trigger_type, current_data, history):
        if trigger_type == 'cross_platform':
            earlier = find_similar_trigger(history, 'cross_platform')
            if earlier:
                spread_change = current_data['spread'] - earlier['spread']
                return f"That spread I flagged {time_ago(earlier)} widened to {spread_change}%."
        return None
    


    System 6: Response Tracker β€” Engagement Adaptation

    What: Track user's response patterns. If user engages with 70%+ of messages, urgency stays high. If engagement <10%, adjust urgency down or suggest tuning.

    Metrics per trigger type:

  • sends: Count of messages sent
  • engagements: Count of messages user responded to (within 1-hour window)
  • ignores: Count of messages user didn't respond to
  • avg_response_time: Average time from message to user response (minutes)
  • 1-hour engagement window: If user responds to a message within 60 minutes, count it as engagement. After 60 min, assume ignored.

    Urgency modifier:

  • Engagement β‰₯70%: Multiply urgency by 1.3 (user likes these alerts, send more)
  • Engagement 40-70%: Urgency Γ— 1.0 (balanced)
  • Engagement <10%: Urgency Γ— 0.5 (user ignoring, tone it down)
  • Adaptation suggestion: After 10+ sends of a trigger type with <20% engagement, log:

    ⚠️ ADJUSTMENT SUGGESTION:
    Trigger: x_signals
    Sends: 12 | Engagement: 8% | Avg response time: Never

    Consider: β†’ Lower signal confidence floor (currently 0.65) β†’ Reduce frequency (increase silence thresholds) β†’ Check if message editorial voice is mismatched

    Persistence: ~/.openclaw/state/response_tracker.json:

    {
      "cross_platform": {
        "sends": 15,
        "engagements": 9,
        "ignores": 6,
        "avg_response_time": 23.5,
        "last_engagement": "2026-03-09T14:32:00Z"
      },
      "x_signals": {
        "sends": 12,
        "engagements": 1,
        "ignores": 11,
        "avg_response_time": null,
        "last_engagement": null
      }
    }
    

    Customization point: Adjust engagement thresholds and modifier multipliers in response_tracker.py:

    ENGAGEMENT_THRESHOLDS = {
        'high': 0.70,    # β‰₯70% β†’ 1.3x urgency
        'low': 0.10,     # <10% β†’ 0.5x urgency
    }
    URGENCY_MULTIPLIERS = {
        'high': 1.3,
        'low': 0.5,
    }
    SUGGESTION_TRIGGERS = {
        'min_sends': 10,
        'max_engagement_for_suggestion': 0.20,
    }
    


    OpenClaw Ecosystem Integration

    The Personality Engine works with any OpenClaw agent β€” it's domain-agnostic. Designed alongside the Prediction Market Trading Stack but applicable to any proactive agent that sends alerts, digests, or notifications.

    Install the complete Prediction Market Trading Stack:

    clawhub install kalshalyst kalshi-command-center polymarket-command-center prediction-market-arbiter xpulse portfolio-drift-monitor market-morning-brief personality-engine
    

    Integration with OpenClaw Agents

    Step 1: Import the engine

    from personality_engine.engine import PersonalityEngine

    engine = PersonalityEngine(user_id="user@example.com")

    Step 2: Hook into proactive trigger system

    In your agent's trigger handler (e.g., proactive_agent.py):

    async def fire_trigger(trigger_type, data):
        # Your normal trigger logic
        message_content = generate_message(trigger_type, data)

    # Pass through personality engine should_send, scheduled_message = await engine.process_trigger( trigger_type=trigger_type, raw_message=message_content, market_data=data, urgency_context={'vol': market_vol, 'pnl': portfolio_pnl, ...} )

    if should_send: if scheduled_message.delayed: schedule_send(scheduled_message.content, delay=scheduled_message.delay_seconds) else: send_now(scheduled_message.content) else: log_silence_skip(trigger_type)

    Step 3: Hook engagement tracker

    When user responds to a message:

    def handle_user_response(message_id, trigger_type, response_time_seconds):
        engine.response_tracker.log_engagement(trigger_type, response_time_seconds)
    

    Step 4: Run micro-initiations

    Add a separate cron job (every 30 min, low-overhead):

    async def micro_initiations_check():
        micro_message = await engine.check_micro_initiations(context={
            'vol': market_vol,
            'trade_count': trades_today,
            'user_absence_hours': hours_since_last_engagement,
            'portfolio_streak': consecutive_days,
        })

    if micro_message: send_now(micro_message)

    Step 5: Daily context reset

    At midnight, engine auto-resets context. Manually trigger if needed:

    engine.context_buffer.reset_daily()
    


    Use Cases Beyond Trading

    While the default voice pools and thresholds are tuned for prediction market trading, every system is designed for domain adaptation:

    | Domain | Editorial Voice | Silence Rules | Micro-Initiations | |--------|----------------|---------------|-------------------| | Trading (default) | Market commentary, edge opinions | Skip flat days, stale divergences | Quiet market, good/bad streaks | | Personal Assistant | Task prioritization opinions | Skip low-urgency reminders | "Quiet week. Inbox is clean." | | DevOps/Monitoring | Incident severity opinions | Skip routine health checks | "Uptime streak: 30 days." | | Sales/CRM | Deal stage opinions | Skip stale leads | "Pipeline looking thin this quarter." | | Content/Social | Engagement commentary | Skip low-performing posts | "Your last post is outperforming." |

    To adapt: swap the VOICE_POOLS dict in editorial_voice.py, update thresholds in selective_silence.py, and add domain-specific MICRO_POOLS in micro_initiations.py. See references/customization.md for full guide.


    File Structure

    personality-engine/
    β”œβ”€β”€ SKILL.md                           # This file
    β”œβ”€β”€ scripts/
    β”‚   β”œβ”€β”€ __init__.py
    β”‚   β”œβ”€β”€ engine.py                      # Main orchestrator
    β”‚   β”œβ”€β”€ editorial_voice.py             # Opinion injection
    β”‚   β”œβ”€β”€ selective_silence.py           # Content quality checks
    β”‚   β”œβ”€β”€ variable_timing.py             # Urgency + time-of-day
    β”‚   β”œβ”€β”€ micro_initiations.py           # Ambient pings
    β”‚   β”œβ”€β”€ context_buffer.py              # Daily memory
    β”‚   └── response_tracker.py            # Engagement tracking
    β”œβ”€β”€ references/
    β”‚   β”œβ”€β”€ systems-overview.md            # Architecture diagram + flow
    β”‚   └── customization.md               # Per-system customization guide
    └── examples/
        └── integration-example.py         # Copy-paste integration template
    


    Customization Quick-Start

    Scenario 1: Your agent fires 50 alerts/day and user ignores most

    1. Increase silence thresholds (selective_silence.py): Higher bars for what counts as "worth sending" 2. Lower variable_timing thresholds (variable_timing.py): Fewer messages slip through outside peak hours 3. Check editorial_voice: Opinions might not match user's style 4. Review response_tracker: Which trigger types have <20% engagement? Mute those.

    Scenario 2: Your agent never initiates, only reacts

    1. Customize micro_initiations pools: Add domain-specific conditions

       'LOW_VOLATILITY_OPPORTUNITY': {
           'condition': lambda ctx: ctx.vol < 0.2 and ctx.last_edge_size > 2.0,
           'messages': ["Calm market, good edge conditions. Might be time to scout."],
       }
       
    2. Tune MICRO_CADENCE: Increase max from 2/week to 3-4/week if user loves it

    Scenario 3: Your agent's opinions feel generic

    1. Open editorial_voice.py and expand voice pools per trigger 2. Add market-specific opinions:

       'VOICE_POOLS': {
           'cross_platform': {
               'big_divergence': [
                   "Big divergence. One of these markets is wrong.",
                   "Spreads are blown out. Arb opportunity.",
                   "Thick divergence β€” reality check time.",
               ],
               ...
       
    3. Vary by user profile (trader vs long-term investor) by passing user_profile to engine init


    Performance & State Management

    State files (user's home directory):

  • ~/.openclaw/state/daily_context.json (~5KB, resets daily)
  • ~/.openclaw/state/response_tracker.json (~2KB, persistent)
  • Engine overhead:

  • editorial_voice: <5ms (dict lookup)
  • selective_silence: <10ms (threshold comparisons)
  • variable_timing: <15ms (urgency calculation + time lookup)
  • micro_initiations: <20ms (condition evaluation)
  • context_buffer: <5ms (history lookup)
  • response_tracker: <5ms (metrics lookup)
  • Total pipeline: ~60ms per trigger (negligible for async message delivery)


    License

    Part of the OpenClaw portfolio. Use freely in any agent.


    Version History

    v1.0.0 (2026-03-09)

  • Initial 6-system framework
  • Default configuration tuned for prediction market trading agents
  • All systems designed for domain adaptation β€” swap voice pools, thresholds, and micro-initiation conditions for any use case

  • Feedback & Issues

    Found a bug? Have a feature request? Want to share results?

  • GitHub Issues: github.com/kingmadellc/openclaw-prediction-stack/issues
  • X/Twitter: @KingMadeLLC
  • Part of the OpenClaw Prediction Stack β€” the first prediction market skill suite on ClawHub.