Skip to content

feat(memory): inject ADR-012 cycle-reflection trailer into all heartbeat templates#295

Closed
samxu01 wants to merge 2 commits intomainfrom
feat/cycles-heartbeat-template
Closed

feat(memory): inject ADR-012 cycle-reflection trailer into all heartbeat templates#295
samxu01 wants to merge 2 commits intomainfrom
feat/cycles-heartbeat-template

Conversation

@samxu01
Copy link
Copy Markdown
Contributor

@samxu01 samxu01 commented May 4, 2026

Summary

Phase 2 (#293) closed the read loop at the protocol level but the §10.3 inline cue on `payload.content` was empirically insufficient — 0 new `cycles[]` writes across 25 agents in the post-deploy window. Agents follow `HEARTBEAT.md`'s structured steps verbatim and deprioritize the inline narrative directive.

This PR moves the cycle-write directive into `HEARTBEAT.md` itself, where the model treats it as authoritative.

Approach: single chokepoint

Instead of editing 25 individual `heartbeatTemplate` strings in `presets.ts`:

  • New `withCyclesDirective(template)` helper in `presets.ts` — appends a uniform "## Memory cycle reflection" trailer. Idempotent.
  • Applied at the four provisioner call-sites (`provision.ts` + `reprovision.ts`) that read `matchedPreset.heartbeatTemplate` and write to PVC + `AgentProfile` cache.

New presets automatically inherit the directive. The 25 raw template strings stay untouched, so the `customizations.heartbeat` flag's "user edited the template" semantics are preserved.

Test plan

  • tsc:check clean
  • Merge → Deploy Dev → reprovision-all → verify HEARTBEAT.md on a PVC has the trailer
  • Wait ~30 min for heartbeat cycle → check AgentMemory for new `cycles[].entries` across agents

🤖 Generated with Claude Code

samxu01 added 2 commits May 3, 2026 22:12
…eat templates

Empirical finding from the post-deploy observation window: the §10.3
inline cue prepended to scheduler heartbeat payload.content was NOT
sufficient to produce cycle writes. Five heartbeats acked across the
cluster after Phase 2 deploy with 0 new agent-authored cycles[]
entries — agents follow HEARTBEAT.md's structured steps verbatim and
deprioritize the inline narrative directive.

Fix: add the cycle-write directive to HEARTBEAT.md itself — the file
the model treats as authoritative. Implemented as a single chokepoint
helper (`withCyclesDirective`) applied at provision/reprovision time:

- New `withCyclesDirective(template)` in presets.ts: appends a uniform
  "## Memory cycle reflection" trailer to any heartbeat template.
  Idempotent (no-op if the trailer is already present); preserves the
  customizations.heartbeat flag's "user edited" semantics by leaving
  the 25 individual template strings untouched.
- Wrapped all four call-sites in provision.ts and reprovision.ts that
  read matchedPreset.heartbeatTemplate (provisioner + AgentProfile
  cache).

Trailer instructs: append a ≤500-char takeaway via
commonly_save_my_memory({sections:{cycles:{append:{content}}}}) just
before HEARTBEAT_OK; skip if nothing memorable; specific over generic;
past entries surface in cyclesDigest on every future event so writing
isn't wasted.

Single point of injection means new presets automatically get the
directive without per-preset edits. reprovision-all on dev pushes the
new HEARTBEAT.md to all 25 agent PVCs in one pass.
…lifecycle

Folds Phase 3 docs into the same PR as the §10.3 trailer-inject helper.
- Event Queue: document pending → delivered → acked lifecycle, mutate-on-claim
  in list(), status-gated ack with monotone $max bump on lastSeenRevision.
- New 'Memory contract (ADR-012)' section: sections envelope (with
  system_exchanges + cycles writer/reader/cap matrix), cycles append shape,
  four-field event payload digest, revision contract, invariant 8a carve-out.
- Document the HEARTBEAT.md trailer auto-inject as the single chokepoint
  for the cycle-write directive.
samxu01 added a commit that referenced this pull request May 4, 2026
…eat templates (#295)

Empirical finding from the post-Phase-2 observation window: the §10.3
inline cue prepended to scheduler heartbeat payload.content was NOT
sufficient to produce cycle writes. Five heartbeats acked across the
cluster after Phase 2 deploy with 0 new agent-authored cycles[]
entries. Agents follow HEARTBEAT.md's structured steps verbatim and
deprioritize the inline narrative directive — confirms the hierarchy:
authoritative workspace file > inline payload.content > structured
metadata.

Fix: add the cycle-write directive to HEARTBEAT.md itself, where the
model treats it as authoritative. Implemented as a single chokepoint
helper applied at provision/reprovision time rather than editing 25
individual heartbeatTemplate strings.

- New `withCyclesDirective(template)` in presets.ts: appends a uniform
  '## Memory cycle reflection' trailer to any heartbeat template.
  Idempotent (no-op if the trailer is already present); preserves the
  customizations.heartbeat flag's 'user edited' semantics by leaving
  the 25 individual template strings untouched.
- Wrapped all four call-sites in provision.ts + reprovision.ts that
  read matchedPreset.heartbeatTemplate (provisioner + AgentProfile cache).

Trailer instructs: append ≤500-char takeaway via
commonly_save_my_memory({sections:{cycles:{append:{content}}}}) just
before HEARTBEAT_OK; skip if nothing memorable; specific over generic;
past entries surface in cyclesDigest on every future event so writing
isn't wasted.

Single point of injection means new presets automatically get the
directive without per-preset edits. reprovision-all on dev pushes the
new HEARTBEAT.md to all 25 agent PVCs in one pass.

Folds in ADR-012 Phase 3 docs:
- AGENT_RUNTIME.md: new 'Memory contract (ADR-012)' section + Event
  Queue lifecycle subsection (mutate-on-claim, monotone \$max bump,
  dup-ack semantics).
@samxu01
Copy link
Copy Markdown
Contributor Author

samxu01 commented May 4, 2026

Squash-merged to main as 4097a8d.

@samxu01 samxu01 closed this May 4, 2026
@samxu01 samxu01 deleted the feat/cycles-heartbeat-template branch May 4, 2026 05:27
samxu01 added a commit that referenced this pull request May 4, 2026
Phase 2.J's withCyclesDirective trailer (PR #295) instructed agents to
call commonly_save_my_memory({sections:{cycles:{append:...}}}), but no
openclaw extension tool with that name exists today. Agents waste 3+
turn-budget tool calls per heartbeat hunting for it before falling
back to the real commonly_write_agent_memory, which exhausts their
budget before they can post a chat reply.

Verified on Nova: silent on Sam's "hey Nova" (06:01 UTC) and "hey"
(06:21 UTC) DMs immediately after the trailer rolled out via
reprovision-all. Pre-rollout, Nova was responding cleanly to four
prior pings within minutes.

Session log /state/agents/nova/sessions/*.jsonl confirms 3× attempted
'commonly_save_my_memory' tool calls (missing tool name) before 1×
successful 'commonly_write_agent_memory' fallback.

This commit makes withCyclesDirective a no-op so HEARTBEAT.md reverts
to its pre-Phase-2.J shape on the next reprovision-all. The helper +
its four call-sites stay in place so re-enabling is a one-line flip
once the openclaw extension exposes a real cycles-write tool.

Forward fix path (separate branch): add commonly_log_cycle(content,
podId?) to Team-Commonly/openclaw fork, build + push gateway image,
update trailer to call the new tool name, flip this back to the real
implementation, reprovision-all + observe.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant