feat: add Diary — passive read-only view of heartbeat cycles#126
Merged
luokerenx4 merged 4 commits intomasterfrom Apr 16, 2026
Merged
feat: add Diary — passive read-only view of heartbeat cycles#126luokerenx4 merged 4 commits intomasterfrom
luokerenx4 merged 4 commits intomasterfrom
Conversation
Restructure the top section into a proper centered hero: logo (140px) above an h1 title, tagline split into bold one-liner + descriptive subtitle, badges row, then preview image. Move feature bullets below the hero so the visual identity reads cleanly before content. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…s feed
Heartbeat already writes every cycle (prompt, reasoning, tool calls, reply) to
an isolated SessionStore('heartbeat'), but that record was never surfaced to
the UI. The Chat window received only the subset of cycles that produced
CHAT_YES notifications, conflating "Alice has something to tell you"
(notification) with "what Alice has been thinking" (status).
This adds a dedicated /activity page — read-only, one-speaker, passive — that
renders the heartbeat session joined with heartbeat.{done,skip,error} event
outcomes. Chat behavior is untouched; notifications still flow there as before.
Backend uses a single polling endpoint (GET /api/activity/history?afterSeq=)
rather than SSE. Heartbeat fires ~every 30min, so a persistent subscription
would be engineering weight for no user-visible benefit. The UI polls on
mount, window focus, and a 60s interval gated on document visibility.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The page was poorly named — "activity" evokes a machine operation log, but the intent is to expose Alice's heartbeat-cycle thoughts, which is closer to a diary than a system feed. Promotes the nav entry out of "Agent" and up to the top section alongside Chat / Portfolio / News, matching its importance. Visual redesign drops Chat's two-speaker bubble metaphor. Each heartbeat cycle renders as a self-contained card (timestamp · outcome chip · body) with sticky date dividers grouping Today / Yesterday / older days. Cycles with no interesting body (duplicate / empty / outside-hours) collapse to slim divider rows so they don't crowd the real content. Extracted MarkdownContent from ChatMessage for reuse without inheriting chat chrome. Also fixes a data-fetch bug: the route was reading heartbeat events from the in-memory ring buffer, which gets saturated by high-frequency events (snapshot.skipped, account.health) and evicts the ~30min-spaced heartbeat entries we care about. Switched to a disk read with in-memory type filtering — cheaper than three separate recent() calls, and correct regardless of buffer churn. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The UI's tsc -b (used by CI) runs with a stricter project configuration that doesn't expose the global JSX namespace. Switching to ReactNode also reads more naturally for return-type annotations in modern React. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a dedicated Diary page that exposes Alice's heartbeat session as a passive, read-only feed — separating "what she's been thinking" from "what she has to tell you" (which stays in Chat).
/api/diary/historyreadingSessionStore('heartbeat')+ joining heartbeat events from the event log/diarypage in the UI, nav entry promoted to the top section alongside Chat / Portfolio / NewsMarkdownContentfromChatMessagefor reuse across surfacesAlso bundled: earlier README hero redesign commit (
627b984) that was sitting on dev.Design notes
ConnectorCenterandWebConnectorare untouched — CHAT_YES heartbeat replies continue to push to Chat as before.heartbeatsession file; no new storage.heartbeat.done/skip/error) are read from disk (eventLog.read()) rather than the in-memory ring buffer — the ring buffer gets saturated by high-frequency events (snapshot.skipped,account.health) and evicts the ~30min-spaced heartbeat entries.Test plan
npx tsc --noEmitpassespnpm test— all 1015 tests pass; 15 new tests insrc/connectors/web/__tests__/diary.spec.tscover event → cycle projectionPOST /api/heartbeat/trigger, verify it appears in/diarywithin the 60s poll window and that Chat behavior is unchanged🤖 Generated with Claude Code