From 3509d2988279153b014065e351b0c668f1ea6ecd Mon Sep 17 00:00:00 2001 From: Agent Date: Sat, 7 Feb 2026 14:01:52 +0000 Subject: [PATCH 01/10] Migrate brain-dump tasks to hex IDs --- memory/brain-dump.json | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/memory/brain-dump.json b/memory/brain-dump.json index 0bd1eee..d39c874 100644 --- a/memory/brain-dump.json +++ b/memory/brain-dump.json @@ -11,26 +11,24 @@ ], "tasks": [ { - "id": "forgejo-script", - "added": "2026-01-31", + "id": "b9d1d89e", + "added": "2026-02-07", "text": "Create script to auto-update workflows to Forgejo monorepo actions", - "context": "Monorepo is done, using GitHub actions as fallback for now", - "priority": "someday" + "priority": "someday", + "context": "Monorepo is done, using GitHub actions as fallback for now" }, { - "id": "forgejo-mcp-server", - "added": "2026-01-31", + "id": "af198211", + "added": "2026-02-07", "text": "Set up MCP server for Forgejo instance", - "context": "Phase 1: MCP server for interactive Claude web sessions (fork + PR workflow). Phase 2: Automated issue-solving pipeline with clarification comments.", "priority": "soon", - "lastNudged": "2026-02-07T13:59:36.313Z" + "context": "Phase 1: MCP server for interactive Claude web sessions (fork + PR workflow). Phase 2: Automated issue-solving pipeline with clarification comments." }, { - "id": "typo3-v13-gbv", - "added": "2026-02-01", + "id": "0902aaba", + "added": "2026-02-07", "text": "TYPO3 v13 upgrade for GBV", - "priority": "soon", - "lastNudged": "2026-02-07T13:59:36.313Z" + "priority": "soon" } ] } From 0352f8d04bb6f3c7fadbd68839e057297bd5c7fd Mon Sep 17 00:00:00 2001 From: Agent Date: Sat, 7 Feb 2026 14:07:57 +0000 Subject: [PATCH 02/10] brain-dump: add recurring management, remove --when filter, show full context --- TOOLS.md | 8 ++- bin/brain-dump | 132 +++++++++++++++++++++++++++-------------- memory/brain-dump.json | 2 +- 3 files changed, 94 insertions(+), 48 deletions(-) diff --git a/TOOLS.md b/TOOLS.md index 5d0d3a8..1539d61 100644 --- a/TOOLS.md +++ b/TOOLS.md @@ -142,17 +142,19 @@ Helper script: `~/clawd/bin/brain-dump` ```bash brain-dump list [--priority now,soon] [--due] [--limit N] brain-dump add --text "..." --priority soon [--context "..."] -brain-dump edit [--text "..."] [--priority ...] [--context "..."] +brain-dump add --recurring --text "..." --frequency daily [--when evening] [--note "..."] [--context "..."] +brain-dump edit [--text "..."] [--priority|--frequency|--when|--note|--context "..."] brain-dump done brain-dump show brain-dump nudged ,,... -brain-dump recurring [--when evening] +brain-dump recurring ``` - Data: `memory/brain-dump.json` - `--due` filters by nudge interval: now=1d, soon=3d, someday=7d - `nudged` marks tasks as just-nudged (resets due timer) -- `recurring` lists recurring reminders (nose shower etc.) +- `recurring` lists all recurring items with full context (note, when, frequency) +- `add --recurring` / `edit` / `done` work for both tasks and recurring items - Output is tab-separated for minimal tokens **Heartbeat workflow:** diff --git a/bin/brain-dump b/bin/brain-dump index 7394c08..2ef6364 100755 --- a/bin/brain-dump +++ b/bin/brain-dump @@ -41,29 +41,32 @@ function formatTask(t) { return line; } +function formatRecurring(r) { + let line = `${r.id}\t${r.frequency}\t${r.when || '-'}\t${r.text}`; + if (r.note) line += `\t${r.note}`; + if (r.context) line += `\t${r.context}`; + return line; +} + // --- Commands --- function cmdList(args) { const data = load(); let tasks = data.tasks || []; - // Filter by priority const prioArg = getFlag(args, '--priority'); if (prioArg) { const prios = prioArg.split(',').map(s => s.trim()); tasks = tasks.filter(t => prios.includes(t.priority)); } - // Filter by due if (args.includes('--due')) { tasks = tasks.filter(isDue); } - // Sort: now > soon > someday const prioOrder = { now: 0, soon: 1, someday: 2 }; tasks.sort((a, b) => (prioOrder[a.priority] ?? 3) - (prioOrder[b.priority] ?? 3)); - // Limit const limitArg = getFlag(args, '--limit'); if (limitArg) { tasks = tasks.slice(0, parseInt(limitArg, 10)); @@ -80,43 +83,71 @@ function cmdList(args) { } function cmdAdd(args) { + const isRecurring = args.includes('--recurring'); const text = getFlag(args, '--text'); if (!text) { console.error('--text required'); process.exit(1); } - const priority = getFlag(args, '--priority') || 'soon'; const context = getFlag(args, '--context') || undefined; const data = load(); - const task = { - id: shortId(), - added: new Date().toISOString().slice(0, 10), - text, - priority, - }; - if (context) task.context = context; - data.tasks = data.tasks || []; - data.tasks.push(task); - save(data); - console.log(`Added: ${task.id}\t${priority}\t${text}`); + + if (isRecurring) { + const frequency = getFlag(args, '--frequency') || 'daily'; + const when = getFlag(args, '--when') || undefined; + const note = getFlag(args, '--note') || undefined; + const item = { id: shortId(), text, frequency }; + if (when) item.when = when; + if (note) item.note = note; + if (context) item.context = context; + data.recurring = data.recurring || []; + data.recurring.push(item); + save(data); + console.log(`Added recurring: ${formatRecurring(item)}`); + } else { + const priority = getFlag(args, '--priority') || 'soon'; + const task = { id: shortId(), added: new Date().toISOString().slice(0, 10), text, priority }; + if (context) task.context = context; + data.tasks = data.tasks || []; + data.tasks.push(task); + save(data); + console.log(`Added: ${task.id}\t${priority}\t${text}`); + } } function cmdEdit(args) { const id = args[0]; - if (!id) { console.error('Usage: brain-dump edit [--text ...] [--priority ...] [--context ...]'); process.exit(1); } + if (!id) { console.error('Usage: brain-dump edit [--text ...] [--priority ...] [--context ...] [--frequency ...] [--when ...] [--note ...]'); process.exit(1); } const data = load(); - const task = (data.tasks || []).find(t => t.id === id); - if (!task) { console.error(`Task ${id} not found.`); process.exit(1); } + + // Check tasks first, then recurring + let item = (data.tasks || []).find(t => t.id === id); + let isRecurring = false; + if (!item) { + item = (data.recurring || []).find(r => r.id === id); + isRecurring = true; + } + if (!item) { console.error(`Item ${id} not found.`); process.exit(1); } const text = getFlag(args, '--text'); - const priority = getFlag(args, '--priority'); const context = getFlag(args, '--context'); + if (text) item.text = text; + if (context !== null && context !== undefined) item.context = context; - if (text) task.text = text; - if (priority) task.priority = priority; - if (context !== null && context !== undefined) task.context = context; - - save(data); - console.log(`Updated: ${formatTask(task)}`); + if (isRecurring) { + const frequency = getFlag(args, '--frequency'); + const when = getFlag(args, '--when'); + const note = getFlag(args, '--note'); + if (frequency) item.frequency = frequency; + if (when) item.when = when; + if (note !== null && note !== undefined) item.note = note; + save(data); + console.log(`Updated recurring: ${formatRecurring(item)}`); + } else { + const priority = getFlag(args, '--priority'); + if (priority) item.priority = priority; + save(data); + console.log(`Updated: ${formatTask(item)}`); + } } function cmdDone(args) { @@ -124,12 +155,27 @@ function cmdDone(args) { if (!id) { console.error('Usage: brain-dump done '); process.exit(1); } const data = load(); - const idx = (data.tasks || []).findIndex(t => t.id === id); - if (idx === -1) { console.error(`Task ${id} not found.`); process.exit(1); } - const removed = data.tasks.splice(idx, 1)[0]; - save(data); - console.log(`Done: ${removed.text}`); + // Check tasks + let idx = (data.tasks || []).findIndex(t => t.id === id); + if (idx !== -1) { + const removed = data.tasks.splice(idx, 1)[0]; + save(data); + console.log(`Done: ${removed.text}`); + return; + } + + // Check recurring + idx = (data.recurring || []).findIndex(r => r.id === id); + if (idx !== -1) { + const removed = data.recurring.splice(idx, 1)[0]; + save(data); + console.log(`Removed recurring: ${removed.text}`); + return; + } + + console.error(`Item ${id} not found.`); + process.exit(1); } function cmdShow(args) { @@ -137,10 +183,11 @@ function cmdShow(args) { if (!id) { console.error('Usage: brain-dump show '); process.exit(1); } const data = load(); - const task = (data.tasks || []).find(t => t.id === id); - if (!task) { console.error(`Task ${id} not found.`); process.exit(1); } + const item = (data.tasks || []).find(t => t.id === id) + || (data.recurring || []).find(r => r.id === id); + if (!item) { console.error(`Item ${id} not found.`); process.exit(1); } - console.log(JSON.stringify(task, null, 2)); + console.log(JSON.stringify(item, null, 2)); } function cmdNudged(args) { @@ -161,19 +208,15 @@ function cmdNudged(args) { console.log(`Marked ${count} task(s) as nudged.`); } -function cmdRecurring(args) { +function cmdRecurring() { const data = load(); - const when = getFlag(args, '--when'); - let items = data.recurring || []; - if (when) { - items = items.filter(r => r.when === when); - } + const items = data.recurring || []; if (items.length === 0) { console.log('No recurring items.'); return; } for (const r of items) { - console.log(`${r.id}\t${r.frequency}\t${r.when || '-'}\t${r.text}`); + console.log(formatRecurring(r)); } } @@ -196,16 +239,17 @@ switch (cmd) { case 'done': cmdDone(args); break; case 'show': cmdShow(args); break; case 'nudged': cmdNudged(args); break; - case 'recurring': cmdRecurring(args); break; + case 'recurring': cmdRecurring(); break; default: console.log(`Usage: brain-dump Commands: list [--priority now,soon] [--due] [--limit N] add --text "..." --priority soon [--context "..."] - edit [--text "..."] [--priority ...] [--context "..."] + add --recurring --text "..." --frequency daily [--when evening] [--note "..."] [--context "..."] + edit [--text "..."] [--priority|--frequency|--when|--note|--context "..."] done show nudged ,,... - recurring [--when evening]`); + recurring`); } diff --git a/memory/brain-dump.json b/memory/brain-dump.json index d39c874..12dea42 100644 --- a/memory/brain-dump.json +++ b/memory/brain-dump.json @@ -2,7 +2,7 @@ "description": "Task tracking β€” auto-captured from chat or manually added. Done tasks get deleted.", "recurring": [ { - "id": "nose-shower", + "id": "843efabf", "text": "Nose shower πŸ‘ƒπŸšΏ", "frequency": "daily", "when": "evening", From 516d6a1b342e1c50ba2d12ccc5e448e25663874e Mon Sep 17 00:00:00 2001 From: Agent Date: Sat, 7 Feb 2026 14:09:40 +0000 Subject: [PATCH 03/10] brain-dump: merge --note into --context, single field for extra info --- TOOLS.md | 4 ++-- bin/brain-dump | 9 ++------- memory/brain-dump.json | 6 +++--- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/TOOLS.md b/TOOLS.md index 1539d61..5ca5afe 100644 --- a/TOOLS.md +++ b/TOOLS.md @@ -142,8 +142,8 @@ Helper script: `~/clawd/bin/brain-dump` ```bash brain-dump list [--priority now,soon] [--due] [--limit N] brain-dump add --text "..." --priority soon [--context "..."] -brain-dump add --recurring --text "..." --frequency daily [--when evening] [--note "..."] [--context "..."] -brain-dump edit [--text "..."] [--priority|--frequency|--when|--note|--context "..."] +brain-dump add --recurring --text "..." --frequency daily [--when evening] [--context "..."] +brain-dump edit [--text "..."] [--priority|--frequency|--when|--context "..."] brain-dump done brain-dump show brain-dump nudged ,,... diff --git a/bin/brain-dump b/bin/brain-dump index 2ef6364..cc25ea4 100755 --- a/bin/brain-dump +++ b/bin/brain-dump @@ -43,7 +43,6 @@ function formatTask(t) { function formatRecurring(r) { let line = `${r.id}\t${r.frequency}\t${r.when || '-'}\t${r.text}`; - if (r.note) line += `\t${r.note}`; if (r.context) line += `\t${r.context}`; return line; } @@ -93,10 +92,8 @@ function cmdAdd(args) { if (isRecurring) { const frequency = getFlag(args, '--frequency') || 'daily'; const when = getFlag(args, '--when') || undefined; - const note = getFlag(args, '--note') || undefined; const item = { id: shortId(), text, frequency }; if (when) item.when = when; - if (note) item.note = note; if (context) item.context = context; data.recurring = data.recurring || []; data.recurring.push(item); @@ -136,10 +133,8 @@ function cmdEdit(args) { if (isRecurring) { const frequency = getFlag(args, '--frequency'); const when = getFlag(args, '--when'); - const note = getFlag(args, '--note'); if (frequency) item.frequency = frequency; if (when) item.when = when; - if (note !== null && note !== undefined) item.note = note; save(data); console.log(`Updated recurring: ${formatRecurring(item)}`); } else { @@ -246,8 +241,8 @@ switch (cmd) { Commands: list [--priority now,soon] [--due] [--limit N] add --text "..." --priority soon [--context "..."] - add --recurring --text "..." --frequency daily [--when evening] [--note "..."] [--context "..."] - edit [--text "..."] [--priority|--frequency|--when|--note|--context "..."] + add --recurring --text "..." --frequency daily [--when evening] [--context "..."] + edit [--text "..."] [--priority|--frequency|--when|--context "..."] done show nudged ,,... diff --git a/memory/brain-dump.json b/memory/brain-dump.json index 12dea42..f2bade1 100644 --- a/memory/brain-dump.json +++ b/memory/brain-dump.json @@ -1,12 +1,12 @@ { - "description": "Task tracking β€” auto-captured from chat or manually added. Done tasks get deleted.", + "description": "Task tracking \u2014 auto-captured from chat or manually added. Done tasks get deleted.", "recurring": [ { "id": "843efabf", - "text": "Nose shower πŸ‘ƒπŸšΏ", + "text": "Nose shower \ud83d\udc43\ud83d\udebf", "frequency": "daily", "when": "evening", - "note": "Remind in evening, whether work just wrapped up or already relaxing" + "context": "Remind in evening, whether work just wrapped up or already relaxing" } ], "tasks": [ From e26f7e141b2a3447e9988eb327b3aa2219861a55 Mon Sep 17 00:00:00 2001 From: Agent Date: Sat, 7 Feb 2026 14:11:22 +0000 Subject: [PATCH 04/10] brain-dump: fix edit usage message, clean test data --- bin/brain-dump | 2 +- memory/brain-dump.json | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/bin/brain-dump b/bin/brain-dump index cc25ea4..a127b8a 100755 --- a/bin/brain-dump +++ b/bin/brain-dump @@ -112,7 +112,7 @@ function cmdAdd(args) { function cmdEdit(args) { const id = args[0]; - if (!id) { console.error('Usage: brain-dump edit [--text ...] [--priority ...] [--context ...] [--frequency ...] [--when ...] [--note ...]'); process.exit(1); } + if (!id) { console.error('Usage: brain-dump edit [--text ...] [--priority ...] [--context ...] [--frequency ...] [--when ...]'); process.exit(1); } const data = load(); diff --git a/memory/brain-dump.json b/memory/brain-dump.json index f2bade1..792739a 100644 --- a/memory/brain-dump.json +++ b/memory/brain-dump.json @@ -1,9 +1,9 @@ { - "description": "Task tracking \u2014 auto-captured from chat or manually added. Done tasks get deleted.", + "description": "Task tracking β€” auto-captured from chat or manually added. Done tasks get deleted.", "recurring": [ { "id": "843efabf", - "text": "Nose shower \ud83d\udc43\ud83d\udebf", + "text": "Nose shower πŸ‘ƒπŸšΏ", "frequency": "daily", "when": "evening", "context": "Remind in evening, whether work just wrapped up or already relaxing" @@ -22,13 +22,15 @@ "added": "2026-02-07", "text": "Set up MCP server for Forgejo instance", "priority": "soon", - "context": "Phase 1: MCP server for interactive Claude web sessions (fork + PR workflow). Phase 2: Automated issue-solving pipeline with clarification comments." + "context": "Phase 1: MCP server for interactive Claude web sessions (fork + PR workflow). Phase 2: Automated issue-solving pipeline with clarification comments.", + "lastNudged": "2026-02-07T14:11:07.284Z" }, { "id": "0902aaba", "added": "2026-02-07", "text": "TYPO3 v13 upgrade for GBV", - "priority": "soon" + "priority": "soon", + "lastNudged": "2026-02-07T14:11:07.284Z" } ] } From 10a4c1227b24a0375bc6632403ab12956d815708 Mon Sep 17 00:00:00 2001 From: Agent Date: Sat, 7 Feb 2026 15:15:32 +0000 Subject: [PATCH 05/10] Rename brain-dump to tasks --- HEARTBEAT.md | 18 +- TOOLS.md | 24 +-- bin/{brain-dump => tasks} | 12 +- memory/2026-02-06.md | 23 +++ memory/2026-02-07.md | 27 +++ memory/ainews-seen.txt | 67 +++++++ memory/calendar-reminders-sent.json | 4 +- memory/derstandard-seen.txt | 120 ++++++++----- memory/heartbeat-state.json | 41 ++++- memory/{brain-dump.json => tasks.json} | 0 memory/tv-shows.json | 145 ++++++++++++++++ memory/wind-down-log.json | 230 ++----------------------- 12 files changed, 415 insertions(+), 296 deletions(-) rename bin/{brain-dump => tasks} (92%) create mode 100644 memory/2026-02-06.md create mode 100644 memory/2026-02-07.md rename memory/{brain-dump.json => tasks.json} (100%) create mode 100644 memory/tv-shows.json diff --git a/HEARTBEAT.md b/HEARTBEAT.md index 624e690..829eda9 100644 --- a/HEARTBEAT.md +++ b/HEARTBEAT.md @@ -20,7 +20,7 @@ Check the following and notify only once per event (track in `memory/heartbeat-s **If they're about to start something new after 20:00**: Gently suggest postponing to tomorrow. - **Work-end reminders**: When they indicate they're wrapping up or transitioning to wind-down, check `memory/brain-dump.json` for `recurring` items with `when: "evening"` and remind them (e.g., nose shower) before they get too deep into relaxation mode. + **Work-end reminders**: When they indicate they're wrapping up or transitioning to wind-down, check `memory/tasks.json` for `recurring` items with `when: "evening"` and remind them (e.g., nose shower) before they get too deep into relaxation mode. **πŸ“ AUTO-LOG EVERYTHING 19:00β†’SLEEP** β€” Log to `memory/wind-down-log.json` as events happen: - What they're doing (working, watching TV, chatting, browsing, etc.) @@ -44,10 +44,18 @@ Check the following and notify only once per event (track in `memory/heartbeat-s 5. **Steam Machine / Steam Frame**: Check for **official Valve news only** about pricing or release date. Notify once when official price or specific release date is announced. Baseline: "early 2026" window, no price yet. -6. **Brain dump nudging**: During daytime hours (10:00-18:00 Vienna), occasionally check `memory/brain-dump.json` for: - - Items with `remindOn` date matching today - - Items older than 2 days that haven't been addressed (weekdays only β€” Mon-Fri) - On weekends: only surface items with `remindOn` = today. +6. **OpenClaw + Claude Code updates**: Check once daily (daytime) for: + - OpenClaw releases (especially for Opus 4.6 support via PR #9863) + - Claude Code new versions + Track in `memory/heartbeat-state.json` watchlist. Notify when new versions ship. + +7. **Task nudging**: During daytime hours (10:00-18:00 Vienna), occasionally check `memory/tasks.json` for: + - `now` priority tasks β€” nudge daily + - `soon` priority tasks β€” nudge every 2-3 days (weekdays only) + - `someday` tasks β€” only mention during weekly reviews or when contextually relevant + On weekends: only nudge `now` priority items. Surface 1-2 items max, conversationally. NOT in evening β€” that's wind-down time. + **Auto-capture:** When user mentions tasks naturally in chat ("I should...", "I need to...", "Don't forget..."), add to tasks.json and confirm with a short acknowledgment. + **Done = delete.** Remove completed tasks immediately. History lives in daily memory logs. If nothing new to report, reply HEARTBEAT_OK. diff --git a/TOOLS.md b/TOOLS.md index 5ca5afe..16f0c73 100644 --- a/TOOLS.md +++ b/TOOLS.md @@ -137,20 +137,20 @@ ainews reset # Clear seen history ## Brain Dump CLI -Helper script: `~/clawd/bin/brain-dump` +Helper script: `~/clawd/bin/tasks` ```bash -brain-dump list [--priority now,soon] [--due] [--limit N] -brain-dump add --text "..." --priority soon [--context "..."] -brain-dump add --recurring --text "..." --frequency daily [--when evening] [--context "..."] -brain-dump edit [--text "..."] [--priority|--frequency|--when|--context "..."] -brain-dump done -brain-dump show -brain-dump nudged ,,... -brain-dump recurring +tasks list [--priority now,soon] [--due] [--limit N] +tasks add --text "..." --priority soon [--context "..."] +tasks add --recurring --text "..." --frequency daily [--when evening] [--context "..."] +tasks edit [--text "..."] [--priority|--frequency|--when|--context "..."] +tasks done +tasks show +tasks nudged ,,... +tasks recurring ``` -- Data: `memory/brain-dump.json` +- Data: `memory/tasks.json` - `--due` filters by nudge interval: now=1d, soon=3d, someday=7d - `nudged` marks tasks as just-nudged (resets due timer) - `recurring` lists all recurring items with full context (note, when, frequency) @@ -158,9 +158,9 @@ brain-dump recurring - Output is tab-separated for minimal tokens **Heartbeat workflow:** -1. `brain-dump list --due --limit 2` β†’ get tasks needing a nudge +1. `tasks list --due --limit 2` β†’ get tasks needing a nudge 2. Mention them conversationally -3. `brain-dump nudged ,` β†’ mark as nudged +3. `tasks nudged ,` β†’ mark as nudged --- diff --git a/bin/brain-dump b/bin/tasks similarity index 92% rename from bin/brain-dump rename to bin/tasks index a127b8a..63f53fa 100755 --- a/bin/brain-dump +++ b/bin/tasks @@ -4,7 +4,7 @@ const fs = require('fs'); const path = require('path'); const crypto = require('crypto'); -const DUMP_PATH = path.join(__dirname, '..', 'memory', 'brain-dump.json'); +const DUMP_PATH = path.join(__dirname, '..', 'memory', 'tasks.json'); const NUDGE_INTERVALS = { now: 24 * 60 * 60 * 1000, // 1 day @@ -112,7 +112,7 @@ function cmdAdd(args) { function cmdEdit(args) { const id = args[0]; - if (!id) { console.error('Usage: brain-dump edit [--text ...] [--priority ...] [--context ...] [--frequency ...] [--when ...]'); process.exit(1); } + if (!id) { console.error('Usage: tasks edit [--text ...] [--priority ...] [--context ...] [--frequency ...] [--when ...]'); process.exit(1); } const data = load(); @@ -147,7 +147,7 @@ function cmdEdit(args) { function cmdDone(args) { const id = args[0]; - if (!id) { console.error('Usage: brain-dump done '); process.exit(1); } + if (!id) { console.error('Usage: tasks done '); process.exit(1); } const data = load(); @@ -175,7 +175,7 @@ function cmdDone(args) { function cmdShow(args) { const id = args[0]; - if (!id) { console.error('Usage: brain-dump show '); process.exit(1); } + if (!id) { console.error('Usage: tasks show '); process.exit(1); } const data = load(); const item = (data.tasks || []).find(t => t.id === id) @@ -187,7 +187,7 @@ function cmdShow(args) { function cmdNudged(args) { const ids = (args[0] || '').split(',').map(s => s.trim()).filter(Boolean); - if (ids.length === 0) { console.error('Usage: brain-dump nudged ,,...'); process.exit(1); } + if (ids.length === 0) { console.error('Usage: tasks nudged ,,...'); process.exit(1); } const data = load(); const now = new Date().toISOString(); @@ -236,7 +236,7 @@ switch (cmd) { case 'nudged': cmdNudged(args); break; case 'recurring': cmdRecurring(); break; default: - console.log(`Usage: brain-dump + console.log(`Usage: tasks Commands: list [--priority now,soon] [--due] [--limit N] diff --git a/memory/2026-02-06.md b/memory/2026-02-06.md new file mode 100644 index 0000000..f664689 --- /dev/null +++ b/memory/2026-02-06.md @@ -0,0 +1,23 @@ +# 2026-02-06 (Friday) + +## Key Events +- **Opus 4.6 upgrade**: User pointed out OpenClaw update included Opus 4.6 support. Config was still on 4.5 β€” patched config to set Opus 4.6 as primary with 4.5 fallback. Updated TOOLS.md. +- **Cron jobs fixed**: News cron jobs were broken all day β€” root cause was `wakeMode: "next-heartbeat"` causing jobs to be skipped when heartbeat timing didn't align. Fixed by switching all 8 news jobs to `wakeMode: "now"`. Tested successfully at 21:35 and 21:39 UTC. +- **Cron delivery note**: What appears truncated in system logs is actually the full message on WhatsApp β€” I only see a summary of cron agent output. +- **Task system revamp**: Restructured brain-dump.json β€” removed status field (done = delete), added priority system (now/soon/someday), updated HEARTBEAT.md with auto-capture and smarter nudging rules. +- **AirPods listed on Willhaben**: Helped write title/description for AirPods Pro 2 USB-C listing. Task completed and removed from brain-dump. +- **Bazzite 42β†’43 upgrade**: Helped user rebase GPD Win 4 from Bazzite 42 to 43. Used `ostree-unverified-registry` to bypass stuck ref. Upgrade successful. +- **FSR4 setup**: Guided user through FSR4 emulated RDNA3 on GPD Win 4 HX 370. ProtonPlus β†’ Proton GE β†’ `DXIL_SPIRV_CONFIG=wmma_rdna3_workaround FSR4_UPGRADE=1`. Set up global env vars. +- **GPD Win 4 notes**: HX 370 processor, BIOS 0.10 (latest for this model), 1080p display. 15W TDP = ~28W total system draw (normal). Clair Obscur needs ~20W TDP for 30fps at 1080p FSR performance. +- **SVS + Watzek Petschinka reminders**: Set for Monday 9 AM Vienna. +- **Codex CLI**: Explained plan mode (Shift+Tab to cycle modes: Ask/Plan/Auto). + +## Wind-down +- 19:00-22:00 window: Failed to check in at 19:00 β€” user called me out. Must proactively reach out when wind-down window starts. +- User worked until ~23:00 on Friday (hook issue β†’ NixOS config β†’ cron testing). Classic scope creep pattern. +- Nose shower done at 23:01. + +## Lessons +- **Always check in at 19:00 Vienna** when wind-down window starts, even if user seems quiet. +- **Cron jobs**: Use `wakeMode: "now"` for isolated jobs that need precise timing. `next-heartbeat` is unreliable for scheduled tasks. +- **Cron delivery**: I only see summaries of cron agent output, not the full message. Don't assume truncation on WhatsApp. diff --git a/memory/2026-02-07.md b/memory/2026-02-07.md new file mode 100644 index 0000000..cee343b --- /dev/null +++ b/memory/2026-02-07.md @@ -0,0 +1,27 @@ +# 2026-02-07 (Saturday) + +## Cron Bug Fix πŸ› +- **Root cause**: `recomputeNextRuns()` in `/app/src/cron/service/store.ts` (line ~409 in ensureLoaded) recomputes `nextRunAtMs` for ALL jobs before `runDueJobs()` runs. For recurring schedules (cron/every), `computeNextRunAtMs()` always returns the NEXT occurrence after `now`, advancing the schedule past the current time. `runDueJobs()` then finds no due jobs. +- One-shot `at` jobs were unaffected because `computeJobNextRunAtMs` returns the original timestamp for them. +- **Fix**: Patched `/app/dist/gateway-cli-D6nsc3s0.js` β€” in `recomputeNextRuns`, added check to skip recomputing if `nextRunAtMs <= now` (job is due, let it execute first). +- **Impact**: All 8 news cron jobs (Der Standard + AI News Γ— 4 times/day) had NEVER fired since creation on Feb 6. +- Hard-killed gateway (PID 2) to force container restart and load patched JS bundle. +- Verified: recurring `every` job fired correctly after patch. Real news jobs scheduled for 14:00 Vienna. +- **TODO**: File upstream bug report on OpenClaw GitHub (issue in `recomputeNextRuns` race condition). + +## GPD Win 4 Optimization +- User working on improving performance/watt on GPD Win 4 2025 (HX 370, Bazzite 43, FSR 4 enabled) +- Discussed: TDP tuning (15-20W sweet spot), core parking via PowerTools Decky plugin, resolution/FSR upscaling, fan curves, frame limiting +- Core parking: disable SMT, reduce threads to 4 for GPU-bound games +- BIOS: UMA frame buffer option not available on HX 370 model (others report same) +- Recommended removing ReShade since FSR 4 handles upscaling +- ProtonGE: update every 2-4 weeks or when a game has issues + +## Android β†’ Snapcast Streaming (Reference) +- No native AirPlay-like solution for Android β†’ Snapcast +- **Best option:** DLNA/UPnP β€” gmrender-resurrect piped into Snapcast server + BubbleUPnP app on phone +- **Alternatives:** Bluetooth A2DP sink (range limited), TCP source (no good Android app yet), AirPlay via Android app (hacky) +- User interested but not urgent β€” revisit when asked + +## Calendar +- Marie besuchen 13:00-17:00 (reminder sent at 11:30 Vienna) diff --git a/memory/ainews-seen.txt b/memory/ainews-seen.txt index 6e9215f..57864b6 100644 --- a/memory/ainews-seen.txt +++ b/memory/ainews-seen.txt @@ -1,15 +1,82 @@ +https://simonwillison.net/2026/Feb/6/an-update-on-heroku/#atom-everything +https://simonwillison.net/2026/Feb/6/karel-doosterlinck/#atom-everything +https://simonwillison.net/2026/Feb/5/ai-adoption-journey/#atom-everything +https://simonwillison.net/2026/Feb/5/two-new-models/#atom-everything +https://simonwillison.net/2026/Feb/5/the-world-factbook/#atom-everything +https://simonwillison.net/2026/Feb/4/voxtral-2/#atom-everything +https://simonwillison.net/2026/Feb/4/distributing-go-binaries/#atom-everything +https://simonwillison.net/2026/Feb/3/introducing-deno-sandbox/#atom-everything https://simonwillison.net/2026/Feb/3/january/#atom-everything https://simonwillison.net/2026/Feb/3/brandon-sanderson/#atom-everything https://simonwillison.net/2026/Feb/2/introducing-the-codex-app/#atom-everything https://simonwillison.net/2026/Feb/2/no-humans-allowed/#atom-everything https://simonwillison.net/2026/Feb/1/openclaw-in-docker/#atom-everything +https://simonwillison.net/2026/Jan/31/andrej-karpathy/#atom-everything +https://simonwillison.net/2026/Jan/31/collective-efficacy/#atom-everything +https://simonwillison.net/2026/Jan/30/steve-yegge/#atom-everything +https://simonwillison.net/2026/Jan/30/moltbook/#atom-everything +https://simonwillison.net/2026/Jan/30/a-programming-tool-for-the-arts/#atom-everything +https://simonwillison.net/2026/Jan/29/datasette-10a24/#atom-everything +https://simonwillison.net/2026/Jan/28/dynamic-features-static-site/#atom-everything +https://simonwillison.net/2026/Jan/28/the-five-levels/#atom-everything +https://simonwillison.net/2026/Jan/27/one-human-one-agent-one-browser/#atom-everything +https://simonwillison.net/2026/Jan/27/kimi-k25/#atom-everything +https://simonwillison.net/2026/Jan/26/tests/#atom-everything +https://simonwillison.net/2026/Jan/26/chatgpt-containers/#atom-everything +https://simonwillison.net/2026/Jan/25/the-browser-is-the-sandbox/#atom-everything +https://simonwillison.net/2026/Jan/25/kakapo-cam/#atom-everything +https://simonwillison.net/2026/Jan/24/dont-trust-the-process/#atom-everything +https://simonwillison.net/2026/Jan/24/jasmine-sun/#atom-everything +https://simonwillison.net/2026/Jan/23/fastrender/#atom-everything +https://openai.com/policies/kr-privacy-policy +https://openai.com/index/our-approach-to-localization +https://openai.com/index/gpt-5-lowers-protein-synthesis-cost +https://openai.com/index/trusted-access-for-cyber +https://openai.com/index/introducing-openai-frontier +https://openai.com/index/navigating-health-questions +https://openai.com/index/introducing-gpt-5-3-codex +https://openai.com/index/gpt-5-3-codex-system-card +https://openai.com/index/unlocking-the-codex-harness +https://openai.com/index/vfl-wolfsburg https://openai.com/index/sora-feed-philosophy https://openai.com/index/snowflake-partnership https://openai.com/index/introducing-the-codex-app https://openai.com/index/inside-our-in-house-data-agent https://openai.com/index/retiring-gpt-4o-and-older-models +https://openai.com/index/taisei +https://openai.com/index/emea-youth-and-wellbeing-grant +https://openai.com/index/the-next-chapter-for-ai-in-the-eu +https://openai.com/index/ai-agent-link-safety +https://openai.com/index/pvh-future-of-fashion +https://openai.com/index/trustbank +https://openai.com/index/introducing-prism +https://openai.com/index/indeed-maggie-hulce +https://openai.com/index/unrolling-the-codex-agent-loop +https://openai.com/index/scaling-postgresql +https://openai.com/index/praktika +https://openai.com/business/guides-and-resources/chatgpt-usage-and-adoption-patterns-at-work +https://openai.com/index/higgsfield +https://openai.com/index/edu-for-countries +https://openai.com/index/how-countries-can-end-the-capability-overhang https://magazine.sebastianraschka.com/p/categories-of-inference-time-scaling https://magazine.sebastianraschka.com/p/state-of-llms-2025 https://magazine.sebastianraschka.com/p/llm-research-papers-2025-part2 https://magazine.sebastianraschka.com/p/technical-deepseek https://magazine.sebastianraschka.com/p/beyond-standard-llms +https://magazine.sebastianraschka.com/p/llm-evaluation-4-approaches +https://magazine.sebastianraschka.com/p/qwen3-from-scratch +https://magazine.sebastianraschka.com/p/from-gpt-2-to-gpt-oss-analyzing-the +https://magazine.sebastianraschka.com/p/the-big-llm-architecture-comparison +https://magazine.sebastianraschka.com/p/llm-research-papers-2025-list-one +https://magazine.sebastianraschka.com/p/coding-the-kv-cache-in-llms +https://magazine.sebastianraschka.com/p/coding-llms-from-the-ground-up +https://magazine.sebastianraschka.com/p/the-state-of-llm-reasoning-model-training +https://magazine.sebastianraschka.com/p/first-look-at-reasoning-from-scratch +https://magazine.sebastianraschka.com/p/state-of-llm-reasoning-and-inference-scaling +https://magazine.sebastianraschka.com/p/understanding-reasoning-llms +https://magazine.sebastianraschka.com/p/ai-research-papers-2024-part-2 +https://magazine.sebastianraschka.com/p/ai-research-papers-2024-part-1 +https://magazine.sebastianraschka.com/p/llm-research-papers-the-2024-list +https://magazine.sebastianraschka.com/p/understanding-multimodal-llms +https://simonwillison.net/2026/Feb/6/tom-dale/#atom-everything +https://simonwillison.net/2026/Feb/6/pydantic-monty/#atom-everything diff --git a/memory/calendar-reminders-sent.json b/memory/calendar-reminders-sent.json index ebffaad..701c1d4 100644 --- a/memory/calendar-reminders-sent.json +++ b/memory/calendar-reminders-sent.json @@ -1,3 +1,5 @@ { - "sent": [] + "sent": [ + {"event": "Marie besuchen", "date": "2026-02-07", "remindedAt": "2026-02-07T09:31:00Z"} + ] } diff --git a/memory/derstandard-seen.txt b/memory/derstandard-seen.txt index 0a9f5d5..6af8197 100644 --- a/memory/derstandard-seen.txt +++ b/memory/derstandard-seen.txt @@ -1,49 +1,75 @@ -https://www.derstandard.at/story/3000000306979/trump-always-chickens-out-macht-taco-tatsaechlich-immer-einen-rueckzieher?ref=rss -https://www.derstandard.at/story/3000000307063/usa-schiessen-iranische-drohne-nahe-flugzeugtraeger-im-arabischen-meer-ab?ref=rss -https://www.derstandard.at/story/3000000306672/neue-epstein-files-werfen-fragen-an-adelige-diplomaten-und-eva-dichand-auf?ref=rss -https://www.derstandard.at/story/3000000306965/wodurch-fast-vier-von-zehn-krebsfaellen-vermeidbar-waeren?ref=rss -https://www.derstandard.at/story/3000000306903/etappensieg-fuer-saudischen-staatsfonds-mubadala-im-streit-mit-signa?ref=rss -https://www.derstandard.at/story/3000000307018/das-gehalt-ueberzeugt-beschaeftigte-nicht-dafuer-die-kollegen?ref=rss -https://www.derstandard.at/story/3000000307007/waymo-will-robotaxis-global-anbieten-und-sammelt-dafuer-neue-milliarden-ein?ref=rss -https://www.derstandard.at/story/3000000307041/babys-erkennen-objekte-schon-im-alter-von-zwei-monaten?ref=rss -https://www.derstandard.at/story/3000000306987/welche-bedrohung-durch-russland-ist-realistisch?ref=rss -https://www.derstandard.at/story/3000000306974/minister-wiederkehr-warum-weniger-latein-im-gymnasium-mehr-humanismus-bedeutet?ref=rss -https://www.derstandard.at/story/3000000306758/olympia-2026-zerstueckelte-winterspiele-sind-die-letzte-chance?ref=rss -https://www.derstandard.at/story/3000000303908/warum-online-bewerbungsgespraeche-so-schwierig-sind-und-wie-man-dennoch-punktet?ref=rss -https://www.derstandard.at/story/3000000306921/psychiaterin-kastner-ueber-kindstoetung-das-groesste-risiko-ist-eine-unbehandelte-depression?ref=rss -https://www.derstandard.at/story/3000000307052/trotz-kreuzbandrisses-vonn-haelt-an-olympia-start-fest?ref=rss -https://www.derstandard.at/story/3000000306703/vermoegen-sinnvoll-anlegen-eigentum-miete-oder-alternative-geldanlage?ref=rss -https://www.derstandard.at/story/3000000306735/krankenstand-wegen-skiunfalls-wann-darf-der-arbeitgeber-das-gehalt-verweigern?ref=rss -https://www.derstandard.at/story/3000000306990/maja-t-droht-in-budapester-antifa-prozess-ein-hartes-urteil?ref=rss -https://www.derstandard.at/story/3000000306855/kunstsammler-leon-black-war-jeffrey-epsteins-haupteinnahmequelle?ref=rss -https://www.derstandard.at/story/3000000306890/epstein-aff228re-ehepaar-clinton-zu-aussage-vor-dem-kongress-bereit?ref=rss -https://www.derstandard.at/story/3000000306960/konflikt-bei-den-salzburger-festspielen?ref=rss -https://www.derstandard.at/story/3000000307071/burgenlands-ex-landeshauptmann-niessl-will-f252r-hofburg-kandidieren?ref=rss -https://www.derstandard.at/story/3000000307072/gaddafi-sohn-seif-al-islam-gestorben?ref=rss -https://www.derstandard.at/story/3000000306899/prozess-wegen-sexuellen-missbrauchs-gegen-ex-politiker-stronach-beginnt-in-kanada?ref=rss -https://www.derstandard.at/story/3000000307067/anklage-will-wahlausschluss-f252r-le-pen-aber-nicht-sofort?ref=rss -https://www.derstandard.at/story/3000000307066/auf-kuba-hat-es-null-grad?ref=rss -https://www.derstandard.at/story/3000000307006/trump-fordert-von-elite-uni-harvard-eine-milliarde-dollar-schadenersatz?ref=rss -https://www.derstandard.at/story/3000000306975/beschuss-bei-17-grad-menschen-suchen-schutz-in-kyjiws-u-bahn-stationen?ref=rss -https://www.derstandard.at/story/3000000306996/tod-eines-haeftlings-expertenkommission-soll-strafvollzug-verbessern?ref=rss -https://www.derstandard.at/story/3000000306831/skelettierte-frauenleiche-in-wien-favoriten-entdeckt?ref=rss -https://www.derstandard.at/story/3000000306971/von-grammys-bis-kennedy-center-der-maga-kulturkampf-folgt-einer-strategie?ref=rss -https://www.derstandard.at/story/3000000306968/nicht-die-ki-ist-ausser-kontrolle-sondern-der-mensch?ref=rss -https://www.derstandard.at/story/3000000306772/latein-kuerzen-lieber-eine-bildungsreform-die-wir-brauchen?ref=rss -https://www.derstandard.at/story/3000000306775/weniger-latein-humanistische-bildung-ist-kein-ballast?ref=rss -https://www.derstandard.at/story/3000000305513/wunderheilung-im-winter?ref=rss -https://www.derstandard.at/story/3000000306811/machtkampf-in-china-mit-unberechenbaren-folgen?ref=rss -https://www.derstandard.at/story/3000000306670/eine-regierung-die-gestalten-will-sollte-mehr-ideen-haben-als-eine-volksbefragung?ref=rss +https://www.derstandard.at/story/3000000306839/sex-geld-macht-was-war-das-geheimnis-des-jeffrey-epstein?ref=rss +https://www.derstandard.at/story/3000000306835/stocker-europa-wird-aus-vielen-richtungen-bedroht?ref=rss +https://www.derstandard.at/story/3000000307558/kritik-an-rassistischem-trump-post-ueber-barack-und-michelle-obama?ref=rss +https://www.derstandard.at/story/3000000307468/der-bitcoin-crasht-die-szene-laechelt-muede?ref=rss +https://www.derstandard.at/story/3000000307239/batterie-ohne-lithium-warum-china-jetzt-auf-druckluftspeicher-setzt?ref=rss +https://www.derstandard.at/story/3000000307485/so-gross-wie-ein-schulbus-phantomqualle-in-atlantik-gefilmt?ref=rss +https://www.derstandard.at/story/3000000307236/jetzt-weiss-jeder-wo-nuuk-ist-wie-sich-trump-auf-den-groenland-tourismus-auswirkt?ref=rss +https://www.derstandard.at/story/3000000307471/die-babler-demontage-ist-verrueckt?ref=rss +https://www.derstandard.at/story/3000000307488/die-epstein-files-sind-eine-gewollte-ueberforderung-der-gesellschaft?ref=rss +https://www.derstandard.at/story/3000000307363/latein-und-ein-aufstand-der-eliten?ref=rss +https://www.derstandard.at/story/3000000306982/darin-gleicht-donald-trump-fast-allen-diktatoren?ref=rss +https://www.derstandard.at/story/3000000307480/nervoes-sam-altman-zuckt-wegen-spott-von-anthropic-aus?ref=rss +https://www.derstandard.at/story/3000000307472/der-herr-der-kameras-orf-regisseur-koegler-inszeniert-die-olympia-abfahrt?ref=rss +https://www.derstandard.at/story/3000000307321/quiz-zehn-fragen-um-die-welt?ref=rss +https://www.derstandard.at/story/3000000307578/polens-parlamentspraesident-gegen-nobelpreis-fuer-trump-us-botschafter-empoert?ref=rss +https://www.derstandard.at/story/3000000307466/die-eu-kommission-testet-alternativen-zu-microsoft-teams?ref=rss +https://www.derstandard.at/story/3000000300279/oesterreichs-fussball-bundesliga-ist-so-schlecht-wie-seit-jahrzehnten-nicht?ref=rss +https://www.derstandard.at/story/3000000305885/als-ai-weiwei-seinen-mittelfinger-dem-tiananmen-platz-entgegenstreckte?ref=rss +https://www.derstandard.at/story/3000000307479/baeume-in-den-dolomiten-haben-wohl-doch-keine-sonnenfinsternis-vorhergesehen?ref=rss +https://www.derstandard.at/story/3000000306805/der-standard-preismonitor-diese-produkte-wurden-am-teuersten?ref=rss +https://www.derstandard.at/story/3000000307527/attentat-in-moskau-auf-stellvertretenden-leiter-des-militaergeheimdienstes?ref=rss +https://www.derstandard.at/story/3000000307544/abfahrt-mit-kreuzbandriss-trainer-svindal-glaubt-an-lindsey-vonns-medaillenchance?ref=rss +https://www.derstandard.at/story/3000000307177/worauf-wir-uns-bei-olympia-am-meisten-freuen?ref=rss +https://www.derstandard.at/story/3000000307391/zweite-runde-mit-dichtem-programm-woeginger-muss-ab-mittwoch-zurueck-auf-die-anklagebank?ref=rss +https://www.derstandard.at/story/3000000307505/-frau-in-wien-nach-mutma223lichem-sexualdelikt-in-lebensgefahr?ref=rss +https://www.derstandard.at/story/3000000307556/abermals-kritik-vor-erster-phase-des-kopftuchverbots-an-schulen?ref=rss +https://www.derstandard.at/story/3000000307559/viele-tote-bei-anschlag-auf-moschee-in-islamabad?ref=rss +https://www.derstandard.at/story/3000000307557/ermittlungen-gegen-norwegischen-ex-regierungschef-wegen-epstein-affaere?ref=rss +https://www.derstandard.at/story/3000000307515/washington-post-redaktion-protestiert-gegen-kahlschlag?ref=rss +https://www.derstandard.at/story/3000000307486/stocker-fuehrt-politisches-armdruecken-in-der-koalition-ein-zu-seinem-schaden?ref=rss +https://www.derstandard.at/story/3000000307554/schon-zu-viel-trump?ref=rss +https://www.derstandard.at/story/3000000307489/der-wert-von-lebensmitteln-sollte-nicht-am-preis-haengen?ref=rss +https://www.derstandard.at/story/3000000307357/schriftsteller-thomas-raab-latein-als-humanistische-eintrittskarte?ref=rss +https://www.derstandard.at/story/3000000307333/die-russische-epstein-connection?ref=rss +https://www.derstandard.at/story/3000000307336/am-niedergang-der-washington-post-ist-nicht-nur-jeff-bezos-schuld?ref=rss +https://www.derstandard.at/story/3000000307138/wie-lange-noch-bleiben-sozialunternehmen-die-unsichtbaren-optimisten?ref=rss https://www.derstandard.at/story/3000000253356/finde-den-fehler?ref=rss https://www.derstandard.at/story/3000000306814/cartoons-februar?ref=rss -https://www.derstandard.at/story/3000000306730/was-ist-euer-lieblings-club-wiens?ref=rss -https://www.derstandard.at/story/3000000306462/wenn-der-letzte-wille-nicht-dem-zufall-ueberlassen-werden-soll?ref=rss -https://www.derstandard.at/story/3000000306728/seid-ihr-auch-von-gestiegenen-svs-beitraegen-betroffen?ref=rss -https://www.derstandard.at/story/3000000306902/teilauszahlung-des-gehalts-in-bitcoin-eure-erfahrungen?ref=rss -https://www.derstandard.at/story/3000000306593/ki-statt-latein-7-kritische-fragen-zur-reform?ref=rss -https://www.derstandard.at/story/3000000306299/neuigkeiten-im-gluecksspielrecht-lootboxen-und-geschaeftsfuehrerhaftung?ref=rss -https://www.derstandard.at/story/3000000306729/sollten-geschaefte-regulaer-sonntags-oeffnen?ref=rss -https://www.derstandard.at/story/3000000306767/wie-oft-schreibt-ihr-noch-mit-der-hand?ref=rss -https://www.derstandard.at/story/3000000306139/was-kostet-ein-verlorenes-tier-rechtlich-gesehen?ref=rss -https://www.derstandard.at/story/3000000305258/das-virtuelle-labor-im-weltraum?ref=rss -https://www.derstandard.at/story/3000000306940/befreiungsschlag-als-bumerang-stockers-volksabstimmung-verstimmt-auch-in-der-oevp?ref=rss +https://www.derstandard.at/story/3000000307458/nutzt-ihr-amazon-fuer-die-taeglichen-verbrauchsartikel?ref=rss +https://www.derstandard.at/story/3000000307065/profitieren-wirklich-alle-aktive-fonds-und-lebensversicherungen?ref=rss +https://www.derstandard.at/story/3000000306520/kurzzeitvermietung-in-wien-das-ende-von-airbnb-als-geschaeftsmodell?ref=rss +https://www.derstandard.at/story/3000000307531/ist-latein-mehr-als-nur-ein-unterrichtsfach?ref=rss +https://www.derstandard.at/story/3000000307305/was-sind-ihre-erfahrungen-als-zugbegleiterinnen?ref=rss +https://www.derstandard.at/story/3000000306657/lueger-ehrenmal-ein-monument-der-gescheiterten-entnazifizierung?ref=rss +https://www.derstandard.at/story/3000000307296/thema-grundwehrdienstverlaengerung-was-sind-eure-erfahrungen?ref=rss +https://www.derstandard.at/story/3000000306485/doppelte-botanik-pflanzen-mit-geschichten-und-zum-geniessen?ref=rss +https://www.derstandard.at/story/3000000307370/was-sind-eure-erinnerungen-an-die-olympischen-winterspiele?ref=rss +https://www.derstandard.at/story/3000000303147/zwischen-information-und-image-was-aerztliche-werbung-darf?ref=rss +https://www.derstandard.at/story/3000000307416/usa-und-eu-kooperieren-bei-seltenen-erden-warum-sie-keine-andere-wahl-haben?ref=rss +https://www.derstandard.at/story/3000000307497/schwaerzungen-und-kontrollverlust-warum-epsteins-opfer-die-veroeffentlichungen-kritisieren?ref=rss +https://www.derstandard.at/story/3000000307598/wehrpflicht-neos-gegen-volksbefragung?ref=rss +https://www.derstandard.at/story/3000000307127/cora-liess-sich-mit-23-sterilisieren-so-krassen-hate-habe-ich-nie-bekommen?ref=rss +https://www.derstandard.at/story/3000000307156/fuer-die-eiserne-reserve-der-benkos-wird-es-eng-was-steckt-in-der-laura-privatstiftung?ref=rss +https://www.derstandard.at/story/3000000307588/grossvater-schoss-in-oberoesterreich-auf-30-jaehrige-enkelin?ref=rss +https://www.derstandard.at/story/3000000307564/epsteins-prominente-verstrickungen-in-die-kunstwelt-haben-ein-nachspiel?ref=rss +https://www.derstandard.at/story/3000000307568/minnesotas-ice-watchers-how-tactics-of-1960s-radicals-went-mainstream?ref=rss +https://www.derstandard.at/story/3000000307500/fleisch-die-empoerung-im-schnitzel-land?ref=rss +https://www.derstandard.at/story/3000000307322/haeppchenweise-tuerkisch-im-neuen-kuebey?ref=rss +https://www.derstandard.at/story/3000000307110/goldverkauf-leicht-gemacht?ref=rss +https://www.derstandard.at/story/3000000307561/geeetech-m1s-im-test-kompetenter-3d-drucker-fuer-kids?ref=rss +https://www.derstandard.at/story/3000000306765/abschied-vom-schlechten-kaffee-in-wien?ref=rss +https://www.derstandard.at/story/3000000307596/zwischen-finger-am-abzug-und-gutem-start-gemischte-reaktionen-im-iran-auf-verhandlungen?ref=rss +https://www.derstandard.at/story/3000000307331/nasa-astronaut-bowen-in-wien-der-mond-ist-nur-der-anfang?ref=rss +https://www.derstandard.at/story/3000000307225/neue-ausstellung-belegt-kunst-braucht-kommerz?ref=rss +https://www.derstandard.at/story/3000000307539/bitcoin-crash-wie-es-dazu-kam-und-wie-weit-es-noch-abwaerts-gehen-kann?ref=rss +https://www.derstandard.at/story/3000000307584/ich-habe-keinen-fehler-gemacht-trump-distanziert-sich-von-rassistische-posting-ueber-die-obamas?ref=rss +https://www.derstandard.at/story/3000000307604/nach-ofarims-aussagen-zum-davidstern-verfahren-reagiert-sein-anwalt?ref=rss +https://www.derstandard.at/story/3000000307605/bundestag-verweigerte-afd-personal-laut-parteiangaben-ausstellung-von-hausausweisen?ref=rss +https://www.derstandard.at/story/3000000307533/sahel-usa-ruecken-wieder-naeher-europa-ringt-derweil-um-einen-kurs?ref=rss +https://www.derstandard.at/story/3000000307601/von-allmen-holt-olympiagold-in-der-abfahrt-oesterreicher-verpassen-medaille?ref=rss +https://www.derstandard.at/story/3000000307595/-zur-prostitution-gezwungen-und-entf252hrt-junge-frau-in-n214-befreit?ref=rss +https://www.derstandard.at/story/3000000307120/braucht-es-2026-ueberhaupt-noch-feminismus?ref=rss +https://www.derstandard.at/story/3000000307420/wie-gross-sollte-ein-kinderzimmer-sein?ref=rss +https://www.derstandard.at/story/3000000307605/usa-wollen-laut-selenskyj-kriegsende-noch-vor-dem-sommer?ref=rss +https://www.derstandard.at/story/3000000306765/profitieren-wirklich-alle-aktive-fonds-und-lebensversicherungen?ref=rss diff --git a/memory/heartbeat-state.json b/memory/heartbeat-state.json index c16ed26..00b598c 100644 --- a/memory/heartbeat-state.json +++ b/memory/heartbeat-state.json @@ -3,14 +3,45 @@ "usa_iran_attack": true, "rheinmetall_above_1950": false, "steam_hardware_price": false, - "steam_hardware_release_date": false + "steam_hardware_release_date": false, + "hamr_40tb_release": false }, "lastChecks": { "news": "2026-01-30T08:17:00Z", - "rheinmetall": "2026-02-03T22:00:00Z", - "rheinmetall_price": 1773.50, - "calendar": "2026-02-03T22:00:00Z", + "rheinmetall": "2026-02-07T08:41:00Z", + "rheinmetall_price": 1587.00, + "calendar": "2026-02-04T04:25:00Z", "steam_hardware": "2026-02-03T22:00:00Z", - "notes": "RHM: €1,773.50, below threshold. Calendar Feb 4: 'nyc' meeting at 12:00 (video call, no action). Steam hardware: still 'early 2026', no official price/date." + "hamr_40tb": "2026-02-04T21:10:00Z", + "notes": "RHM: €1,902.00, below €1,950 threshold. Steam hardware: still 'early 2026', no official price/date. HAMR 40TB: expected mid-2026, no release date yet." + }, + "watchlist": { + "hamr_40tb": { + "description": "Seagate 40TB HAMR drives (IronWolf Pro / Exos)", + "expectedRelease": "mid-2026", + "notifyOn": "release with price", + "lastCheck": "2026-02-04", + "status": "not yet released" + }, + "steam_hardware": { + "description": "Steam Machine / Steam Frame", + "expectedRelease": "early 2026", + "notifyOn": "official price or release date", + "status": "announced, no price/date" + }, + "openclaw_opus46": { + "description": "OpenClaw support for Claude Opus 4.6", + "pr": "#9863", + "notifyOn": "PR merged or new release with opus-4-6 support", + "lastCheck": "2026-02-05", + "status": "PR open, not merged" + }, + "claude_code_update": { + "description": "Claude Code updates", + "notifyOn": "new version released", + "lastCheck": "2026-02-05", + "lastKnownVersion": null, + "status": "watching" + } } } diff --git a/memory/brain-dump.json b/memory/tasks.json similarity index 100% rename from memory/brain-dump.json rename to memory/tasks.json diff --git a/memory/tv-shows.json b/memory/tv-shows.json new file mode 100644 index 0000000..82d35b2 --- /dev/null +++ b/memory/tv-shows.json @@ -0,0 +1,145 @@ +{ + "description": "TV shows tracking for recommendations", + "shows": [ + { + "title": "Monarch: Legacy of Monsters", + "status": "watching", + "startedWatching": "2026-02-04", + "currentEpisode": 2, + "platform": "Apple TV+", + "genre": ["Sci-Fi", "Fantasy", "Drama", "Action & Adventure"], + "universe": "MonsterVerse (Godzilla)", + "rating": null, + "notes": "Features Kurt Russell & Wyatt Russell. Ask when finished." + }, + { + "title": "Fallout", + "status": "watching", + "season": 2, + "platform": "Prime Video", + "genre": ["Sci-Fi", "Post-apocalyptic", "Drama"], + "notes": "Season 2 finale ready to watch as of Feb 4" + }, + { + "title": "Prodigal Son", + "status": "watched", + "genre": ["Crime", "Drama", "Thriller"], + "notes": "Was watching Feb 3" + }, + { + "title": "Hijack", + "status": "watching", + "season": 2, + "platform": "Apple TV+", + "genre": ["Thriller", "Drama"], + "notes": "S2 finale drops March 4, 2026" + } + ], + "history": [ + { + "title": "Wheel of Time", + "rating": "liked", + "genre": ["Fantasy", "Adventure"] + }, + { + "title": "Stargate SG-1", + "rating": "liked", + "genre": ["Sci-Fi", "Adventure", "Military"] + }, + { + "title": "Stargate Atlantis", + "rating": "liked", + "genre": ["Sci-Fi", "Adventure", "Military"] + }, + { + "title": "Doctor Who", + "rating": "liked", + "genre": ["Sci-Fi", "Adventure", "Time travel"] + }, + { + "title": "Chuck", + "rating": "liked", + "genre": ["Action", "Comedy", "Spy"], + "notes": "Light-hearted spy action" + }, + { + "title": "Sherlock", + "rating": "liked", + "genre": ["Crime", "Mystery", "Drama"] + }, + { + "title": "Psych", + "rating": "liked", + "genre": ["Comedy", "Crime", "Mystery"], + "notes": "Light-hearted crime procedural" + }, + { + "title": "Big Bang Theory", + "rating": "liked", + "genre": ["Sitcom", "Comedy"] + }, + { + "title": "King of Queens", + "rating": "liked", + "genre": ["Sitcom", "Comedy"] + }, + { + "title": "Stranger Things", + "rating": "liked early seasons", + "genre": ["Sci-Fi", "Fantasy", "Horror"], + "notes": "First seasons good, later seasons declined" + }, + { + "title": "Breaking Bad", + "rating": "liked", + "genre": ["Drama", "Crime", "Thriller"] + }, + { + "title": "Ted Lasso", + "rating": "liked", + "genre": ["Comedy", "Feel-good"] + }, + { + "title": "The Boys", + "rating": "liked", + "genre": ["Action", "Superhero", "Dark comedy"] + }, + { + "title": "Jack Ryan", + "rating": "liked", + "genre": ["Action", "Thriller", "Spy"] + }, + { + "title": "Reacher", + "rating": "liked", + "genre": ["Action", "Crime", "Thriller"] + }, + { + "title": "Game of Thrones", + "rating": "no", + "genre": ["Fantasy", "Drama"], + "notes": "Didn't enjoy - but likes other fantasy (Wheel of Time)" + }, + { + "title": "The Office (US)", + "rating": "meh", + "genre": ["Comedy", "Mockumentary"] + } + ], + "notSeen": ["The Expanse", "Succession", "The Bear", "True Detective", "Mindhunter", "Ozark", "What We Do in the Shadows"], + "preferences": { + "likedGenres": ["Sci-Fi", "Action", "Thriller", "Spy", "Crime/Mystery", "Sitcom", "Feel-good comedy", "Fantasy/Adventure"], + "patterns": [ + "Big sci-fi fan (Stargate, Doctor Who, Fallout)", + "Enjoys fantasy adventure (Wheel of Time) - GoT was exception not rule", + "Loves action thrillers (Reacher, Jack Ryan, The Boys)", + "Appreciates light-hearted comedy-action blends (Chuck, Psych)", + "Classic sitcom fan (Big Bang Theory, King of Queens)", + "Likes clever mysteries (Sherlock)", + "Quality drama with tight storytelling (Breaking Bad)", + "Prefers shows that stay focused - lost interest when Stranger Things dragged" + ], + "notLiked": ["Game of Thrones specifically", "Mockumentary style (Office was meh)"], + "notes": ["Broad taste but leans toward fun/adventurous over grimdark"] + } +} diff --git a/memory/wind-down-log.json b/memory/wind-down-log.json index ac831c9..250937c 100644 --- a/memory/wind-down-log.json +++ b/memory/wind-down-log.json @@ -1,223 +1,13 @@ { - "goal": { - "lastTaskDone": "22:00", - "windDownPeriod": "22:00-00:00", - "bedtime": "00:00", - "windDownNeeded": "~2 hours" - }, - "timezone": "Europe/Vienna", - "learningPhase": true, + "date": "2026-02-06", "entries": [ - { - "date": "2026-01-30", - "time": "23:14", - "activity": "nose shower (evening routine)", - "note": "does this every evening" - }, - { - "date": "2026-01-30", - "time": "23:20", - "activity": "tinkering with HA automation", - "note": "setting up morning briefing hook" - }, - { - "date": "2026-01-30", - "time": "23:28", - "activity": "setting up CalDAV access for me", - "note": "still working on integrations" - }, - { - "date": "2026-01-30", - "time": "23:37", - "activity": "still working on HA morning hook", - "note": "acknowledged wants to finish, 23 min to midnight" - }, - { - "date": "2026-01-30", - "time": "23:44", - "activity": "testing morning briefing hook", - "note": "first test - CalDAV didn't work" - }, - { - "date": "2026-01-30", - "time": "23:46", - "activity": "testing morning briefing hook", - "note": "second test - CalDAV worked!" - }, - { - "date": "2026-01-30", - "time": "23:49", - "activity": "starting wind-down", - "note": "watching something, hot beverage" - }, - { - "date": "2026-01-31", - "time": "01:10", - "activity": "bedtime routine", - "note": "brushing teeth, putting cats out" - }, - { - "date": "2026-01-31", - "time": "02:15", - "activity": "going to sleep", - "note": "watched in bed, surfed internet" - }, - { - "date": "2026-01-31", - "time": "19:04", - "activity": "Gitea β†’ Forgejo migration", - "note": "been working for hours already, now on workflow migration to new actions monorepo", - "taskType": "infrastructure/devops tinkering" - }, - { - "date": "2026-01-31", - "time": "19:13", - "activity": "decided to defer script to tomorrow", - "note": "nudge worked! chose pragmatic stopping point: point to GitHub actions, test workflow, script tomorrow", - "nudgeResult": "accepted" - }, - { - "date": "2026-01-31", - "time": "19:56", - "activity": "finished testing workflows", - "note": "tested 2 workflows, both worked. Final switch to Forgejo planned for tomorrow morning. Task wrapped up successfully before 20:00!" - }, - { - "date": "2026-01-31", - "time": "20:13", - "activity": "starting semi wind-down (watching something)", - "note": "usually finishes before 22:00 - on track for goal!" - }, - { - "date": "2026-01-31", - "time": "22:05", - "activity": "bedtime routine starting (brushing teeth)", - "note": "right on schedule! brain-dumped MCP/automation ideas first, then wind-down" - }, - { - "date": "2026-01-31", - "time": "22:32", - "activity": "in bed winding down", - "note": "cat, tea, audiobook - proper relaxation mode" - }, - { - "date": "2026-01-31", - "time": "23:27", - "activity": "going to sleep", - "note": "33 minutes BEFORE midnight goal!" - }, - { - "date": "2026-02-01", - "time": "19:16", - "activity": "relaxing, watching a series", - "note": "already winding down by 19:16 on Sunday - great start!" - }, - { - "date": "2026-02-01", - "time": "20:36", - "activity": "nose shower done", - "note": "completed after episode ended, reminder at 20:10 worked" - }, - { - "date": "2026-02-01", - "time": "23:45", - "activity": "going to sleep", - "note": "15 minutes before midnight goal - on track!" - }, - { - "date": "2026-02-02", - "time": "01:01", - "activity": "couldn't fall asleep, ate a bit, trying again", - "note": "trouble sleeping despite good wind-down timing" - }, - { - "date": "2026-02-02", - "time": "19:22", - "activity": "setting up ci-templates and testing with gbv-aktuell", - "note": "working on workflow optimization from earlier discussion" - }, - { - "date": "2026-02-02", - "time": "22:10", - "activity": "stopped working", - "note": "fixed Deployer issue, called it a day. I failed to suggest stopping points earlier (19:00-22:00)" - }, - { - "date": "2026-02-02", - "time": "22:33", - "activity": "nose shower reminder", - "note": "requested 23 min delay after first reminder" - }, - { - "date": "2026-02-02", - "time": "22:39", - "activity": "nose shower done", - "note": "completed" - }, - { - "date": "2026-02-02", - "time": "22:46", - "activity": "identity setup chat", - "note": "chose Hoid as my identity - relaxed conversation while winding down" - }, - { - "date": "2026-02-02", - "time": "23:51", - "activity": "in bed winding down", - "note": "watching/relaxing more" - }, - { - "date": "2026-02-03", - "time": "00:05", - "activity": "trying to sleep", - "note": "5 min past midnight goal" - }, - { - "date": "2026-02-03", - "time": "19:15", - "activity": "watching Prodigal Son (TV)", - "note": "visited Marie earlier (16:00), now relaxing with a series - good wind-down activity" - }, - { - "date": "2026-02-03", - "time": "21:40", - "activity": "arrived home", - "note": "HomeArrival hook fired, sent nose shower reminder" - } - ], - "patterns": { - "2026-01-30": { - "stoppedWork": "23:49", - "startedBedRoutine": "01:10", - "actualBedtime": "02:15", - "windDownDuration": "~2.5 hours", - "goalMissedBy": "~2h 15min", - "notes": "was tinkering with tools until late, then watched TV + internet in bed" - }, - "2026-01-31": { - "stoppedWork": "19:56", - "startedBedRoutine": "22:05", - "actualBedtime": "23:27", - "windDownDuration": "~1.5 hours", - "goalMetBy": "33 minutes early!", - "notes": "nudge at 19:13 helped defer script task. Proper wind-down: TV, then bed with cat/tea/audiobook. Huge improvement from previous night.", - "sleepOutcome": { - "fellAsleepIn": "~30 min", - "briefWake": "5-6am", - "wokeUp": "08:00", - "totalSleep": "~8 hours", - "quality": "good", - "morningFeeling": "better than last 2 days" - } - }, - "2026-02-02": { - "stoppedWork": "22:10", - "noseShower": "22:39", - "inBed": "23:51", - "tryingSleep": "00:05", - "windDownDuration": "~2 hours", - "goalMissedBy": "~5 min (work ended late at 22:10 instead of 22:00)", - "notes": "I failed at wind-down guidance - helped with work from 19:00 to 22:10 without suggesting stopping points. User called me out, updated HEARTBEAT.md. Bedtime itself was close to goal." - } - } + {"time": "19:30", "activity": "Likely gaming on GPD Win 4 or relaxing β€” no messages since 19:32", "note": "Friday evening, was testing FSR4/Clair Obscur earlier"}, + {"time": "20:54", "activity": "Working β€” fixing a post hook issue in Claude Code", "note": "Said it seems very tricky. Friday evening, still coding."}, + {"time": "21:02", "activity": "Still working on hook issue", "note": "Wants to solve it first, then no plans. Good stopping point once this is done."}, + {"time": "21:31", "activity": "Hook issue solved, now adding NixOS config for persistence", "note": "Scope creep β€” solved the original issue but now starting a new task (NixOS config). 9:30 PM Friday."}, + {"time": "21:32", "activity": "\"Just 1 more try\" on NixOS config", "note": "Committed to wrapping up after this attempt."}, + {"time": "22:37", "activity": "Still working β€” testing cron job fixes", "note": "Past 11:30 PM Friday, still debugging cron. Scope crept from NixOS config to cron testing."}, + {"time": "23:01", "activity": "Done working! Doing nose shower πŸ‘ƒπŸšΏ", "note": "Finally wrapped up. Work ended ~23:00 on a Friday."}, + {"time": "02:12", "activity": "In bed, winding down", "note": "Very late β€” 2:12 AM Saturday. Acknowledges being late."} + ] } From cc5baa712b21c1e1fd1c071f5377292425e0d0d3 Mon Sep 17 00:00:00 2001 From: Agent Date: Sat, 7 Feb 2026 15:37:00 +0000 Subject: [PATCH 06/10] Add audiobooks CLI for Audiobookshelf API access - current/recent/finished/stats/libraries commands - Tab-separated output for minimal tokens - For wind-down suggestions: know what user is listening to --- TOOLS.md | 19 ++++++ bin/audiobooks | 169 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 188 insertions(+) create mode 100755 bin/audiobooks diff --git a/TOOLS.md b/TOOLS.md index 16f0c73..d6a561d 100644 --- a/TOOLS.md +++ b/TOOLS.md @@ -67,6 +67,25 @@ derstandard raw [max] # Full RSS XML 2. Pick interesting ones, optionally fetch full content with `articles` 3. Next briefing: only shows articles published since last check +## Audiobookshelf + +Helper script: `~/clawd/bin/audiobooks` + +```bash +audiobooks current # Currently listening / in-progress books +audiobooks recent [limit] # Recently active books (default: 5) +audiobooks finished [limit] # Finished books (default: 10) +audiobooks stats # Listening stats overview +audiobooks libraries # List libraries +``` + +- Credentials: `.credentials/audiobookshelf.env` +- URL: `https://audiobooks.cloonar.com` +- Output is tab-separated for minimal tokens +- Use during wind-down to suggest continuing audiobook + +--- + ## Forgejo Git Access Helper script: `~/bin/forgejo` diff --git a/bin/audiobooks b/bin/audiobooks new file mode 100755 index 0000000..a46c99c --- /dev/null +++ b/bin/audiobooks @@ -0,0 +1,169 @@ +#!/usr/bin/env node + +const fs = require('fs'); +const path = require('path'); +const https = require('https'); + +const CRED_PATH = path.join(__dirname, '..', '.credentials', 'audiobookshelf.env'); + +function loadCreds() { + const raw = fs.readFileSync(CRED_PATH, 'utf8'); + const env = {}; + for (const line of raw.split('\n')) { + const m = line.match(/^(\w+)=(.+)$/); + if (m) env[m[1]] = m[2]; + } + return env; +} + +function api(endpoint) { + const { AUDIOBOOKSHELF_URL, AUDIOBOOKSHELF_TOKEN } = loadCreds(); + const url = `${AUDIOBOOKSHELF_URL}${endpoint}`; + return new Promise((resolve, reject) => { + const req = https.get(url, { headers: { 'Authorization': `Bearer ${AUDIOBOOKSHELF_TOKEN}` } }, (res) => { + let data = ''; + res.on('data', c => data += c); + res.on('end', () => { + try { resolve(JSON.parse(data)); } + catch { reject(new Error(`Invalid JSON from ${endpoint}`)); } + }); + }); + req.on('error', reject); + req.setTimeout(10000, () => { req.destroy(); reject(new Error('Timeout')); }); + }); +} + +function formatDuration(secs) { + const h = Math.floor(secs / 3600); + const m = Math.floor((secs % 3600) / 60); + if (h > 0) return `${h}h ${m}m`; + return `${m}m`; +} + +function formatProgress(progress) { + return `${Math.round(progress * 100)}%`; +} + +async function cmdCurrent() { + const data = await api('/api/me/items-in-progress'); + const items = data.libraryItems || []; + if (items.length === 0) { + console.log('Nothing in progress.'); + return; + } + for (const item of items) { + const meta = item.media?.metadata || {}; + const title = meta.title || 'Unknown'; + const author = meta.authorName || 'Unknown'; + const narrator = meta.narratorName || '-'; + const series = meta.seriesName || '-'; + const duration = formatDuration(item.media?.duration || 0); + + // Get progress from user's mediaProgress + const me = await api('/api/me'); + const prog = (me.mediaProgress || []).find(p => p.libraryItemId === item.id); + const progress = prog ? formatProgress(prog.progress) : '?'; + const currentTime = prog ? formatDuration(prog.currentTime) : '?'; + const remaining = prog ? formatDuration((item.media?.duration || 0) - (prog.currentTime || 0)) : '?'; + + console.log(`${title}\t${author}\t${series}\t${progress}\t${currentTime}/${duration}\tremaining:${remaining}\tnarrator:${narrator}`); + } +} + +async function cmdLibraries() { + const data = await api('/api/libraries'); + for (const lib of (data.libraries || [])) { + console.log(`${lib.id}\t${lib.name}\t${lib.mediaType}`); + } +} + +async function cmdRecent(args) { + const limit = args[0] || '5'; + const me = await api('/api/me'); + const progress = (me.mediaProgress || []) + .filter(p => !p.isFinished) + .sort((a, b) => (b.lastUpdate || 0) - (a.lastUpdate || 0)) + .slice(0, parseInt(limit, 10)); + + if (progress.length === 0) { + console.log('No recent listening activity.'); + return; + } + + for (const p of progress) { + try { + const item = await api(`/api/items/${p.libraryItemId}?expanded=1`); + const meta = item.media?.metadata || {}; + const title = meta.title || 'Unknown'; + const author = meta.authorName || 'Unknown'; + const series = meta.seriesName || '-'; + const pct = formatProgress(p.progress); + const lastUpdate = new Date(p.lastUpdate).toISOString().slice(0, 10); + console.log(`${title}\t${author}\t${series}\t${pct}\tlast:${lastUpdate}`); + } catch { + // Item might have been removed + } + } +} + +async function cmdFinished(args) { + const limit = args[0] || '10'; + const me = await api('/api/me'); + const finished = (me.mediaProgress || []) + .filter(p => p.isFinished) + .sort((a, b) => (b.finishedAt || 0) - (a.finishedAt || 0)) + .slice(0, parseInt(limit, 10)); + + if (finished.length === 0) { + console.log('No finished books.'); + return; + } + + for (const p of finished) { + try { + const item = await api(`/api/items/${p.libraryItemId}?expanded=1`); + const meta = item.media?.metadata || {}; + const title = meta.title || 'Unknown'; + const author = meta.authorName || 'Unknown'; + const finishedDate = p.finishedAt ? new Date(p.finishedAt).toISOString().slice(0, 10) : '?'; + console.log(`${title}\t${author}\tfinished:${finishedDate}`); + } catch { + // Item might have been removed + } + } +} + +async function cmdStats() { + const me = await api('/api/me'); + const progress = me.mediaProgress || []; + const inProgress = progress.filter(p => !p.isFinished && !p.hideFromContinueListening).length; + const finished = progress.filter(p => p.isFinished).length; + const totalListened = progress.reduce((sum, p) => sum + (p.currentTime || 0), 0); + + console.log(`in-progress:${inProgress}\tfinished:${finished}\ttotal-listened:${formatDuration(totalListened)}`); +} + +// --- Main --- + +const [cmd, ...args] = process.argv.slice(2); + +const run = async () => { + switch (cmd) { + case 'current': await cmdCurrent(); break; + case 'recent': await cmdRecent(args); break; + case 'finished': await cmdFinished(args); break; + case 'stats': await cmdStats(); break; + case 'libraries': await cmdLibraries(); break; + default: + console.log(`Usage: audiobooks + +Commands: + current Currently listening / in-progress books + recent [limit] Recently active books (default: 5) + finished [limit] Finished books (default: 10) + stats Listening stats overview + libraries List libraries`); + } +}; + +run().catch(err => { console.error(`Error: ${err.message}`); process.exit(1); }); From 4be80803d4ffebc23a34302f7e5c43e4e1c1d94a Mon Sep 17 00:00:00 2001 From: Agent Date: Sat, 7 Feb 2026 15:54:48 +0000 Subject: [PATCH 07/10] Pre-compaction memory flush: full day summary --- memory/2026-02-07.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/memory/2026-02-07.md b/memory/2026-02-07.md index cee343b..859f86a 100644 --- a/memory/2026-02-07.md +++ b/memory/2026-02-07.md @@ -23,5 +23,49 @@ - **Alternatives:** Bluetooth A2DP sink (range limited), TCP source (no good Android app yet), AirPlay via Android app (hacky) - User interested but not urgent β€” revisit when asked +## Cron Bug β€” Already Fixed Upstream +- Bug fixed in OpenClaw **2026.2.6** (we're on 2026.2.4) +- Changelog: "prevent recomputeNextRuns from skipping due jobs when timer fires late by reordering onTimer flow" +- PR #10776 by @tyler6204 +- User wants to update OpenClaw (asked, not done yet) + +## Cron Jobs Consolidated +- 8 news jobs β†’ 2 jobs using multi-time cron expressions: `0 10,14,18,22 * * *` +- Der Standard: job ID `917a96d5-14e7-4057-96e5-d83f2729ed9b` +- AI News: job ID `a8991f6b-a31a-4997-bc92-b286573241d4` +- Both confirmed working after fix (14:00 Vienna delivery successful) + +## Tasks CLI (`bin/tasks`) +- Renamed from `brain-dump` to `tasks` +- Data file: `memory/tasks.json` (was `memory/brain-dump.json`) +- Commands: list, add, edit, done, show, nudged, recurring +- Supports both regular tasks and recurring items +- `--due` flag with nudge intervals: now=1d, soon=3d, someday=7d +- Merged `--note` and `--context` into single `--context` field +- Design decision: tasks tool is for actionable items ONLY, not knowledge storage. Reference info goes in memory files where `memory_search` finds it. + +## Audiobookshelf Integration +- Built `bin/audiobooks` CLI tool +- URL: https://audiobooks.cloonar.com +- Credentials stored in `.credentials/audiobookshelf.env` +- Commands: current, recent, finished, stats, libraries +- Currently listening: "Die zweite Legion" (Askir Band 2) by Richard Schwartz β€” 44% done, 8h 46m remaining +- Purpose: wind-down suggestions ("pick up your audiobook") + +## Infuse + Jellyfin +- User uses Infuse app on Apple TV with Jellyfin server +- Asked about syncing watch state from Infuse β†’ Jellyfin +- Infuse has native Jellyfin integration that auto-syncs watch state +- InfuseSync plugin also available (github.com/firecore/InfuseSync) +- Need to confirm: is user using Jellyfin connection or direct file share? +- Task added: `47eaa129` β€” look into Jellyfin playing stats with Intune app on iOS + +## Improvement Ideas Discussed +- Better wind-down: concrete suggestions using audiobook/TV data instead of vague nagging +- Proactive calendar prep: weather, travel time, context from previous visits +- Email triage: decided not worth it (user still uses mail client) +- Workout: not needed (has working app already) +- Decided: keep wind-down in main session (not separate agent) for better context + ## Calendar - Marie besuchen 13:00-17:00 (reminder sent at 11:30 Vienna) From f1db2f3b2dd8cd5df05fd41e944fa21959a57540 Mon Sep 17 00:00:00 2001 From: Agent Date: Sat, 7 Feb 2026 16:09:01 +0000 Subject: [PATCH 08/10] Add Jellyfin CLI + update wind-down instructions with concrete suggestions --- HEARTBEAT.md | 6 ++ TOOLS.md | 22 +++++++ bin/jellyfin | 150 ++++++++++++++++++++++++++++++++++++++++++++++ memory/tasks.json | 7 +++ 4 files changed, 185 insertions(+) create mode 100755 bin/jellyfin diff --git a/HEARTBEAT.md b/HEARTBEAT.md index 829eda9..5926b26 100644 --- a/HEARTBEAT.md +++ b/HEARTBEAT.md @@ -20,6 +20,12 @@ Check the following and notify only once per event (track in `memory/heartbeat-s **If they're about to start something new after 20:00**: Gently suggest postponing to tomorrow. + **Concrete wind-down suggestions**: Don't just say "maybe wind down" β€” use real data: + - `bin/jellyfin resume` β†’ suggest continuing what they're watching + - `bin/jellyfin recent` β†’ suggest something newly added + - `bin/audiobooks current` β†’ suggest picking up their audiobook + - Make it specific: "You're 44% through Die zweite Legion" or "New movie added: The Rip (2026)" + **Work-end reminders**: When they indicate they're wrapping up or transitioning to wind-down, check `memory/tasks.json` for `recurring` items with `when: "evening"` and remind them (e.g., nose shower) before they get too deep into relaxation mode. **πŸ“ AUTO-LOG EVERYTHING 19:00β†’SLEEP** β€” Log to `memory/wind-down-log.json` as events happen: diff --git a/TOOLS.md b/TOOLS.md index d6a561d..ffc3932 100644 --- a/TOOLS.md +++ b/TOOLS.md @@ -86,6 +86,28 @@ audiobooks libraries # List libraries --- +## Jellyfin + +Helper script: `~/clawd/bin/jellyfin` + +```bash +jellyfin resume [limit] # Continue watching (in-progress items) +jellyfin recent [limit] # Recently added to library +jellyfin watched [limit] # Watch history (last played) +jellyfin shows # All series with watch status +jellyfin movies # All movies with watch status +jellyfin search # Search library +jellyfin stats # Watch statistics overview +jellyfin libraries # List libraries +``` + +- Credentials: `.credentials/jellyfin.env` (user-scoped token for `tv`) +- URL: `https://jellyfin.cloonar.com` +- Output is tab-separated for minimal tokens +- Use during wind-down to suggest specific shows/movies + +--- + ## Forgejo Git Access Helper script: `~/bin/forgejo` diff --git a/bin/jellyfin b/bin/jellyfin new file mode 100755 index 0000000..0b26870 --- /dev/null +++ b/bin/jellyfin @@ -0,0 +1,150 @@ +#!/usr/bin/env node +// Jellyfin CLI β€” token-efficient output for assistant use +const https = require('https'); +const fs = require('fs'); +const path = require('path'); + +// Load credentials +const envFile = fs.readFileSync(path.join(__dirname, '..', '.credentials', 'jellyfin.env'), 'utf8'); +const env = {}; +envFile.split('\n').forEach(l => { const [k, ...v] = l.split('='); if (k && v.length) env[k.trim()] = v.join('=').trim(); }); + +const BASE = env.JELLYFIN_URL; +const API_KEY = env.JELLYFIN_API_KEY; +const USER_ID = env.JELLYFIN_USER_ID; + +function api(endpoint) { + const sep = endpoint.includes('?') ? '&' : '?'; + const url = `${BASE}${endpoint}${sep}api_key=${API_KEY}`; + return new Promise((resolve, reject) => { + https.get(url, res => { + let data = ''; + res.on('data', c => data += c); + res.on('end', () => { + try { resolve(JSON.parse(data)); } catch { resolve(data); } + }); + }).on('error', reject); + }); +} + +function getUserId() { return USER_ID; } + +function dur(ticks) { + if (!ticks) return ''; + const min = Math.round(ticks / 600000000); + if (min < 60) return `${min}m`; + return `${Math.floor(min/60)}h${min%60 ? ' '+min%60+'m' : ''}`; +} + +function pct(userData, runTimeTicks) { + if (!userData) return ''; + if (userData.Played) return 'βœ“'; + if (userData.PlayedPercentage) return Math.round(userData.PlayedPercentage) + '%'; + if (userData.PlaybackPositionTicks && runTimeTicks) return Math.round(userData.PlaybackPositionTicks / runTimeTicks * 100) + '%'; + return ''; +} + +const commands = { + async resume(limit = 10) { + const uid = await getUserId(); + const r = await api(`/Users/${uid}/Items/Resume?Limit=${limit}&Fields=Overview,RunTimeTicks&MediaTypes=Video`); + if (!r.Items.length) return console.log('Nothing in progress'); + console.log('TITLE\tEPISODE\tPROGRESS\tDURATION'); + r.Items.forEach(i => { + const show = i.SeriesName || ''; + const name = show ? `${i.Name}` : i.Name; + console.log([show || i.Name, show ? i.Name : '', pct(i.UserData, i.RunTimeTicks), dur(i.RunTimeTicks)].join('\t')); + }); + }, + + async recent(limit = 10) { + const uid = await getUserId(); + const r = await api(`/Users/${uid}/Items/Latest?Limit=${limit}&Fields=RunTimeTicks`); + if (!r.length) return console.log('No recent items'); + console.log('TYPE\tTITLE\tNAME\tYEAR\tDURATION'); + r.forEach(i => { + console.log([i.Type === 'Episode' ? 'EP' : 'MOV', i.SeriesName || i.Name, i.SeriesName ? i.Name : '', i.ProductionYear || '', dur(i.RunTimeTicks)].join('\t')); + }); + }, + + async watched(limit = 20) { + const uid = await getUserId(); + const r = await api(`/Users/${uid}/Items?Limit=${limit}&SortBy=DatePlayed&SortOrder=Descending&Filters=IsPlayed&Recursive=true&IncludeItemTypes=Movie,Episode&Fields=RunTimeTicks,DateLastMediaAdded`); + if (!r.Items.length) return console.log('No watched items'); + console.log('TYPE\tTITLE\tEPISODE\tYEAR'); + r.Items.forEach(i => { + console.log([i.Type === 'Episode' ? 'EP' : 'MOV', i.SeriesName || i.Name, i.SeriesName ? i.Name : '', i.ProductionYear || ''].join('\t')); + }); + }, + + async shows() { + const uid = await getUserId(); + const r = await api(`/Users/${uid}/Items?IncludeItemTypes=Series&Recursive=true&SortBy=SortName&Fields=RunTimeTicks`); + if (!r.Items.length) return console.log('No shows'); + console.log('TITLE\tYEAR\tSTATUS'); + r.Items.forEach(i => { + console.log([i.Name, i.ProductionYear || '', pct(i.UserData, i.RunTimeTicks) || 'unwatched'].join('\t')); + }); + }, + + async movies() { + const uid = await getUserId(); + const r = await api(`/Users/${uid}/Items?IncludeItemTypes=Movie&Recursive=true&SortBy=SortName&Fields=RunTimeTicks`); + if (!r.Items.length) return console.log('No movies'); + console.log('TITLE\tYEAR\tDURATION\tSTATUS'); + r.Items.forEach(i => { + console.log([i.Name, i.ProductionYear || '', dur(i.RunTimeTicks), pct(i.UserData, i.RunTimeTicks) || '-'].join('\t')); + }); + }, + + async search(query) { + if (!query) { console.error('Usage: jellyfin search '); process.exit(1); } + const uid = await getUserId(); + const r = await api(`/Users/${uid}/Items?SearchTerm=${encodeURIComponent(query)}&Recursive=true&IncludeItemTypes=Movie,Series,Episode&Limit=10&Fields=RunTimeTicks`); + if (!r.Items.length) return console.log('No results'); + console.log('TYPE\tTITLE\tNAME\tYEAR'); + r.Items.forEach(i => { + console.log([i.Type, i.SeriesName || i.Name, i.SeriesName ? i.Name : '', i.ProductionYear || ''].join('\t')); + }); + }, + + async stats() { + const uid = await getUserId(); + const [movies, shows, episodes] = await Promise.all([ + api(`/Users/${uid}/Items?IncludeItemTypes=Movie&Recursive=true&Filters=IsPlayed`), + api(`/Users/${uid}/Items?IncludeItemTypes=Series&Recursive=true`), + api(`/Users/${uid}/Items?IncludeItemTypes=Episode&Recursive=true&Filters=IsPlayed`), + ]); + console.log(`Movies watched:\t${movies.TotalRecordCount}`); + console.log(`Shows in library:\t${shows.TotalRecordCount}`); + console.log(`Episodes watched:\t${episodes.TotalRecordCount}`); + }, + + async libraries() { + const uid = getUserId(); + const r = await api(`/Users/${uid}/Views`); + console.log('NAME\tTYPE\tID'); + (r.Items || []).forEach(l => { + console.log([l.Name, l.CollectionType || 'mixed', l.Id].join('\t')); + }); + } +}; + +const cmd = process.argv[2]; +const args = process.argv.slice(3); + +if (!cmd || !commands[cmd]) { + console.log('Usage: jellyfin [args]\n'); + console.log('Commands:'); + console.log(' resume [limit] Continue watching'); + console.log(' recent [limit] Recently added'); + console.log(' watched [limit] Watch history'); + console.log(' shows All series'); + console.log(' movies All movies'); + console.log(' search Search library'); + console.log(' stats Watch statistics'); + console.log(' libraries List libraries'); + process.exit(0); +} + +commands[cmd](...args).catch(e => { console.error(e.message); process.exit(1); }); diff --git a/memory/tasks.json b/memory/tasks.json index 792739a..b1b86a1 100644 --- a/memory/tasks.json +++ b/memory/tasks.json @@ -31,6 +31,13 @@ "text": "TYPO3 v13 upgrade for GBV", "priority": "soon", "lastNudged": "2026-02-07T14:11:07.284Z" + }, + { + "id": "47eaa129", + "added": "2026-02-07", + "text": "Look into Jellyfin playing stats with Intune app on iOS", + "priority": "soon", + "context": "Goal: give Hoid access to TV show watching stats for better wind-down suggestions. Check if Intune/Jellyfin exposes an API for currently watching/recently played." } ] } From ec18f30f6d6545f6f9e6264bec8d9b8ac51d6358 Mon Sep 17 00:00:00 2001 From: Agent Date: Sat, 7 Feb 2026 19:18:34 +0000 Subject: [PATCH 09/10] Add wind-down rules to AGENTS.md + first 19:00 nudge to HEARTBEAT.md --- AGENTS.md | 20 ++++++++++++++++++++ HEARTBEAT.md | 2 ++ memory/ainews-seen.txt | 1 + memory/derstandard-seen.txt | 12 ++++++++++++ memory/tasks.json | 7 ------- memory/wind-down-log.json | 13 ++++--------- 6 files changed, 39 insertions(+), 16 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 796e9cc..5b2bf3c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -48,6 +48,26 @@ Capture what matters. Decisions, context, things to remember. Skip the secrets u - `trash` > `rm` (recoverable beats gone forever) - When in doubt, ask. +### πŸ”‘ Credentials +- **Never read credential files.** Not even to "verify" or "check" them. +- When setting up a new integration, create `.credentials/service.env` with **placeholder values** and let the human fill them in. +- Scripts source credentials at runtime β€” you don't need to see them. +- Example placeholder file: + ``` + SERVICE_URL=https://example.com + SERVICE_API_KEY=FILL_IN + SERVICE_USER=FILL_IN + ``` + +## Evening Wind-Down (19:00-23:00 Vienna) + +After 19:00 Vienna time, you're in wind-down mode. This applies in **all conversations**, not just heartbeats: + +- **If chatting about work/tinkering**: Actively look for stopping points. When a subtask completes or there's a natural pause, suggest wrapping up. Don't just passively help them keep going. +- **If they want to start something new after 20:00**: Gently suggest postponing to tomorrow. +- **Concrete suggestions**: Use `bin/jellyfin` and `bin/audiobooks` to suggest specific shows/audiobooks instead of vague "maybe wind down." +- **Evening reminders**: When they're transitioning to wind-down, remind about evening recurring tasks (e.g., nose shower) before they get too comfortable. + ## External vs Internal **Safe to do freely:** diff --git a/HEARTBEAT.md b/HEARTBEAT.md index 5926b26..497c8ec 100644 --- a/HEARTBEAT.md +++ b/HEARTBEAT.md @@ -8,6 +8,8 @@ Check the following and notify only once per event (track in `memory/heartbeat-s 3. **Evening wind-down guidance (19:00-22:00 Vienna)**: + **First nudge at 19:00**: On the first heartbeat at/after 19:00 Vienna, always check in β€” ask what they're doing if not in active conversation, or nudge toward winding down if already chatting about work/tinkering. + **Active work detection**: If user is chatting with me about work tasks, I KNOW they're working. Don't just passively help β€” actively look for stopping points. **During work conversations after 19:00**: diff --git a/memory/ainews-seen.txt b/memory/ainews-seen.txt index 57864b6..e215e99 100644 --- a/memory/ainews-seen.txt +++ b/memory/ainews-seen.txt @@ -80,3 +80,4 @@ https://magazine.sebastianraschka.com/p/llm-research-papers-the-2024-list https://magazine.sebastianraschka.com/p/understanding-multimodal-llms https://simonwillison.net/2026/Feb/6/tom-dale/#atom-everything https://simonwillison.net/2026/Feb/6/pydantic-monty/#atom-everything +https://simonwillison.net/2026/Feb/7/software-factory/#atom-everything diff --git a/memory/derstandard-seen.txt b/memory/derstandard-seen.txt index 6af8197..1e5a76b 100644 --- a/memory/derstandard-seen.txt +++ b/memory/derstandard-seen.txt @@ -73,3 +73,15 @@ https://www.derstandard.at/story/3000000307120/braucht-es-2026-ueberhaupt-noch-f https://www.derstandard.at/story/3000000307420/wie-gross-sollte-ein-kinderzimmer-sein?ref=rss https://www.derstandard.at/story/3000000307605/usa-wollen-laut-selenskyj-kriegsende-noch-vor-dem-sommer?ref=rss https://www.derstandard.at/story/3000000306765/profitieren-wirklich-alle-aktive-fonds-und-lebensversicherungen?ref=rss +https://www.derstandard.at/story/3000000306828/in-den-usa-haben-nazi-vergleiche-hochkonjunktur?ref=rss +https://www.derstandard.at/story/3000000306837/moltbook-apokalypse-und-shitposting?ref=rss +https://www.derstandard.at/story/3000000306928/vom-ich-zum-du-100-tage-als-personenbetreuer-beduerftiger-menschen?ref=rss +https://www.derstandard.at/story/3000000307507/warum-thailand-bei-der-cannabis-legalisierung-zurueckgerudert-ist?ref=rss +https://www.derstandard.at/story/3000000306092/zukunftsforscher-gen-z-boomer-millennials-sind-keine-guten-kategorien?ref=rss +https://www.derstandard.at/story/3000000307298/lady-gaga-adrien-brody-friends-hoehepunkte-der-super-bowl-spots?ref=rss +https://www.derstandard.at/story/3000000306983/gesuender-essen-im-alltag-11-expertentipps-die-zeigen-wie-es-gelingen-kann?ref=rss +https://www.derstandard.at/story/3000000307609/buhrufe-fuer-vance-bei-olympia-eroeffnung-waren-im-us-tv-nicht-zu-hoeren?ref=rss +https://www.derstandard.at/story/3000000306833/olympia-biathletin-slettemark-niemand-in-groenland-will-zum-amerikaner-werden?ref=rss +https://www.derstandard.at/story/3000000303500/kunstduenger-ruiniert-millionen-alte-prozesse-im-boden?ref=rss +https://www.derstandard.at/story/3000000307033/wo-sind-die-games-fuer-einen-einzelnen-abend?ref=rss +https://www.derstandard.at/story/3000000307298/warum-thailand-bei-der-cannabis-legalisierung-zurueckgerudert-ist?ref=rss diff --git a/memory/tasks.json b/memory/tasks.json index b1b86a1..792739a 100644 --- a/memory/tasks.json +++ b/memory/tasks.json @@ -31,13 +31,6 @@ "text": "TYPO3 v13 upgrade for GBV", "priority": "soon", "lastNudged": "2026-02-07T14:11:07.284Z" - }, - { - "id": "47eaa129", - "added": "2026-02-07", - "text": "Look into Jellyfin playing stats with Intune app on iOS", - "priority": "soon", - "context": "Goal: give Hoid access to TV show watching stats for better wind-down suggestions. Check if Intune/Jellyfin exposes an API for currently watching/recently played." } ] } diff --git a/memory/wind-down-log.json b/memory/wind-down-log.json index 250937c..1d648b6 100644 --- a/memory/wind-down-log.json +++ b/memory/wind-down-log.json @@ -1,13 +1,8 @@ { - "date": "2026-02-06", + "date": "2026-02-07", "entries": [ - {"time": "19:30", "activity": "Likely gaming on GPD Win 4 or relaxing β€” no messages since 19:32", "note": "Friday evening, was testing FSR4/Clair Obscur earlier"}, - {"time": "20:54", "activity": "Working β€” fixing a post hook issue in Claude Code", "note": "Said it seems very tricky. Friday evening, still coding."}, - {"time": "21:02", "activity": "Still working on hook issue", "note": "Wants to solve it first, then no plans. Good stopping point once this is done."}, - {"time": "21:31", "activity": "Hook issue solved, now adding NixOS config for persistence", "note": "Scope creep β€” solved the original issue but now starting a new task (NixOS config). 9:30 PM Friday."}, - {"time": "21:32", "activity": "\"Just 1 more try\" on NixOS config", "note": "Committed to wrapping up after this attempt."}, - {"time": "22:37", "activity": "Still working β€” testing cron job fixes", "note": "Past 11:30 PM Friday, still debugging cron. Scope crept from NixOS config to cron testing."}, - {"time": "23:01", "activity": "Done working! Doing nose shower πŸ‘ƒπŸšΏ", "note": "Finally wrapped up. Work ended ~23:00 on a Friday."}, - {"time": "02:12", "activity": "In bed, winding down", "note": "Very late β€” 2:12 AM Saturday. Acknowledges being late."} + {"time": "19:14", "activity": "Tinkering β€” troubleshooting Bazzite suspend/resume + VRAM on GPD Win 4", "note": "Saturday evening, tech tinkering not deep work. Active conversation."}, + {"time": "19:44", "activity": "Still GPD tinkering β€” fixed VRAM (8GB via UMAF), narrowed suspend crash to CPU hotplug (PowerTools core parking + SMT)", "note": "Making progress, having fun with it. Not work."}, + {"time": "20:10", "activity": "Done tinkering β€” nosmt kernel param fixed suspend. Switching to YouTube then TV/audiobook", "note": "Good wind-down transition. Reminded about nose shower."} ] } From 66423cf66b1b6fe93d18f8419b37872fff3e7901 Mon Sep 17 00:00:00 2001 From: Agent Date: Sat, 7 Feb 2026 19:20:12 +0000 Subject: [PATCH 10/10] Remove redundant work-detection from HEARTBEAT.md (now in AGENTS.md) --- HEARTBEAT.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/HEARTBEAT.md b/HEARTBEAT.md index 497c8ec..7f912bd 100644 --- a/HEARTBEAT.md +++ b/HEARTBEAT.md @@ -10,18 +10,8 @@ Check the following and notify only once per event (track in `memory/heartbeat-s **First nudge at 19:00**: On the first heartbeat at/after 19:00 Vienna, always check in β€” ask what they're doing if not in active conversation, or nudge toward winding down if already chatting about work/tinkering. - **Active work detection**: If user is chatting with me about work tasks, I KNOW they're working. Don't just passively help β€” actively look for stopping points. - - **During work conversations after 19:00**: - - Track how long the current task has been going - - When a subtask completes or there's a natural pause, suggest: "This might be a good stopping point for tonight" - - If a task is dragging on (30+ min with no end in sight), gently note: "This is getting complex β€” want to pick it up tomorrow with fresh eyes?" - - Don't wait for them to ask β€” proactively identify when a task can be paused - **If NOT in active conversation**: Send a brief WhatsApp asking what they're doing (working? winding down? about to start something new?). Log responses in `memory/wind-down-log.json`. - **If they're about to start something new after 20:00**: Gently suggest postponing to tomorrow. - **Concrete wind-down suggestions**: Don't just say "maybe wind down" β€” use real data: - `bin/jellyfin resume` β†’ suggest continuing what they're watching - `bin/jellyfin recent` β†’ suggest something newly added