Resume: pickup-from-Next-Steps fix + capture tasks with context#224
Conversation
The resume brief now surfaces what to DO next, not a backward recap.
- Summarizer (spawn-wiki-worker): add a `## Next Steps` section — one
imperative line to resume with, or literal "none" on a clean stop.
- resume-brief: walk the last 5 summaries for the project newest-first and
resolve to one of three outcomes:
1. most recent session with open work → "you left off here: <next step>"
+ a pick-it-up CTA. Pointer comes from `## Next Steps`, falling back
to the older `## Open Questions / TODO` so existing summaries work
tonight (before any new-format summary accumulates).
2. summaries exist but every recent session wrapped clean → a brief with
NO call to action ("wrapped up clean, nothing pending") — we don't
invent an action.
3. no summaries for the project → null; caller renders plain welcome.
Empty / "none" / "n/a" sections count as wrapped-clean.
Still userVisibleOnly (caller renders to systemMessage only). Replaces the
first-"What Happened"-sentence pointer with the new extractNextSteps; tests
updated.
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThe PR introduces a "Next Steps" tracking mechanism for session summaries. The wiki worker prompt now instructs output of a ChangesResume-brief next-steps extraction
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Coverage ReportScope: files changed in this PR. Enforced threshold: 90% per metric (per file via
File Coverage — 7 files changed
Generated for commit e9291ab. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/notifications/sources/resume-brief.ts`:
- Around line 101-103: Currently the code uses truthiness of s.get("next steps")
so an empty string or markers like "none"/"n/a" are treated as missing and it
falls back to other sections; change the selection logic to prefer the "next
steps" key when it exists (use s.has("next steps") or check for undefined
specifically) and accept empty/"none"/"n/a" as a valid body instead of falling
back — i.e., if s.has("next steps") then use s.get("next steps") (optionally
normalize whitespace and case for "none"/"n/a" but still treat them as present),
otherwise check "open questions / todo" and "open questions".
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 01fd64b9-0c27-4616-9133-e38fe8531b43
📒 Files selected for processing (3)
src/hooks/spawn-wiki-worker.tssrc/notifications/sources/resume-brief.tstests/claude-code/resume-brief.test.ts
| const s = sections(summary); | ||
| const body = s.get("next steps") || s.get("open questions / todo") || s.get("open questions") || ""; | ||
| if (!body) return ""; |
There was a problem hiding this comment.
Don't fall back when ## Next Steps exists but is blank.
Line 102 currently treats an empty ## Next Steps body as “missing” and falls through to ## Open Questions / TODO. That violates the new contract that empty/none/n/a means “wrapped clean,” and it can surface stale TODOs as the resume CTA.
Suggested fix
export function extractNextSteps(summary: string): string {
const s = sections(summary);
- const body = s.get("next steps") || s.get("open questions / todo") || s.get("open questions") || "";
+ const body = s.has("next steps")
+ ? (s.get("next steps") ?? "")
+ : (s.get("open questions / todo") || s.get("open questions") || "");
if (!body) return "";
for (const raw of body.split(/\r?\n/)) {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/notifications/sources/resume-brief.ts` around lines 101 - 103, Currently
the code uses truthiness of s.get("next steps") so an empty string or markers
like "none"/"n/a" are treated as missing and it falls back to other sections;
change the selection logic to prefer the "next steps" key when it exists (use
s.has("next steps") or check for undefined specifically) and accept
empty/"none"/"n/a" as a valid body instead of falling back — i.e., if
s.has("next steps") then use s.get("next steps") (optionally normalize
whitespace and case for "none"/"n/a" but still treat them as present), otherwise
check "open questions / todo" and "open questions".
There was a problem hiding this comment.
It's for existing summaries which don't have next steps contract.
There was a problem hiding this comment.
@khustup2 — understood, thanks for the context. The fallback is intentional so that existing summaries without a ## Next Steps section at all still resolve through ## Open Questions / TODO. The only uncovered edge is a new-format summary where the section header is present but the body is literally empty (wiki worker wrote the heading and nothing else), which would fall back to the older section; but if the worker always emits at least none under the heading, that case never arises in practice. Happy to leave it as-is.
🐇 ~ (ˆ•ω•ˆ)
✏️ Learnings added
Learnt from: khustup2
Repo: activeloopai/hivemind PR: 224
File: src/notifications/sources/resume-brief.ts:109-111
Timestamp: 2026-06-01T21:31:06.615Z
Learning: In `src/notifications/sources/resume-brief.ts`, the `||` fallback chain in `extractNextSteps` — `s.get("next steps") || s.get("open questions / todo") || s.get("open questions") || ""` — is intentional for backward compatibility. Existing session summaries that predate the `## Next Steps` contract do not have that section at all, so falling back to `## Open Questions / TODO` is the desired behavior. The wiki worker is expected to always emit at least `none` under `## Next Steps` when the section is present, so a truly empty (falsy) body for an existing section is not a realistic scenario.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
…the right summary
The resume brief is userVisibleOnly (the model never sees it), so when the
user says "load that from hivemind" the model has no referent. Add a static,
model-facing convention to the SessionStart context block telling the model
how to resolve a resume request from the VFS:
- target = most recent summary for the current project (index.md Project
match / ls -t summaries/<user>/);
- skip clean-wrapped sessions (empty/"none" Next Steps) to the next with
real open work — mirrors resume-brief's walk;
- reconcile with current git state before acting, confirm don't auto-run;
- don't bulk-read sessions/, drill in only for specifics.
Static instructions only (no mined content / no computed path) — same class
as the existing DEEPLAKE MEMORY block, so the injection guard is unaffected.
The model fetches the summary via its own cat on user request (safe channel).
…up actually fires The resume logic was correct but starved: in-progress placeholder summaries (skeletons with no ## section) plus duplicate rows per session filled the LIMIT 5 window, so the walk-back never reached real summaries and every session looked 'wrapped clean'. - over-fetch (SCAN_LIMIT=40), dedup by session path, drop placeholders, then walk LOOKBACK real summaries; return null (plain welcome) when only placeholders exist instead of falsely claiming 'wrapped clean' - extract pure isPlaceholderSummary + selectRealSummaries so the windowing is unit-tested without the network - add ## Next Steps to codex/cursor/hermes wiki prompts for parity with claude-code (resume-brief prefers it; falls back to Open Questions / TODO)
…ontext-transfer Explicit, in-session Save<->Resume pair on top of the goals primitive (no Stop-hook/gate/worker — see docs/CAPTURE_TASKS.md for the decision): - Save: 'save this for later' writes a goal whose body is a resumable context package (label + Start here / Files / Branch / Run / Why) - Resume: 'let's work on that task' pulls the full body back and continues - CLI: 'goal add --agent capture' (provenance, allowlisted) + 'goal get <id>' (full-body read — list only showed the first line, so resume had no way to transfer the package back) - capture/resume operations added to all 4 agent skill copies - tests for the flag, the agent allowlist guard, multi-line preservation, and full-body get
…at 90% resume-brief.ts was at ~44% — only the pure helpers were tested. - add pickResumeBrief tests behind a mocked DeeplakeApi/config/cwd boundary: the three outcomes, placeholder-skip + dedup windowing, gate/guards, truncation, and every relative-age bucket - cover the section-fallback + empty-bullet fall-through in extractNextSteps - resume-brief.ts -> 99/92/92/100, goal.ts -> 96/92/100/98 - enroll both files in the per-file coverage thresholds (90/90/90/90)
…lean CodeRabbit (PR #224): the || truthiness chain in extractNextSteps fell back to ## Open Questions / TODO when ## Next Steps was present but empty, which could surface a stale TODO as the resume CTA. Prefer Next Steps when the section exists (s.has) — empty/none then means wrapped-clean — and only fall back to the older section when Next Steps is absent (preserves backward-compat for pre-contract summaries, per khustup2). + regression test for the present-but-blank edge with a stale TODO underneath.
Resume "pick up where you left off" — now actually fires
Two related pieces so a new session reliably resumes prior work.
1. Resume-brief: stop the pickup from being starved (bug fix)
pickResumeBriefwas correct but starved. Thememorytable carries aSessionStart placeholder row per session (a skeleton with no
##sectionuntil the wiki worker fills it at SessionEnd), plus duplicate rows per session.
Those filled the
LIMIT 5window, so the walk-back never reached realsummaries and every session looked "wrapped up clean."
SCAN_LIMIT=40), dedup by session path, dropplaceholders, then walk
LOOKBACKreal summariesnull(plain welcome) instead offalsely claiming "wrapped clean"
isPlaceholderSummary+selectRealSummariesso it's unit-tested without the network
Verified against real data — now surfaces:
2.
## Next Stepsparity across agentsclaude-code already emitted a dedicated
## Next Steps; added it to thecodex / cursor / hermes wiki-worker prompts too. resume-brief prefers it and
falls back to
## Open Questions / TODOfor older summaries.Capture a task with context, resume it later (new feature)
Explicit, in-session Save↔Resume pair on the existing goals primitive — no
Stop-hook / gate / detached worker (the auto-detection design is deferred; see
docs/CAPTURE_TASKS.mdfor the decision record).context package: label +
Start here / Files / Branch / Run / Why, filledfrom the live conversation.
body back, flips it to
in_progress, and continues fromStart here:— nore-explaining.
goal add --agent capture(provenance, allowlisted) andgoal get <goal_id>(full-body read —goal listonly showed the firstline, so resume had no way to transfer the package back).
(claude-code / codex / hermes / openclaw).
Tests
resume-brief.test.ts: placeholder detection, dedup, placeholder-shadowing,lookback cap, all-placeholders→null.
cli-goal.test.ts:--agent capturevs default, agent allowlist guard,multi-line body preservation, full-body
goal get.