Journal Update Directions¶
How to detect activity and append journal Log entries — format, synthesis rules, approval flow
When to use¶
user wants to update their journal with recent activity
Slash command: /wb-journal-update
Linked workflow: daily-journal/update-journal
Related capabilities¶
journal/journal_statejournal/journal_writecontext/context_bundle
Directions¶
Start via mcp__work-buddy__wb_run("update-journal"). Advance with wb_advance after each step.
Target date: Defaults to the backend-resolved logical Journal day. Do not ask a civil-midnight today/yesterday question; the configured timezone and day-boundary policy is authoritative. Ask only when the user supplies an ambiguous explicit date reference that the policy cannot resolve.
Synthesis instructions¶
The Log is a near-real-time event log, not a high-level summary. Each entry anchors a thing that happened at a specific time.
Format (attributed): *
Rules: 1. One entry per distinct activity -- a commit, a completed task, a bug fix. If 6 things happened, produce ~4-6 entries. 2. Timestamps from the data -- minute-level. 1:11 PM not 1:00 PM. Never round. 3. Describe the work, not the tools -- 'Fixed vault path normalization' not '1 commit to work-buddy' 4. Aggregate only when truly redundant -- 3 commits fixing same bug = one entry. But bug fix + feature + docs = three entries. 5. Commits and task completions are primary evidence. 6. Keep entries short -- one line, one topic. 7. Cover the full window -- if last entry timestamp is well before collect_until, something was missed.
Sources you MUST consult before synthesizing¶
The collect step writes a bundle directory. Read EVERY relevant file before drafting entries — a single source is never sufficient. Gaps here are how entire days of paper-lane work get silently dropped.
git_summary.md— multi-repo scan across ALL repos underrepos_root. Each commit is bucketed under#### <project>subheadings. This is the primary git evidence; trust it for commit-level activity in every registered project.chat_summary.md— in a bundle this carries only SpecStory + CLI history (the agent-harness conversations live inagent_session_summary.md, source 3). It may be absent entirely when nothing falls in the window — that is expected, not a gap.agent_session_summary.md— the interpreted surface, and your primary conversation evidence. Agent-session activity (Claude Code, Codex, …) from the conversation_observability DB, one block per project. Each session lists its tldr, a topic timeline with wall-clock time ranges, commits, uncommitted files, and PR activity. When a session has no summary yet (opted out, errored, or not yet generated) afirst message:line stands in. A session with a multi-hour span and no commits is exploration you should still log; if it appears here with uncommitted files but no row ingit_summary.md, that is real unfinished work, not a gap.obsidian_summary.md— Running Notes additions, task completions, journal sign-in.session_activity_summary.md— MCP gateway events for THIS session only; useful for sanity-checking your own actions but not project-wide activity.
Every bundle file opens with a *Window: …* banner stating the exact window it covers; the sources are scoped to the journal's activity window, so what you see already belongs to the target day.
Drill when a session is opaque. If agent_session_summary.md shows a long session with no commits and its topic titles don't tell you what happened, call conversation_observability_get(session_id, include_topics=true, include_writes=true) for the full per-session picture before logging (or leaving out) that exploration. summary_search finds sessions across the store by topic.
If you produce a draft Log that mentions only one project across an active multi-hour day, treat that as a smell and re-check sources 1, 2, and 3 before presenting it to the user.
Timestamp semantics across the bundle¶
- All bundle timestamps are local wall-clock time (the configured
timezone/USER_TZ), with no "UTC" label. Times ingit_summary.md,chat_summary.md,agent_session_summary.md, andobsidian_summary.mdsit on one local timeline, so they can be compared and ordered directly — and they line up with the journal's own local Sign-In, office-arrival, and Log times. Place events at the local time shown. - Chat and SpecStory sessions are windowed by real conversation time, not file mtime. A Claude Code session's window membership comes from its message-derived start/end; a SpecStory session's from its filename stamp. A session resumed today but whose conversation happened days ago will NOT appear in today's window — and
chat_summary.mdlabels every session with its real start/end, so a session header's date is the date the conversation actually happened.
Approval + dedup — REQUIRED before any write¶
Two gates stand between a draft and journal_write. Both are mandatory every run, including backfills:
- Dedupe against what is already there. Before presenting, call
journal_statefor each target day and read its existing Log entries. Drop any draft entry whose activity is already logged (same activity/time). When backfilling a multi-day window, whole days are often already covered — skip those days entirely. The write must be idempotent and safe to re-run. - Get explicit user approval. Present the deduped entries (grouped by day; name the days you are skipping as already-covered) and wait for an explicit go-ahead. The user may edit, reword, add, or remove. Do NOT call
journal_writeuntil they approve — a verbal "looks good / proceed" counts; silence does not. When presenting, you MUST also call out every entry you left unattributed ("N entries I couldn't attribute to a project: …") so the omissions are visible and auditable — never omit a project tag silently.
Note: journal_write is itself consent-gated by the Obsidian bridge — each call raises a surface consent prompt (Obsidian / dashboard / Telegram), separate from the in-chat approval above. For a multi-day backfill, tell the user they can approve once with "Allow always (this session)" so the writes do not stack one prompt per day.
Calling journal_write¶
The entries parameter is a JSON string containing a list of [time, description] tuples — NOT pre-formatted vault lines. The function handles vault formatting (bullets, tags) internally. Each description should INCLUDE the #projects/<slug> prefix when the entry was attributed; entries you deliberately left unattributed (after a failed match) carry no project prefix.
Example:
`mcp__work-buddy__wb_run("journal_write", {
"target": "YYYY-MM-DD",
"entries": "[[\"6:08 PM\", \"#projects/work-buddy — Fixed consent nesting bug.\"], [\"7:52 PM\", \"#projects/ecg-inquiry — Added grader run for 32 ECG batch.\"]]"
})`
Do NOT pass pre-formatted strings like * 6:08 PM - Description. #wb/journal/log — pass raw [time, description] pairs and let the function format them.
Don'ts¶
- Don't fabricate activity not in the signals
- Don't repeat information already in existing Log entries
- Don't include raw git hashes or file paths unless they add meaning
- Don't add entries to sections other than Log
- Don't synthesize from a single source — always cross-reference git + chat + agent_session_summary + obsidian
- Don't omit a project tag out of laziness — you MUST run
project_listand attempt resolution first; omit only after a genuine failed match, and always flag the omission at approval - Don't invent
#projects/unknownor any placeholder slug for non-project activity — a genuine life event simply carries no project tag
--- context from: obsidian/bridge ---