openclaw - ✅(Solved) Fix [Bug]: Heartbeat ignores lightContext: true, loads full agent context + unbounded session history [4 pull requests, 3 comments, 4 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#43767Fetched 2026-04-08 00:18:18
View on GitHub
Comments
3
Participants
4
Timeline
20
Reactions
0
Author
Timeline (top)
referenced ×8cross-referenced ×6commented ×3labeled ×2

Heartbeat ignores lightContext: true, loads full agent context + unbounded session history

Error Message

06:04:09 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK 06:05:21 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK 06:06:05 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK 06:06:23 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK 06:06:38 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK 06:11:11 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK 06:11:31 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK 06:11:44 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK 06:16:02 - ContextWindowExceededError: prompt is too long: 200656 tokens > 200000 maximum

Root Cause

Heartbeat ignores lightContext: true, loads full agent context + unbounded session history

Fix Action

Workaround

Set heartbeat.every to "off" in openclaw.json to disable heartbeats entirely.

PR fix notes

PR #43908: fix(config): expose heartbeat lightContext and other options in config help

Description (problem / solution / changelog)

Summary

  • Problem: In src/config/schema.help.ts and src/config/schema.labels.ts, multiple heartbeat configuration options (such as lightContext, includeReasoning, every, activeHours, etc.) were missing. While fully implemented in the Zod schema and runtime runner, they were invisible to users via /config help or autocomplete.
  • Why it matters: Users could not discover these options, leading to confusion. Specifically for lightContext, users mistakenly placed lightContext: true directly in HEARTBEAT.md instead of openclaw.json, resulting in unbounded context growth and excessive API credit consumption. This is a high-impact regression (Fixes #43767).
  • What changed:
    • src/config/schema.help.ts: Added missing agents.defaults.heartbeat.*, agents.list.*.heartbeat.*, and agents.list[].heartbeat.* options.
    • Comprehensive Audit: Aligned all 15 heartbeat fields across all three variants (defaults, list.*, list[]) to ensure 100% parity.
    • Operational Guidance: Added critical edge-case documentation based on bot reviews:
      • Documented every: "0m" as the correct path to disable heartbeats, alongside a warning about the default agent's fallback behavior.
      • Added warnings that to and accountId are only read when target is set.
      • Added a warning that heartbeat.session is ignored when session.scope is global.
      • Added a security note to includeReasoning.
    • Removed the static help text for heartbeat.target to allow dynamic channel list generation via applyHeartbeatTargetHints.
    • src/config/schema.labels.ts: Added all corresponding UI labels to satisfy the keeps labels in parity for all help keys quality test.
  • What did NOT change: The runtime logic in heartbeat-runner.ts and the schema definitions in zod-schema.agent-runtime.ts remain completely untouched.

Change Type (select all)

  • Bug fix

Scope (select all touched areas)

  • Config / Schema

Linked Issue/PR

Fixes #43767

Test Plan

  • Verified all schema.help.quality.test.ts tests pass (including label parity and operational guidance checks).
  • Verified schema.test.ts passes (specifically fixing the adds heartbeat target hints with dynamic channels test by removing static help text).
  • Verified vitest run src/config/ passes completely.
  • Verified vitest run src/infra/heartbeat-runner passes to ensure no runtime regressions.
  • Verified vitest run src/cron/ passes to ensure no cron scheduling regressions.

AI-Assisted Contribution

  • AI Usage: This PR was developed with AI assistance.
  • Human Review: I have personally reviewed, designed, and fully understand all the code changes.
  • Testing: Fully tested locally with my OpenClaw instance.
  • Prompt Context: The AI was instructed to perform a deep root-cause analysis of the heartbeat visibility issue, implement the initial fix, and then perform a comprehensive audit across all three schema variants (defaults, list.*, list[]) to address all bot review feedback (Codex & Greptile), ensuring 100% documentation parity and accurate edge-case warnings without touching runtime logic.

Changed files

  • src/config/schema.help.ts (modified, +83/-0)
  • src/config/schema.labels.ts (modified, +41/-0)

PR #46634: Heartbeat: add isolatedSession option for fresh session per heartbeat run

Description (problem / solution / changelog)

Summary

  • Problem: Heartbeat runs accumulate turns in the main session. Over time (hours/days), the full conversation history is re-sent to the LLM on every heartbeat tick, burning ~100K tokens per run.
  • Why it matters: Users running frequent heartbeats (every 5–60 min) face massive token costs and eventual context window exhaustion, with no built-in escape hatch.
  • What changed: Added heartbeat.isolatedSession boolean config option. When true, each heartbeat run gets a fresh session (no prior conversation history) using the existing resolveCronSession pattern with forceNew. Reduces per-heartbeat token cost from ~100K to ~2-5K tokens.
  • What did NOT change (scope boundary): Delivery routing still uses the main session's lastChannel/lastTo. The main session transcript is untouched. Default behavior (isolatedSession: false) is unchanged.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #20011
  • Related #20649
  • Related #7957
  • Related #21597
  • Related #43767

User-visible / Behavior Changes

  • New config key: heartbeat.isolatedSession (boolean, default false).
  • When enabled, heartbeat runs use a fresh <sessionKey>:heartbeat session each time (no prior conversation history).
  • Combine with lightContext: true for maximum token savings.
  • Docs updated: docs/gateway/heartbeat.md, docs/gateway/configuration-reference.md.

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: Bun/Node 22
  • Model/provider: Any
  • Relevant config (redacted):
agents:
  defaults:
    heartbeat:
      every: "5m"
      target: "last"
      isolatedSession: true
      lightContext: true

Steps

  1. Set heartbeat.isolatedSession: true in config
  2. Run heartbeat (or wait for scheduled tick)
  3. Observe session key used in heartbeat run

Expected

  • Heartbeat uses <sessionKey>:heartbeat (fresh, no history)
  • Token usage ~2-5K per run

Actual

  • Confirmed via test: isolated session key is <sessionKey>:heartbeat
  • Non-isolated run uses original <sessionKey> (unchanged default)

Evidence

  • Failing test/log before + passing after
  • Two new tests: "uses isolated session key when isolatedSession is enabled" and "uses main session key when isolatedSession is not set"

Human Verification (required)

  • Verified scenarios: Both tests pass, existing heartbeat tests still pass
  • Edge cases checked: Default behavior unchanged when isolatedSession not set; delivery routing still reads main session for lastChannel/lastTo
  • What you did not verify: Live multi-day heartbeat run with real provider

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? New optional isolatedSession key (default false)
  • Migration needed? No

Failure Recovery (if this breaks)

  • How to disable/revert: Set isolatedSession: false or omit the key
  • Known bad symptoms: heartbeat using wrong session key, delivery routing failing

Risks and Mitigations

  • Risk: Isolated session discards all prior heartbeat context; heartbeat prompt must be self-contained.
    • Mitigation: This is the intended behavior — matches cron sessionTarget: "isolated" semantics. Documented in config reference and heartbeat docs.

Changed files

  • docs/.generated/config-baseline.json (modified, +22/-2)
  • docs/.generated/config-baseline.jsonl (modified, +5/-3)
  • docs/gateway/configuration-reference.md (modified, +2/-0)
  • docs/gateway/heartbeat.md (modified, +12/-4)
  • src/config/legacy.migrations.part-3.ts (modified, +1/-0)
  • src/config/types.agent-defaults.ts (modified, +7/-0)
  • src/config/zod-schema.agent-runtime.ts (modified, +1/-0)
  • src/infra/heartbeat-runner.model-override.test.ts (modified, +68/-0)
  • src/infra/heartbeat-runner.ts (modified, +30/-4)

PR #57136: fix(heartbeat): clear sessionFile on new isolated session to prevent context accumulation

Description (problem / solution / changelog)

Problem

When isolatedSession: true is configured for heartbeats, resolveCronSession is called with forceNew: true and correctly generates a new sessionId (UUID) on every heartbeat tick.

However, the new session entry was spread from the prior entry (...entry), which preserved the old sessionFile path from the previous run.

resolveSessionFilePath has this logic:

function resolveSessionFilePath(sessionId, entry, opts) {
  const candidate = entry?.sessionFile?.trim();
  if (candidate) return resolvePathWithinSessionsDir(...);  // prefers entry.sessionFile!
  return resolveSessionTranscriptPathInDir(sessionId, sessionsDir);  // only fallback
}

So every heartbeat continued appending to the same old transcript file, even though a new sessionId was assigned. This caused unbounded context growth that eventually triggered model fallbacks and failed heartbeat runs — despite isolatedSession: true being set.

Observed: context grew from ~18K tokens to 190K+ tokens over 24 hours, causing repeated Gemini API errors and fallback to backup models.

Fix

Clear sessionFile when isNewSession is true, so resolveSessionFilePath falls through to derive a fresh path from the new sessionId.

...(isNewSession && { sessionFile: undefined }),

This is analogous to the existing cleanup of lastChannel, lastTo, deliveryContext, etc. that was already done on new session rollover.

Testing

  • Verified locally with isolatedSession: true + 1h heartbeat interval: each heartbeat now creates a new <uuid>.jsonl transcript file, starting at ~18K tokens instead of inheriting prior session history.
  • Existing session.test.ts passes.

Related

Fixes #43767

Changed files

  • src/cron/isolated-agent/session.ts (modified, +1/-0)

PR #60776: fix: pass bootstrapContextMode/RunKind to runEmbeddedAttempt

Description (problem / solution / changelog)

Summary

  • Problem: lightContext: true on cron jobs had no effect — all 5 workspace bootstrap files were still injected into the LLM system prompt, inflating the token usage from.
  • Why it matters: lightContext exists specifically to reduce cost and latency for simple automated cron jobs that don't need workspace context. It was completely non-functional.
  • What changed: Added 2 lines in pi-embedded-runner/run.ts to pass bootstrapContextMode and bootstrapContextRunKind from params through to the runEmbeddedAttempt() call. These fields were already defined on the params type and consumed by the attempt function — they just were never wired at the call site.
  • What did NOT change (scope boundary): No changes to bootstrap resolution logic, cron gateway, system prompt building, or session/config handling. The filter logic was already correct — only the plumbing was missing.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Related: lightContext support for cron jobs
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: runEmbeddedPiAgent() in pi-embedded-runner/run.ts manually enumerates every field when calling runEmbeddedAttempt() (~80 fields). When bootstrapContextMode and bootstrapContextRunKind were added to RunEmbeddedPiAgentParams, they were wired into the compaction paths but not the primary runEmbeddedAttempt() call. The attempt function received undefined for both, causing applyContextModeFilter() to default to "full".
  • Missing detection / guardrail: No test verifies that runEmbeddedPiAgent propagates bootstrap context fields to the attempt. The explicit field-by-field call pattern (vs. spreading) makes omissions silent — TypeScript won't flag a missing optional field.
  • Contributing context: The field-by-field destructuring pattern across ~80 fields in the call site makes it easy to miss new additions during review.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: pi-embedded-runner/run.test.ts or equivalent
  • Scenario the test should lock in: When runEmbeddedPiAgent is called with bootstrapContextMode: "lightweight" and bootstrapContextRunKind: "cron", the inner runEmbeddedAttempt call must receive those same values (not undefined).
  • Why this is the smallest reliable guardrail: A seam test that spies on the attempt call params catches the plumbing bug without needing a full LLM round-trip.
  • If no new test is added, why not: This PR is a minimal hotfix. A follow-up test PR is recommended.

User-visible / Behavior Changes

Cron jobs with lightContext: true in their agentTurn payload now correctly skip workspace bootstrap file injection. Observed impact on a real cron job:

  • injectedWorkspaceFiles: 5 → 0
  • projectContextChars: 12,304 → 0
  • totalTokens: ~16–19k → ~4.5k

Diagram (if applicable)

Before:
  cron gateway (bootstrapContextMode: "lightweight")
    -> runEmbeddedPiAgent(params)
      -> runEmbeddedAttempt({...80 fields...})  // bootstrapContextMode: undefined
        -> resolveBootstrapContextForRun(contextMode: undefined)  // defaults to "full"
          -> returns 5 workspace files

After:
  cron gateway (bootstrapContextMode: "lightweight")
    -> runEmbeddedPiAgent(params)
      -> runEmbeddedAttempt({...80 fields + 2 new...})  // bootstrapContextMode: "lightweight"
        -> resolveBootstrapContextForRun(contextMode: "lightweight")
          -> returns []

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Repro + Verification

Environment

  • OS: Linux 6.17.0-1009-oracle (Ubuntu)
  • Runtime/container: Node.js, OpenClaw v2026.3.28
  • Model/provider: google/gemini-2.5-flash
  • Integration/channel: Cron (isolated session, Telegram delivery)
  • Relevant config: jobs.json entry with payload.lightContext: true

Steps

  1. Configure a cron job with lightContext: true in the agentTurn payload
  2. Wait for or trigger the cron run
  3. Inspect the session JSONL — check first system message for "# Project Context" section and token count

Expected

  • No "# Project Context" section in system prompt
  • injectedWorkspaceFiles: [], projectContextChars: 0
  • Total tokens ~4–5k (prompt-only, no bootstrap overhead)

Actual

  • "# Project Context" with 5 files injected
  • projectContextChars: 12304, total tokens 16–19k

Evidence

Attach at least one:

  • Trace/log snippets

Before fix (session from earlier cron runs):

projectContextChars = 12304
injectedWorkspaceFiles = 5
totalTokens = 16k–19k+

After fix (session 4dd55883-bc95-4ce8-a205-33c145821c97.jsonl):

projectContextChars = 0
injectedWorkspaceFiles = []
systemPrompt.chars = 11006
totalTokens = 4548

Fix was verified by patching the minified production bundle (pi-embedded-BYdcxQ5A.js:39742) at runtime, restarting the gateway, and observing the next cron execution

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: Live cron run with lightContext: true on production gateway after hot-patching the bundled JS. Confirmed zero injected workspace files and ~75% token reduction.
  • Edge cases checked: Confirmed the bootstrap filter logic itself (applyContextModeFilter) was already correct for all three run kinds (default/heartbeat/cron) — only the passthrough was missing.
  • What I did NOT verify: Other callers of runEmbeddedPiAgent (auto-reply, memory flush, followup runner) — those have separate call sites with their own field enumeration and may have similar omissions for different fields.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes — adds two previously-omitted optional fields to an internal function call. No config, API, or schema changes.

Changed files

  • src/agents/pi-embedded-runner/run.overflow-compaction.test.ts (modified, +18/-0)
  • src/agents/pi-embedded-runner/run.ts (modified, +2/-0)

Code Example

{
  "deliveryContext": {
    "channel": "webchat",
    "to": "heartbeat"
  },
  "origin": {
    "provider": "heartbeat"
  },
  "contextTokens": 200000,
  "inputTokens": 118222,
  "outputTokens": 1416,
  "compactionCount": 1
}

---

06:04:09 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK
06:05:21 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK
06:06:05 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK
06:06:23 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK
06:06:38 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK
06:11:11 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK
06:11:31 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK
06:11:44 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK
06:16:02 - ContextWindowExceededError: prompt is too long: 200656 tokens > 200000 maximum

---

04:14:40 [agent/embedded] embedded run agent end: isError=true error=API rate limit reached
04:15:05 [agent/embedded] embedded run agent end: isError=true error=API rate limit reached
04:15:33 [agent/embedded] embedded run agent end: isError=true error=API rate limit reached
04:16:03 [agent/embedded] embedded run agent end: isError=true error=API rate limit reached
  -- 5 min pause, then repeats --
04:19:35 [agent/embedded] embedded run agent end: isError=true error=API rate limit reached
04:20:01 [agent/embedded] embedded run agent end: isError=true error=API rate limit reached
04:20:31 [agent/embedded] embedded run agent end: isError=true error=API rate limit reached
04:21:06 [agent/embedded] embedded run agent end: isError=true error=API rate limit reached
  -- pattern continued for hours --

---
RAW_BUFFERClick to expand / collapse

Bug type

Regression (worked before, now fails)

Summary

Heartbeat ignores lightContext: true, loads full agent context + unbounded session history

Steps to reproduce

Bug Description

The heartbeat feature loads the full agent context and accumulated conversation history on every heartbeat tick, instead of honoring the lightContext: true directive in HEARTBEAT.md. This causes unbounded token growth that eventually maxes out the context window and burns through API credits.

Environment

  • OpenClaw version: 2026.3.8
  • Deployment: Docker/Podman (containerized)
  • LLM provider: Anthropic (claude-sonnet-4-6) via LiteLLM proxy
  • Heartbeat interval: 5m

Expected behavior

Expected Behavior

  1. HEARTBEAT.md specifies lightContext: true — heartbeat turns should inject only HEARTBEAT.md, not the full workspace context
  2. Each heartbeat should run in an isolated session (fresh context), not append to the main conversation history
  3. There should be a token budget/cap for heartbeat runs

Actual behavior

Actual Behavior

  1. lightContext: true is completely ignored. The systemPromptReport in sessions.json shows ALL workspace files injected on every heartbeat: AGENTS.md, SOUL.md, TOOLS.md, IDENTITY.md, USER.md, HEARTBEAT.md, MEMORY.md (~29K chars system prompt)
  2. Heartbeat runs append to a single persistent session (agent:files:main). The session grows monotonically until it hits the model's context limit (200K tokens)
  3. No token budget exists — the heartbeat sent 200,656 tokens in its final request before failing with ContextWindowExceededError

OpenClaw version

OpenClaw version: 2026.3.8

Operating system

Windows 11

Install method

npm

Model

Anthropic claude code

Provider / routing chain

→ LiteLLM proxy (http://litellm:4000, running in openclaw-litellm container) → Anthropic API (api.anthropic.com/v1/messages)

Config file / key location

No response

Additional provider/model setup details

Evidence from sessions.json

{
  "deliveryContext": {
    "channel": "webchat",
    "to": "heartbeat"
  },
  "origin": {
    "provider": "heartbeat"
  },
  "contextTokens": 200000,
  "inputTokens": 118222,
  "outputTokens": 1416,
  "compactionCount": 1
}

LiteLLM Proxy Logs (showing the runaway calls)

06:04:09 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK
06:05:21 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK
06:06:05 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK
06:06:23 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK
06:06:38 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK
06:11:11 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK
06:11:31 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK
06:11:44 - litellm.acompletion(model=anthropic/claude-sonnet-4-6) 200 OK
06:16:02 - ContextWindowExceededError: prompt is too long: 200656 tokens > 200000 maximum

Agent Logs (showing retry storm pattern)

Every 5 minutes, the heartbeat fires and retries 3-4 times on rate limit before giving up:

04:14:40 [agent/embedded] embedded run agent end: isError=true error=API rate limit reached
04:15:05 [agent/embedded] embedded run agent end: isError=true error=API rate limit reached
04:15:33 [agent/embedded] embedded run agent end: isError=true error=API rate limit reached
04:16:03 [agent/embedded] embedded run agent end: isError=true error=API rate limit reached
  -- 5 min pause, then repeats --
04:19:35 [agent/embedded] embedded run agent end: isError=true error=API rate limit reached
04:20:01 [agent/embedded] embedded run agent end: isError=true error=API rate limit reached
04:20:31 [agent/embedded] embedded run agent end: isError=true error=API rate limit reached
04:21:06 [agent/embedded] embedded run agent end: isError=true error=API rate limit reached
  -- pattern continued for hours --

Suggested Fixes

  1. Honor lightContext: true — only inject the file that declares it, not the full workspace
  2. Isolate heartbeat sessions — each heartbeat should start fresh, not accumulate history
  3. Add maxContextTokens config for heartbeat runs (e.g., 10K cap)
  4. Fail fast on rate limit — don't retry heartbeat runs on 429, just skip to next interval
  5. Add token budget tracking — if heartbeat exceeds N tokens, auto-reset the session

Related

  • #11972 (Model fallback does not trigger on 429 rate limit errors) — the retry-on-429 behavior compounds this bug

Workaround

Set heartbeat.every to "off" in openclaw.json to disable heartbeats entirely.

Logs, screenshots, and evidence

Impact and severity

Impact

  • Credit burn: With a 5m heartbeat, the agent was making 288 full-context API calls per day. When rate-limited, it retried 3-4 times per cycle, multiplying the cost
  • Retry storm on rate limit: Each rate-limited heartbeat retried with the full 200K token payload multiple times before giving up
  • No circuit breaker: Nothing stops the heartbeat from sending increasingly large requests as history accumulates

Additional information

No response

extent analysis

Problem Summary

Heartbeat runs are loading the full workspace context and re‑using a persistent session, ignoring lightContext: true. This causes unbounded token growth, context‑window errors, and massive credit burn.

Root Cause Analysis

  1. Context builder always calls loadAllWorkspaceFiles() instead of checking the lightContext flag in HEARTBEAT.md.
  2. Session manager re‑uses the agent:files:main session for every heartbeat tick.
  3. Heartbeat runner has no token‑budget guard and retries on every 429, compounding the load.

Fix Plan

1. Honor lightContext in the context loader

// src/heartbeat/contextBuilder.ts
import { readFileSync } from 'fs';
import { Workspace } from '../workspace';

export async function buildHeartbeatContext(): Promise<string> {
  const hbPath = Workspace.path('HEARTBEAT.md');
  const hbContent = readFileSync(hbPath, 'utf‑8');

  // Parse front‑matter (YAML) for lightContext flag
  const lightContext = /lightContext:\s*true/.test(hbContent);

  if (lightContext) {
    // Return only the HEARTBEAT file (strip front‑matter)
    return hbContent.replace(/^---[\s\S]*?---\n/, '');
  }

  // Fallback – load full workspace (previous behaviour)
  const files = ['AGENTS.md','SOUL.md','TOOLS.md','IDENTITY.md','USER.md','MEMORY.md'];
  const parts = files.map(f => readFileSync(Workspace.path(f), 'utf‑8'));
  return [hbContent, ...parts].join('\n');
}

2. Isolate heartbeat sessions

// src/heartbeat/runner.ts
import { createSession, appendMessage, getSession } from '../sessions';

export async function runHeartbeat() {
  // Always start a fresh, short‑lived session
  const session

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING