feat(memory): ambient nudges for record_decision and record_code_area - #144
Open
rajkumarsakthivel wants to merge 3 commits into
Open
feat(memory): ambient nudges for record_decision and record_code_area#144rajkumarsakthivel wants to merge 3 commits into
rajkumarsakthivel wants to merge 3 commits into
Conversation
Recording decisions and code areas currently depends on the agent obeying CLAUDE.md instructions. This makes memory opt-in and fragile. Agents that forget (or whose context compacts away the instructions) silently produce sessions with no durable memory. Two mechanisms make recording ambient: 1. Inline nudges on context_search results. After 4 searches with no record_decision, a directive appears listing the search count and prompting the agent to record if it made non-obvious choices. A separate nudge fires when 3+ files have been explored (via search or expand_chunk) without any record_code_area call, listing the specific unrecorded file paths. Both nudges include a "skip if" clause so the agent can ignore them when just browsing. After the first record_decision, the search threshold doubles to 8. 2. Stop hook summary. The Stop hook (already installed) now returns a compact session-end summary to stdout. The hook script is updated to capture Stop output (like SessionStart) so it gets injected into the agent's context. The summary lists search count, decisions recorded, and code areas recorded, with a directive to record if counts are low. New tests: 4 (decision nudge threshold, reset after record, code area nudge with unrecorded files, exclusion of recorded files).
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds “ambient” memory-recording nudges to improve cross-session memory reliability by prompting agents (via tool output) to call record_decision and record_code_area when activity suggests they should.
Changes:
- Appends decision/code-area nudges to
context_searchtool results based on session activity thresholds. - Adds a Stop-hook nudge generator that summarizes low-recording activity at session end.
- Updates the hook installer scripts to capture and print Stop-hook stdout (so it can be injected into model context), and adds integration tests for the new
context_searchnudges.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| tests/integration/test_mcp_server.py | Adds integration tests verifying decision/code-area nudges appear (or not) under expected thresholds. |
| src/context_engine/memory/hooks.py | Adds Stop-hook nudge builder and returns Stop-hook output intended for model-context injection. |
| src/context_engine/memory/hook_installer.py | Updates installed hook scripts to capture/emit Stop output similarly to SessionStart. |
| src/context_engine/integration/mcp_server.py | Introduces per-session nudge state and appends nudges to context_search results; resets some state on record_decision. |
Comments suppressed due to low confidence (1)
src/context_engine/integration/mcp_server.py:747
- The decision nudge will fire on every context_search after the threshold is reached because the condition uses ">=". That will repeatedly inject the same reminder into tool output and can quickly become noisy; trigger once when the threshold is crossed (or track a last-nudged counter).
if self._searches_since_last_decision >= threshold:
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Fix misleading comment claiming nudge resets on record_code_area
- Return 204 instead of {"ok":true} JSON when Stop has no nudge
- Add tests for _build_stop_nudge (fires, silent-few, silent-recorded)
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (3)
src/context_engine/memory/hooks.py:385
- handle_stop() now intentionally returns plain text (nudge) or 204 to avoid injecting JSON into the model context, but the exception path still returns a JSON body. If Stop enqueue fails, that JSON will be captured by the hook script and can pollute the model context the same way the comment below is trying to avoid. Consider returning a small text/plain message (or an empty body) on failures as well for consistency.
except Exception:
log.exception("Stop enqueue failed")
return web.json_response({"ok": False}, status=202)
src/context_engine/memory/hooks.py:404
- _build_stop_nudge() docstring says it only queries tool_events and decisions, but the function also counts code_areas and uses that to decide whether to emit a nudge. Updating the docstring will keep the behavior discoverable and prevent future confusion when adjusting thresholds.
Queries memory.db for tool_events (context_search calls) and decisions
recorded during this session. Returns a short directive if activity
was significant but recording was low. Returns "" if nothing to nudge.
src/context_engine/integration/mcp_server.py:763
- _build_nudge() calls get_session_snapshot() twice and indexes snap["decisions"]. In tests/mocks or future snapshot implementations, a missing "decisions" key would raise a KeyError. Reusing the same snapshot and using .get(...) makes this more robust and avoids redundant snapshot calls.
# ── decision nudge ────────────────────────────────────────────
threshold = (
self._DECISION_NUDGE_REPEAT
if self._has_recorded_decision
else self._DECISION_NUDGE_FIRST
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
CCE's cross-session memory depends on the agent calling
record_decisionandrecord_code_area, but that only happens when the agent obeys CLAUDE.md instructions. If context compacts or the agent just forgets, the session produces no durable memory. This PR makes recording ambient by nudging the agent from within tool results.Inline nudges on
context_search:Decision nudge fires after 4 context searches with 0 decisions recorded this session. Message includes the search count and a directive to call
record_decisionif a non-obvious choice was made. Includes "skip if this session is just exploration/reading" to prevent garbage recordings. After the firstrecord_decision, the threshold doubles to 8 (longer leash once the agent has shown it knows how).Code area nudge fires when 3+ files have been explored (via
context_searchorexpand_chunk) without anyrecord_code_areacall. Lists the specific unrecorded file paths (max 5) so the agent has concrete material to act on rather than a generic reminder. Files that were alreadyrecord_code_area'd are excluded from the count.Both nudges can fire in the same response. They appear before the output compression directive, as part of the tool result text.
Stop hook summary:
The existing Stop hook (fires on session end) now returns a compact summary: search count, decisions recorded, code areas recorded, with a directive to record if counts are low. The hook script is updated to capture Stop stdout (previously only SessionStart output was captured). Users get the updated script on next
cce init.Example nudge (after 4th search, 0 decisions):
Example code area nudge: