Skip to content

feat(hooks): add reliability stack hooks for memory gating and crash recovery#2329

Open
inwardwellbeing wants to merge 6 commits intocode-yeongyu:devfrom
inwardwellbeing:ck/reliability-stack
Open

feat(hooks): add reliability stack hooks for memory gating and crash recovery#2329
inwardwellbeing wants to merge 6 commits intocode-yeongyu:devfrom
inwardwellbeing:ck/reliability-stack

Conversation

@inwardwellbeing
Copy link

@inwardwellbeing inwardwellbeing commented Mar 5, 2026

Summary

  • add resource-gate tool-guard hook to block agent/tool execution under critical memory pressure and warn under high pressure using macOS vm_stat + swap telemetry
  • add session reliability hooks: auto-checkpoint, execution-gate, learning-bus-injector, and correction-detector
  • register new hooks in schema + hook registries/event dispatch, bump version to 3.10.0, and ignore platform sourcemaps in packages/*/bin/*.map

Why

  • reduce interactive OOM crash frequency and recovery cost by preventing overload and injecting resumable checkpointing signals

Verification

  • existing local verification from implementation pass: build + test suite including new hook tests

Summary by cubic

Adds a reliability stack to prevent OOMs and improve session recovery. Adds memory gating for background tasks and session hooks for auto-restore/checkpointing and startup briefings.

  • New Features

    • Resource Gate: blocks task spawns when RAM <1GB; warns at <2GB or >88% used; parses macOS vm_stat + swap with os.freemem() fallback; warning appended to task description.
    • Auto Checkpoint: injects session_restore on first idle; then session_checkpoint after 20 idles or 15 minutes (5‑min cooldown); skips sub‑agents.
    • Execution Gate: on first idle, injects a briefing from flight plan, last‑24h autonomous decisions, and high‑severity session_start corrections; 4k‑char cap; skips sub‑agents.
    • Learning Bus Injector: injects top recent system events (≤7 days, confidence ≥0.5), ranked by type/recency; max 10 events/2k chars; skips sub‑agents.
    • Correction Detector: detects user correction phrases and writes JSONL events with severity/weight to Mind Palace/AI/_state/system-events.jsonl for trust scoring.
    • Wiring: hooks registered and dispatched (resource-gate runs first in tool.execute.before); version bumped to 3.10.0; ignore packages//bin/.map; tests added for resource-gate and auto-checkpoint.
  • Migration

    • Enable in config: resource-gate, auto-checkpoint, execution-gate, learning-bus-injector, correction-detector.
    • For macOS memory parsing, ensure vm_stat and sysctl are available; fallback still works but with less precision.
    • Ensure Mind Palace vault exists at /Library/Mobile Documents/iCloudmd~obsidian/Documents/Mind Palace with:
      • AI/_state/system-events.jsonl (corrections)
      • AI/_state/decision-journal.jsonl, AI/_state/flight-plan.json, AI/_state/correction-index.json (for briefings)

Written for commit 3905a7b. Summary will update on new commits.

inwardwellbeing and others added 6 commits March 5, 2026 13:12
Add correction detection for identifying user corrections in conversations. Includes detector logic, event emitter, and constants.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <[email protected]>
Blocks agent spawning when available memory <1GB, warns at <2GB. Uses vm_stat + sysctl vm.swapusage parsing with os.freemem() fallback. Dispatched first in tool-execute-before chain to catch OOM before any tool runs.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <[email protected]>
…kpoint hooks

Three session hooks for the reliability stack: execution-gate controls agent dispatch flow, learning-bus-injector feeds corrections into session context, auto-checkpoint injects session_restore on first idle and session_checkpoint after sustained activity (20 idles or 15 min, 5-min cooldown).

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <[email protected]>
Add learning-bus-injector, execution-gate, resource-gate, and auto-checkpoint to HookNameSchema. Export factory functions and types from hooks barrel.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <[email protected]>
Version bump for reliability stack: resource-gate, auto-checkpoint, execution-gate, learning-bus-injector, and correction-detector hooks.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <[email protected]>
@github-actions
Copy link
Contributor

github-actions bot commented Mar 5, 2026

Thank you for your contribution! Before we can merge this PR, we need you to sign our Contributor License Agreement (CLA).

To sign the CLA, please comment on this PR with:

I have read the CLA Document and I hereby sign the CLA

This is a one-time requirement. Once signed, all your future contributions will be automatically accepted.


I have read the CLA Document and I hereby sign the CLA


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

10 issues found across 30 files

Confidence score: 2/5

  • High-confidence compatibility bugs in src/hooks/index.ts are likely merge-blocking: auto-checkpoint, execution-gate, and learning-bus-injector pass path: { id: sessionID } instead of path: { sessionID }, which can break Opencode SDK calls at runtime.
  • src/hooks/execution-gate/constants.ts hardcodes a personal iCloud Obsidian vault path, creating clear cross-platform/usability regressions for other environments unless replaced with config/env-driven paths.
  • There are additional behavior risks in timing/filtering and text processing (src/hooks/auto-checkpoint/hook.ts, src/hooks/learning-bus-injector/event-reader.ts, src/hooks/correction-detector/detector.ts), so this is not just a housekeeping pass and needs targeted fixes before merging.
  • Pay close attention to src/hooks/index.ts, src/hooks/execution-gate/constants.ts, src/hooks/auto-checkpoint/hook.ts, src/hooks/learning-bus-injector/event-reader.ts - SDK path contract mismatches, hardcoded environment paths, and logic edge cases could cause immediate runtime or correctness issues.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/hooks/execution-gate/constants.ts">

<violation number="1" location="src/hooks/execution-gate/constants.ts:6">
P1: Custom agent: **Opencode Compatibility**

Hardcoding a personal iCloud Obsidian vault path breaks cross-platform compatibility and usability for other Opencode users. Use an environment variable or a standard Opencode configuration directory instead.</violation>
</file>

<file name="src/hooks/index.ts">

<violation number="1" location="src/hooks/index.ts:54">
P0: Custom agent: **Opencode Compatibility**

The `learning-bus-injector` hook implementation passes invalid path parameters to the Opencode SDK. It uses `path: { id: sessionID }` instead of the required `path: { sessionID }` for `session.messages()` and `session.promptAsync()`. This will cause URL interpolation failures.</violation>

<violation number="2" location="src/hooks/index.ts:55">
P0: Custom agent: **Opencode Compatibility**

The `execution-gate` hook implementation passes invalid path parameters to the Opencode SDK. It uses `path: { id: sessionID }` instead of the required `path: { sessionID }` for `session.messages()` and `session.promptAsync()`. This will result in SDK request failures.</violation>

<violation number="3" location="src/hooks/index.ts:57">
P0: Custom agent: **Opencode Compatibility**

The `auto-checkpoint` hook implementation passes invalid path parameters to the Opencode SDK. It uses `path: { id: sessionID }` instead of the required `path: { sessionID }` for `session.messages()` and `session.promptAsync()`. This will result in SDK request failures.</violation>
</file>

<file name="src/hooks/auto-checkpoint/hook.ts">

<violation number="1" location="src/hooks/auto-checkpoint/hook.ts:116">
P1: When `lastInjectionAt` is 0 (initial state or failed injection), `timeSinceLastInjection` incorrectly falls back to `now` (current timestamp), causing `minutesSince` to calculate as ~28 million minutes. The checkpoint prompt then displays an absurd duration. The fallback should be `0` instead of `now` to correctly indicate no time has passed since injection.</violation>
</file>

<file name="src/hooks/learning-bus-injector/event-reader.ts">

<violation number="1" location="src/hooks/learning-bus-injector/event-reader.ts:43">
P2: Unsafe property access via event.event_type could return prototype methods instead of weight values. If event_type is 'constructor', 'toString', or other Object.prototype property names, the lookup returns a function rather than undefined, bypassing the ?? 0.3 fallback and causing NaN in score calculations.</violation>

<violation number="2" location="src/hooks/learning-bus-injector/event-reader.ts:65">
P2: Use numeric timestamp comparison instead of lexicographical string comparison for date filtering</violation>
</file>

<file name="src/hooks/correction-detector/emitter.ts">

<violation number="1" location="src/hooks/correction-detector/emitter.ts:1">
P1: Unregistered 'correction-detector' hook implementation is dead code</violation>
</file>

<file name="src/hooks/correction-detector/detector.ts">

<violation number="1" location="src/hooks/correction-detector/detector.ts:14">
P2: Removing code blocks and system tags with empty string instead of space causes adjacent words to merge, breaking word boundary pattern matching for correction detection</violation>
</file>

<file name="src/hooks/resource-gate/memory-check.ts">

<violation number="1" location="src/hooks/resource-gate/memory-check.ts:115">
P2: Add platform guard to avoid unnecessary process spawning on non-macOS systems. Consider checking `process.platform === 'darwin'` before executing macOS-specific commands.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Add one-off context when rerunning by tagging @cubic-dev-ai with guidance or docs links (including llms.txt)
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

export { createLearningBusInjectorHook, type LearningBusInjectorHook } from "./learning-bus-injector"
export { createExecutionGateHook, type ExecutionGateHook } from "./execution-gate"
export { createResourceGateHook, type MemoryStatus } from "./resource-gate"
export { createAutoCheckpointHook } from "./auto-checkpoint"
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0: Custom agent: Opencode Compatibility

The auto-checkpoint hook implementation passes invalid path parameters to the Opencode SDK. It uses path: { id: sessionID } instead of the required path: { sessionID } for session.messages() and session.promptAsync(). This will result in SDK request failures.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/index.ts, line 57:

<comment>The `auto-checkpoint` hook implementation passes invalid path parameters to the Opencode SDK. It uses `path: { id: sessionID }` instead of the required `path: { sessionID }` for `session.messages()` and `session.promptAsync()`. This will result in SDK request failures.</comment>

<file context>
@@ -51,3 +51,7 @@ export { createWriteExistingFileGuardHook } from "./write-existing-file-guard";
+export { createLearningBusInjectorHook, type LearningBusInjectorHook } from "./learning-bus-injector"
+export { createExecutionGateHook, type ExecutionGateHook } from "./execution-gate"
+export { createResourceGateHook, type MemoryStatus } from "./resource-gate"
+export { createAutoCheckpointHook } from "./auto-checkpoint"
</file context>
Fix with Cubic

export { createJsonErrorRecoveryHook, JSON_ERROR_TOOL_EXCLUDE_LIST, JSON_ERROR_PATTERNS, JSON_ERROR_REMINDER } from "./json-error-recovery";
export { createReadImageResizerHook } from "./read-image-resizer"
export { createLearningBusInjectorHook, type LearningBusInjectorHook } from "./learning-bus-injector"
export { createExecutionGateHook, type ExecutionGateHook } from "./execution-gate"
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0: Custom agent: Opencode Compatibility

The execution-gate hook implementation passes invalid path parameters to the Opencode SDK. It uses path: { id: sessionID } instead of the required path: { sessionID } for session.messages() and session.promptAsync(). This will result in SDK request failures.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/index.ts, line 55:

<comment>The `execution-gate` hook implementation passes invalid path parameters to the Opencode SDK. It uses `path: { id: sessionID }` instead of the required `path: { sessionID }` for `session.messages()` and `session.promptAsync()`. This will result in SDK request failures.</comment>

<file context>
@@ -51,3 +51,7 @@ export { createWriteExistingFileGuardHook } from "./write-existing-file-guard";
 export { createJsonErrorRecoveryHook, JSON_ERROR_TOOL_EXCLUDE_LIST, JSON_ERROR_PATTERNS, JSON_ERROR_REMINDER } from "./json-error-recovery";
 export { createReadImageResizerHook } from "./read-image-resizer"
+export { createLearningBusInjectorHook, type LearningBusInjectorHook } from "./learning-bus-injector"
+export { createExecutionGateHook, type ExecutionGateHook } from "./execution-gate"
+export { createResourceGateHook, type MemoryStatus } from "./resource-gate"
+export { createAutoCheckpointHook } from "./auto-checkpoint"
</file context>
Fix with Cubic

export { createHashlineReadEnhancerHook } from "./hashline-read-enhancer";
export { createJsonErrorRecoveryHook, JSON_ERROR_TOOL_EXCLUDE_LIST, JSON_ERROR_PATTERNS, JSON_ERROR_REMINDER } from "./json-error-recovery";
export { createReadImageResizerHook } from "./read-image-resizer"
export { createLearningBusInjectorHook, type LearningBusInjectorHook } from "./learning-bus-injector"
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0: Custom agent: Opencode Compatibility

The learning-bus-injector hook implementation passes invalid path parameters to the Opencode SDK. It uses path: { id: sessionID } instead of the required path: { sessionID } for session.messages() and session.promptAsync(). This will cause URL interpolation failures.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/index.ts, line 54:

<comment>The `learning-bus-injector` hook implementation passes invalid path parameters to the Opencode SDK. It uses `path: { id: sessionID }` instead of the required `path: { sessionID }` for `session.messages()` and `session.promptAsync()`. This will cause URL interpolation failures.</comment>

<file context>
@@ -51,3 +51,7 @@ export { createWriteExistingFileGuardHook } from "./write-existing-file-guard";
 export { createHashlineReadEnhancerHook } from "./hashline-read-enhancer";
 export { createJsonErrorRecoveryHook, JSON_ERROR_TOOL_EXCLUDE_LIST, JSON_ERROR_PATTERNS, JSON_ERROR_REMINDER } from "./json-error-recovery";
 export { createReadImageResizerHook } from "./read-image-resizer"
+export { createLearningBusInjectorHook, type LearningBusInjectorHook } from "./learning-bus-injector"
+export { createExecutionGateHook, type ExecutionGateHook } from "./execution-gate"
+export { createResourceGateHook, type MemoryStatus } from "./resource-gate"
</file context>
Fix with Cubic


export const HOOK_NAME = "execution-gate"

export const VAULT_ROOT = path.join(
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Custom agent: Opencode Compatibility

Hardcoding a personal iCloud Obsidian vault path breaks cross-platform compatibility and usability for other Opencode users. Use an environment variable or a standard Opencode configuration directory instead.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/execution-gate/constants.ts, line 6:

<comment>Hardcoding a personal iCloud Obsidian vault path breaks cross-platform compatibility and usability for other Opencode users. Use an environment variable or a standard Opencode configuration directory instead.</comment>

<file context>
@@ -0,0 +1,21 @@
+
+export const HOOK_NAME = "execution-gate"
+
+export const VAULT_ROOT = path.join(
+  os.homedir(),
+  "Library/Mobile Documents/iCloud~md~obsidian/Documents/Mind Palace",
</file context>
Fix with Cubic


// Check thresholds: idle count (proxy for messages) or time since last injection
const idlesSinceLastInjection = state.idleCount
const timeSinceLastInjection = state.lastInjectionAt === 0 ? now : now - state.lastInjectionAt
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: When lastInjectionAt is 0 (initial state or failed injection), timeSinceLastInjection incorrectly falls back to now (current timestamp), causing minutesSince to calculate as ~28 million minutes. The checkpoint prompt then displays an absurd duration. The fallback should be 0 instead of now to correctly indicate no time has passed since injection.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/auto-checkpoint/hook.ts, line 116:

<comment>When `lastInjectionAt` is 0 (initial state or failed injection), `timeSinceLastInjection` incorrectly falls back to `now` (current timestamp), causing `minutesSince` to calculate as ~28 million minutes. The checkpoint prompt then displays an absurd duration. The fallback should be `0` instead of `now` to correctly indicate no time has passed since injection.</comment>

<file context>
@@ -0,0 +1,157 @@
+
+    // Check thresholds: idle count (proxy for messages) or time since last injection
+    const idlesSinceLastInjection = state.idleCount
+    const timeSinceLastInjection = state.lastInjectionAt === 0 ? now : now - state.lastInjectionAt
+
+    const messageThresholdMet = idlesSinceLastInjection >= CHECKPOINT_MESSAGE_THRESHOLD
</file context>
Suggested change
const timeSinceLastInjection = state.lastInjectionAt === 0 ? now : now - state.lastInjectionAt
const timeSinceLastInjection = state.lastInjectionAt === 0 ? 0 : now - state.lastInjectionAt
Fix with Cubic

@@ -0,0 +1,98 @@
import * as fs from "node:fs"
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Unregistered 'correction-detector' hook implementation is dead code

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/correction-detector/emitter.ts:

<comment>Unregistered 'correction-detector' hook implementation is dead code</comment>

<file context>
@@ -0,0 +1,98 @@
+import * as fs from "node:fs"
+import * as path from "node:path"
+import * as os from "node:os"
+
+import { SYSTEM_EVENTS_PATH, SEVERITY_WEIGHTS, HOOK_NAME } from "./constants"
+import type { DetectedCorrection } from "./detector"
+import { highestSeverity } from "./detector"
+import { log } from "../../shared/logger"
+
</file context>
Fix with Cubic

if (!line.trim()) continue
try {
const event = JSON.parse(line) as SystemEvent
if (event.timestamp >= cutoffStr) {
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Use numeric timestamp comparison instead of lexicographical string comparison for date filtering

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/learning-bus-injector/event-reader.ts, line 65:

<comment>Use numeric timestamp comparison instead of lexicographical string comparison for date filtering</comment>

<file context>
@@ -0,0 +1,84 @@
+      if (!line.trim()) continue
+      try {
+        const event = JSON.parse(line) as SystemEvent
+        if (event.timestamp >= cutoffStr) {
+          const confidence = event.confidence ?? 0.8
+          if (confidence >= MIN_CONFIDENCE) {
</file context>
Fix with Cubic

}

function computeScore(event: SystemEvent): number {
const typeWeight = EVENT_TYPE_WEIGHTS[event.event_type] ?? 0.3
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Unsafe property access via event.event_type could return prototype methods instead of weight values. If event_type is 'constructor', 'toString', or other Object.prototype property names, the lookup returns a function rather than undefined, bypassing the ?? 0.3 fallback and causing NaN in score calculations.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/learning-bus-injector/event-reader.ts, line 43:

<comment>Unsafe property access via event.event_type could return prototype methods instead of weight values. If event_type is 'constructor', 'toString', or other Object.prototype property names, the lookup returns a function rather than undefined, bypassing the ?? 0.3 fallback and causing NaN in score calculations.</comment>

<file context>
@@ -0,0 +1,84 @@
+}
+
+function computeScore(event: SystemEvent): number {
+  const typeWeight = EVENT_TYPE_WEIGHTS[event.event_type] ?? 0.3
+  const confidence = event.confidence ?? 0.8
+  const recency = recencyScore(event.timestamp)
</file context>
Fix with Cubic

*/
function cleanText(text: string): string {
return text
.replace(/```[\s\S]*?```/g, "")
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Removing code blocks and system tags with empty string instead of space causes adjacent words to merge, breaking word boundary pattern matching for correction detection

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/correction-detector/detector.ts, line 14:

<comment>Removing code blocks and system tags with empty string instead of space causes adjacent words to merge, breaking word boundary pattern matching for correction detection</comment>

<file context>
@@ -0,0 +1,52 @@
+ */
+function cleanText(text: string): string {
+  return text
+    .replace(/```[\s\S]*?```/g, "")
+    .replace(/`[^`]+`/g, "")
+    .replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "")
</file context>
Fix with Cubic

}
}

export function checkMacOSMemory(): MemoryStatus {
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Add platform guard to avoid unnecessary process spawning on non-macOS systems. Consider checking process.platform === 'darwin' before executing macOS-specific commands.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/resource-gate/memory-check.ts, line 115:

<comment>Add platform guard to avoid unnecessary process spawning on non-macOS systems. Consider checking `process.platform === 'darwin'` before executing macOS-specific commands.</comment>

<file context>
@@ -0,0 +1,136 @@
+  }
+}
+
+export function checkMacOSMemory(): MemoryStatus {
+  try {
+    const vmStatOutput = execSync("vm_stat", { encoding: "utf8" })
</file context>
Fix with Cubic

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