Skip to content

feat: add per-entity heartbeat cadence overrides (snooze + proactive mode) #31

Description

@keyoku-bot

Summary

Add a first-class way for a user/entity to temporarily tune heartbeat interruption behavior — both less proactive ("I'm busy, don't bother me until tomorrow morning") and more proactive ("keep suggesting things, I'm open to ideas right now").

The current engine has strong heartbeat decision logic (urgency tiers, cooldowns, nudge backoff, time-period suppression, quiet hours), but there is no explicit per-entity override for short-lived interruption preference.

Problem

Right now heartbeat behavior is shaped by:

  • watcher scheduling / adaptive intervals
  • urgency tiers and cooldowns
  • time-period suppression (working, evening, late_night, quiet)
  • nudge silence thresholds / backoff
  • quiet hours and deadline/scheduled bypass rules

That gives good default behavior, but it does not let the user say things like:

  • "I'm busy now, don't bother me until tomorrow morning"
  • "Pause suggestions for 4 hours"
  • "Be more proactive today"
  • "Keep suggesting stuff, I want more ideas right now"

These are not exactly the same as quiet hours, and they are not well-modeled as only changing the watcher tick interval. The real product need is a temporary per-entity interruption policy override that influences heartbeat decisions.

Proposed scope

Introduce a persisted per-entity cadence override with expiry.

Override modes

  1. Suppress / snooze mode

    • reduce or suppress low/normal interruption behavior until a specified time
    • examples:
      • busy
      • pause_suggestions
      • snooze_until
  2. Proactive mode

    • temporarily increase willingness to suggest / nudge / act on non-urgent signals
    • examples:
      • proactive
      • high_touch
      • more_ideas

Key design requirements

  • override is scoped per entity (not global)
  • override is temporary and has an expiry timestamp
  • override is evaluated in the heartbeat decision layer, not only in watcher scheduling
  • urgent/immediate signals still have a defined breakout path
  • behavior is explainable in decision/debug output
  • override expiration is automatic

Recommended design direction

Primary control should live in heartbeat decision logic, with watcher cadence changes as an optional secondary optimization.

Why:

  • changing only the watcher interval is too coarse
  • decision logic already owns interruption semantics (cooldowns, nudge gating, urgency, suppression reasons)
  • a per-entity override belongs closer to evaluateShouldAct / nudge suppression than to process-level scheduling alone

A good first implementation would:

  • persist a cadence override record per entity
  • load it during heartbeat evaluation
  • modify cooldown / nudge / suggestion behavior based on mode
  • preserve urgent break-through behavior for scheduled/deadline/critical cases
  • expose the active override in debug/developer-trace surfaces

Suggested behavior

Suppress / snooze

When active:

  • suppress low / normal suggestion paths
  • likely suppress nudge flow entirely
  • optionally suppress elevated signals depending on configuration
  • do not suppress immediate/critical signals by default

Examples:

  • busy until tomorrow 9am
  • do not bother me for 3 hours
  • pause suggestions today

Proactive

When active:

  • shorten cooldown multipliers
  • lower the bar for surfacing suggestions
  • make nudge logic more willing during valid time periods
  • still respect hard safety/quiet-hour boundaries unless explicitly designed otherwise

Examples:

  • be more proactive today
  • keep surfacing ideas this afternoon
  • I want more nudges right now

Non-goals

  • full natural-language parsing in this issue
  • replacing quiet hours
  • suppressing critical deadline/scheduled signals with no escape hatch
  • a permanent learned personality/preference system
  • watcher-only interval tuning without decision-layer integration

Likely implementation areas

  • heartbeat_decide.go
    • apply override in evaluateShouldAct
    • integrate with cooldown / suppression / nudge decisions
  • heartbeat_options.go
    • add option plumbing as needed for tests / API path
  • watcher.go
    • optional secondary optimization if per-entity cadence should influence scheduling
  • storage/*
    • persist active cadence override with expiry
  • cmd/keyoku-server/handlers*.go
    • API surface for set/get/clear override
  • debug / trace response types
    • expose active override in developer-facing diagnostics

Open design questions

  1. Should busy/snooze suppress only low/normal, or also elevated?
  2. Should proactive mode adjust only cooldowns, or also time-period suppression / nudge thresholds?
  3. Should the initial API be explicit/structured (recommended), with natural-language mapping handled elsewhere?
  4. Should watcher scheduling eventually become entity-aware, or is decision-layer control sufficient for v1?

Acceptance criteria

  • Can set a per-entity cadence override with an expiry
  • Can clear / inspect the current override
  • Heartbeat decision logic changes behavior while override is active
  • Immediate/critical signals still break through according to documented rules
  • Override expires automatically and behavior returns to normal
  • Debug/developer-trace output makes the active override visible
  • Tests cover:
    • suppressive mode reducing interruptions
    • proactive mode increasing willingness to surface suggestions
    • expiry behavior
    • urgent breakout behavior

Notes

This feels adjacent to heartbeat reflection / personalization work, but it is narrower and operationally useful on its own: it gives users a direct, temporary control over how interruptive Keyoku should be without forcing them to reconfigure global watcher defaults.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions