Skip to content

Decision Journal ability#259

Open
hassan1731996 wants to merge 10 commits intoopenhome-dev:devfrom
hassan1731996:feature/decision-journal
Open

Decision Journal ability#259
hassan1731996 wants to merge 10 commits intoopenhome-dev:devfrom
hassan1731996:feature/decision-journal

Conversation

@hassan1731996
Copy link
Copy Markdown
Contributor

What is Decision Journal?

A passive ability that silently captures the decisions you make in natural conversation — "I decided to take the startup job", "I am going with the Toyota", "I am torn between two offers" — and stores them with rich context.

Just talk naturally. No trigger word needed to log a decision. Then say "decision journal" anytime to review your queue, record how decisions turned out, run a reflective session, or hear patterns in how you decide.

Key Features

Passive Capture

  • Listens every 15 seconds, zero friction
  • Two-phase detection: fast keyword filter + LLM significance classifier
  • Filters out trivial choices ("I will grab coffee") and third-party decisions ("she decided to quit")
  • Captures both committed decisions and active deliberation ("I am torn between X and Y")
  • Smart dedup: 60% word-overlap prevents capturing the same decision twice
  • Persists across session disconnects

Decision Lifecycle Tracking

  • Every captured decision moves through: pending outcome → outcome recorded
  • Record outcomes as: good call, bad call, mixed, or too soon to tell
  • Capture a one-sentence reflection when recording outcomes
  • Stale-outcome nudge: gentle daily reminder after 14 days on HIGH significance decisions

Reflection Sessions

  • Guided 2-round reflective coaching per decision
  • LLM generates thoughtful, open-ended questions based on decision context
  • Responds with empathetic 2-3 sentence insight after each answer

Pattern Analysis

  • After 5+ decisions, synthesizes 2-3 concrete patterns in your decision-making style
  • Example: "You tend to act quickly on career decisions but overthink financial ones"
  • Injects insight into agent personality for organic follow-up

Smart Organization

  • Groups decisions by category: career / financial / health / relationship / personal / other
  • Highlights pending-outcome decisions in list view
  • Startup notification if 2+ decisions need outcomes on reconnect
  • Daily briefing on new day if unresolved decisions exist

Manual Add

  • Say "add a decision" to log manually with category and alternatives prompts
  • Dedup check prevents duplicates on manual adds too

How It Works Under the Hood

background.py (daemon)

  • Polls message history every 15 seconds
  • Phase 1: fast keyword scan across 30+ decision trigger phrases (no LLM cost)
  • SKIP_PHRASES pre-filter catches agent-directed questions and third-party decisions before Phase 1
  • Phase 2: LLM significance classifier — only significant personal decisions captured
  • Dedup check against active decisions (60%) + recent history (50%)
  • Handles queue overflow (max 50 active, archives to history)
  • Stale-outcome nudge block runs once per day (persisted via last_nudge_date)
  • Daily briefing block on day rollover
  • Startup notification on session connect if 2+ pending-outcome decisions
  • Personality injection capped at 3 per session
  • LLM rate-limited to 3 calls per 15s poll cycle

main.py (interactive skill)

  • Triggered by 20+ hotword variants
  • 8 intents: LIST, OUTCOME, REFLECT, PATTERN, ADD, HISTORY, STATS, CLEAR_ALL, TOGGLE
  • Smart decision selection: explicit number, ordinal word, keyword overlap, pending-outcome first
  • Outcome sentiment mapped from natural language ("great" → positive, "regret" → negative)
  • Pattern analysis requires minimum 5 decisions before running
  • Reflect handler caps at 2 exchanges per session to avoid over-coaching
  • All explore handlers reload fresh data to catch daemon additions
  • Confirmation loop for destructive clear operations

Testing Verified

  • Trivial decisions filtered (significance: low)
  • Agent-directed questions skipped (SKIP_PHRASES)
  • Third-party decisions skipped ("she decided", "they chose")
  • Dedup with 60% threshold on active + 50% on history
  • Outcome lifecycle: pending → recorded → archived
  • too_soon outcome keeps status pending for future nudge
  • Stale nudge fires max once per day (persisted)
  • Pattern analysis guards on fewer than 5 decisions
  • Session reconnect without re-processing old messages
  • Startup notification on reconnect with 2+ pending
  • Platform compliance: no print/asyncio.sleep/asyncio.create_task, resume_normal_flow in finally, all daemon speak calls preceded by send_interrupt_signal, Pydantic constraints respected, init.py empty

github-actions Bot and others added 2 commits April 21, 2026 05:10
Passive background daemon captures significant decisions from natural conversation
and stores them with category, alternatives, and significance. Interactive skill
enables outcome recording, guided reflection sessions, LLM-synthesized pattern
analysis, stale-outcome nudges after 14 days, and daily briefings. Two-phase
detection filters trivial and third-party decisions; 60% dedup prevents recapture.
@hassan1731996 hassan1731996 requested review from a team as code owners April 26, 2026 10:06
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 26, 2026

🔀 Branch Merge Check

PR direction: feature/decision-journaldev

Passedfeature/decision-journaldev is a valid merge direction

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 26, 2026

✅ Community PR Path Check — Passed

All changed files are inside the community/ folder. Looks good!

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 26, 2026

✅ Ability Validation Passed

📋 Validating: community/decision-journal
  ✅ All checks passed!

@github-actions github-actions Bot added the community-ability Community-contributed ability label Apr 26, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 26, 2026

🔍 Lint Results

🔧 Auto-formatted

Some files were automatically cleaned and formatted with autoflake + autopep8 and committed.

  • Unused imports removed (autoflake)
  • Unused variables removed (autoflake)
  • PEP8 formatting applied (autopep8)

__init__.py — Empty as expected

Files linted: community/decision-journal/background.py community/decision-journal/main.py

✅ Flake8 — Passed

✅ All checks passed!

hassan1731996 and others added 7 commits April 26, 2026 15:07
Use wait_for_complete_transcription() return value as trigger_text in
main.py so intent classification sees the actual current utterance —
get_full_message_history() does not include the current turn at call time.

Move nudge_checked_today and briefed_today flag-setting into finally
blocks in background.py so they are always set even when an exception
occurs, preventing the stale-nudge and daily-briefing blocks from
re-firing on every poll after an error.
1. Sentiment substring collision — _infer_outcome_sentiment now uses whole-word
   regex for all single-word keywords so "know" no longer matches "no" → negative,
   "yesterday" no longer matches "yes" → positive, etc. Multi-word phrases checked
   first as they are unambiguous.

2. Outcome auto-selection — _handle_outcome now requires genuine keyword overlap
   between hint and a decision summary before auto-picking. Generic trigger text
   ("record an outcome") no longer silently selects the first pending item when
   multiple decisions exist; the user is asked to pick instead.

3. ADD intent miss — _classify_intent now also catches "add/log + decision" so
   "add to my decision journal" routes correctly to ADD instead of falling to LIST.

4. Category inference gap — _handle_add now calls _infer_category(topic) as the
   default before asking the user, so the best available category is always set
   even when the user exits the category question.

5. Daily flags never reset — background.py tracks s["current_day"] and resets
   nudge_checked_today and briefed_today whenever the calendar date changes,
   ensuring stale-nudge and daily-briefing fire correctly on day 2+ of long sessions.
The check required both a clear keyword AND 'all' in the text.
'clear my decisions' is a registered hotword but contains no 'all',
so it fell through to LIST. Widened the match to also fire when the
text contains 'decision' or 'journal', which covers all natural
phrasings users would say within this skill.
Bug A — 'add a decision' mid-list routed to explore:
_handle_list reply router had no ADD branch so any unrecognised
reply fell to _handle_explore. Added ADD routing before the else.

Bug B — 'hear another' replayed the same decision:
_handle_explore had no awareness of what was just shown so asking
for 'another' when only one decision exists looped forever on the
same item. Added exclude_id parameter: when the user asks for
'another/different/next', the current decision is excluded from
candidates. If nothing remains, a friendly message is spoken and
the flow exits cleanly.

Bug C — 'clear my decisions' consumed as outcome/reflection answer:
Any hotword said while user_response() was waiting was treated as
an answer to the open question. Added _intercept_redirect() helper
that checks every user_response() reply for clear/add intent before
the answer is processed. Also guards the run_io_loop reflection step
so a redirect command is never saved as reflection text.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community-ability Community-contributed ability

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant