diff --git a/AGENTS.md b/AGENTS.md index 5b2bf3c..796e9cc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -48,26 +48,6 @@ 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 7f912bd..624e690 100644 --- a/HEARTBEAT.md +++ b/HEARTBEAT.md @@ -8,17 +8,19 @@ 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**: + - 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`. - **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)" + **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/tasks.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/brain-dump.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.) @@ -42,18 +44,10 @@ 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. **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. +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. 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 ffc3932..5d0d3a8 100644 --- a/TOOLS.md +++ b/TOOLS.md @@ -67,47 +67,6 @@ 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 - ---- - -## 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` @@ -178,30 +137,28 @@ ainews reset # Clear seen history ## Brain Dump CLI -Helper script: `~/clawd/bin/tasks` +Helper script: `~/clawd/bin/brain-dump` ```bash -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 +brain-dump list [--priority now,soon] [--due] [--limit N] +brain-dump add --text "..." --priority soon [--context "..."] +brain-dump edit [--text "..."] [--priority ...] [--context "..."] +brain-dump done +brain-dump show +brain-dump nudged ,,... +brain-dump recurring [--when evening] ``` -- Data: `memory/tasks.json` +- 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 all recurring items with full context (note, when, frequency) -- `add --recurring` / `edit` / `done` work for both tasks and recurring items +- `recurring` lists recurring reminders (nose shower etc.) - Output is tab-separated for minimal tokens **Heartbeat workflow:** -1. `tasks list --due --limit 2` β†’ get tasks needing a nudge +1. `brain-dump list --due --limit 2` β†’ get tasks needing a nudge 2. Mention them conversationally -3. `tasks nudged ,` β†’ mark as nudged +3. `brain-dump nudged ,` β†’ mark as nudged --- diff --git a/bin/audiobooks b/bin/audiobooks deleted file mode 100755 index a46c99c..0000000 --- a/bin/audiobooks +++ /dev/null @@ -1,169 +0,0 @@ -#!/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); }); diff --git a/bin/tasks b/bin/brain-dump similarity index 51% rename from bin/tasks rename to bin/brain-dump index 63f53fa..7394c08 100755 --- a/bin/tasks +++ b/bin/brain-dump @@ -4,7 +4,7 @@ const fs = require('fs'); const path = require('path'); const crypto = require('crypto'); -const DUMP_PATH = path.join(__dirname, '..', 'memory', 'tasks.json'); +const DUMP_PATH = path.join(__dirname, '..', 'memory', 'brain-dump.json'); const NUDGE_INTERVALS = { now: 24 * 60 * 60 * 1000, // 1 day @@ -41,31 +41,29 @@ function formatTask(t) { return line; } -function formatRecurring(r) { - let line = `${r.id}\t${r.frequency}\t${r.when || '-'}\t${r.text}`; - 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)); @@ -82,112 +80,72 @@ 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(); - - if (isRecurring) { - const frequency = getFlag(args, '--frequency') || 'daily'; - const when = getFlag(args, '--when') || undefined; - const item = { id: shortId(), text, frequency }; - if (when) item.when = when; - 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}`); - } + 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: tasks edit [--text ...] [--priority ...] [--context ...] [--frequency ...] [--when ...]'); process.exit(1); } + if (!id) { console.error('Usage: brain-dump edit [--text ...] [--priority ...] [--context ...]'); process.exit(1); } const data = load(); - - // 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 task = (data.tasks || []).find(t => t.id === id); + if (!task) { console.error(`Task ${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 (isRecurring) { - const frequency = getFlag(args, '--frequency'); - const when = getFlag(args, '--when'); - if (frequency) item.frequency = frequency; - if (when) item.when = when; - 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)}`); - } + 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)}`); } function cmdDone(args) { const id = args[0]; - if (!id) { console.error('Usage: tasks done '); process.exit(1); } + 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); } - // 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); + const removed = data.tasks.splice(idx, 1)[0]; + save(data); + console.log(`Done: ${removed.text}`); } function cmdShow(args) { const id = args[0]; - if (!id) { console.error('Usage: tasks show '); process.exit(1); } + if (!id) { console.error('Usage: brain-dump show '); process.exit(1); } const data = load(); - 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); } + const task = (data.tasks || []).find(t => t.id === id); + if (!task) { console.error(`Task ${id} not found.`); process.exit(1); } - console.log(JSON.stringify(item, null, 2)); + console.log(JSON.stringify(task, null, 2)); } function cmdNudged(args) { const ids = (args[0] || '').split(',').map(s => s.trim()).filter(Boolean); - if (ids.length === 0) { console.error('Usage: tasks nudged ,,...'); process.exit(1); } + if (ids.length === 0) { console.error('Usage: brain-dump nudged ,,...'); process.exit(1); } const data = load(); const now = new Date().toISOString(); @@ -203,15 +161,19 @@ function cmdNudged(args) { console.log(`Marked ${count} task(s) as nudged.`); } -function cmdRecurring() { +function cmdRecurring(args) { const data = load(); - const items = data.recurring || []; + const when = getFlag(args, '--when'); + let items = data.recurring || []; + if (when) { + items = items.filter(r => r.when === when); + } if (items.length === 0) { console.log('No recurring items.'); return; } for (const r of items) { - console.log(formatRecurring(r)); + console.log(`${r.id}\t${r.frequency}\t${r.when || '-'}\t${r.text}`); } } @@ -234,17 +196,16 @@ switch (cmd) { case 'done': cmdDone(args); break; case 'show': cmdShow(args); break; case 'nudged': cmdNudged(args); break; - case 'recurring': cmdRecurring(); break; + case 'recurring': cmdRecurring(args); break; default: - console.log(`Usage: tasks + console.log(`Usage: brain-dump Commands: list [--priority now,soon] [--due] [--limit N] add --text "..." --priority soon [--context "..."] - add --recurring --text "..." --frequency daily [--when evening] [--context "..."] - edit [--text "..."] [--priority|--frequency|--when|--context "..."] + edit [--text "..."] [--priority ...] [--context "..."] done show nudged ,,... - recurring`); + recurring [--when evening]`); } diff --git a/bin/jellyfin b/bin/jellyfin deleted file mode 100755 index 0b26870..0000000 --- a/bin/jellyfin +++ /dev/null @@ -1,150 +0,0 @@ -#!/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/2026-02-06.md b/memory/2026-02-06.md deleted file mode 100644 index f664689..0000000 --- a/memory/2026-02-06.md +++ /dev/null @@ -1,23 +0,0 @@ -# 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 deleted file mode 100644 index 859f86a..0000000 --- a/memory/2026-02-07.md +++ /dev/null @@ -1,71 +0,0 @@ -# 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 - -## 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) diff --git a/memory/ainews-seen.txt b/memory/ainews-seen.txt index e215e99..6e9215f 100644 --- a/memory/ainews-seen.txt +++ b/memory/ainews-seen.txt @@ -1,83 +1,15 @@ -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 -https://simonwillison.net/2026/Feb/7/software-factory/#atom-everything diff --git a/memory/tasks.json b/memory/brain-dump.json similarity index 63% rename from memory/tasks.json rename to memory/brain-dump.json index 792739a..0bd1eee 100644 --- a/memory/tasks.json +++ b/memory/brain-dump.json @@ -2,35 +2,35 @@ "description": "Task tracking β€” auto-captured from chat or manually added. Done tasks get deleted.", "recurring": [ { - "id": "843efabf", + "id": "nose-shower", "text": "Nose shower πŸ‘ƒπŸšΏ", "frequency": "daily", "when": "evening", - "context": "Remind in evening, whether work just wrapped up or already relaxing" + "note": "Remind in evening, whether work just wrapped up or already relaxing" } ], "tasks": [ { - "id": "b9d1d89e", - "added": "2026-02-07", + "id": "forgejo-script", + "added": "2026-01-31", "text": "Create script to auto-update workflows to Forgejo monorepo actions", - "priority": "someday", - "context": "Monorepo is done, using GitHub actions as fallback for now" + "context": "Monorepo is done, using GitHub actions as fallback for now", + "priority": "someday" }, { - "id": "af198211", - "added": "2026-02-07", + "id": "forgejo-mcp-server", + "added": "2026-01-31", "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.", - "lastNudged": "2026-02-07T14:11:07.284Z" + "priority": "soon", + "lastNudged": "2026-02-07T13:59:36.313Z" }, { - "id": "0902aaba", - "added": "2026-02-07", + "id": "typo3-v13-gbv", + "added": "2026-02-01", "text": "TYPO3 v13 upgrade for GBV", "priority": "soon", - "lastNudged": "2026-02-07T14:11:07.284Z" + "lastNudged": "2026-02-07T13:59:36.313Z" } ] } diff --git a/memory/calendar-reminders-sent.json b/memory/calendar-reminders-sent.json index 701c1d4..ebffaad 100644 --- a/memory/calendar-reminders-sent.json +++ b/memory/calendar-reminders-sent.json @@ -1,5 +1,3 @@ { - "sent": [ - {"event": "Marie besuchen", "date": "2026-02-07", "remindedAt": "2026-02-07T09:31:00Z"} - ] + "sent": [] } diff --git a/memory/derstandard-seen.txt b/memory/derstandard-seen.txt index 1e5a76b..0a9f5d5 100644 --- a/memory/derstandard-seen.txt +++ b/memory/derstandard-seen.txt @@ -1,87 +1,49 @@ -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/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/3000000253356/finde-den-fehler?ref=rss https://www.derstandard.at/story/3000000306814/cartoons-februar?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 -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 +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 diff --git a/memory/heartbeat-state.json b/memory/heartbeat-state.json index 00b598c..c16ed26 100644 --- a/memory/heartbeat-state.json +++ b/memory/heartbeat-state.json @@ -3,45 +3,14 @@ "usa_iran_attack": true, "rheinmetall_above_1950": false, "steam_hardware_price": false, - "steam_hardware_release_date": false, - "hamr_40tb_release": false + "steam_hardware_release_date": false }, "lastChecks": { "news": "2026-01-30T08:17:00Z", - "rheinmetall": "2026-02-07T08:41:00Z", - "rheinmetall_price": 1587.00, - "calendar": "2026-02-04T04:25:00Z", + "rheinmetall": "2026-02-03T22:00:00Z", + "rheinmetall_price": 1773.50, + "calendar": "2026-02-03T22:00:00Z", "steam_hardware": "2026-02-03T22:00:00Z", - "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" - } + "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." } } diff --git a/memory/tv-shows.json b/memory/tv-shows.json deleted file mode 100644 index 82d35b2..0000000 --- a/memory/tv-shows.json +++ /dev/null @@ -1,145 +0,0 @@ -{ - "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 1d648b6..ac831c9 100644 --- a/memory/wind-down-log.json +++ b/memory/wind-down-log.json @@ -1,8 +1,223 @@ { - "date": "2026-02-07", + "goal": { + "lastTaskDone": "22:00", + "windDownPeriod": "22:00-00:00", + "bedtime": "00:00", + "windDownNeeded": "~2 hours" + }, + "timezone": "Europe/Vienna", + "learningPhase": true, "entries": [ - {"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."} - ] + { + "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." + } + } }