Problem
When pi performs compaction (auto-compaction or /compact), the Ralph Wiggum loop silently stops working. The agent continues, but ralph_done returns "No active Ralph loop" and the iteration counter freezes.
Root Cause
The extension maintains loop state in two places:
- On-disk (persistent):
.ralph/<name>.state.json tracks status, iteration count, etc.
- In-memory (ephemeral): A closure variable
let currentLoop: string | null = null tracks which loop is active.
When compaction happens, the session reloads and the extension module is re-initialized, resetting currentLoop to null. The on-disk state remains intact, but the extension has no reference to it.
The session_start handler finds active loops on disk and notifies the user, but never restores currentLoop:
pi.on("session_start", async (_event, ctx) => {
const active = listLoops(ctx).filter((l) => l.status === "active");
if (active.length > 0 && ctx.hasUI) {
const lines = active.map(/* ... */);
ctx.ui.notify(`Active Ralph loops:\n${lines.join("\n")}\n\nUse /ralph resume <name> to continue`, "info");
}
updateUI(ctx); // currentLoop is still null here
});
After this, all currentLoop-dependent code silently fails:
ralph_done: returns "No active Ralph loop"
agent_end: early-returns without checking completion markers
before_agent_start: early-returns without injecting loop instructions
Proposed Fix
Restore currentLoop from disk state in the session_start handler:
pi.on("session_start", async (_event, ctx) => {
const active = listLoops(ctx).filter((l) => l.status === "active");
if (active.length > 0) {
// Restore currentLoop from disk state (critical for surviving compaction)
if (!currentLoop) {
currentLoop = active[0].name;
}
if (ctx.hasUI) {
const lines = active.map(/* ... */);
ctx.ui.notify(`Active Ralph loops:\n${lines.join("\n")}\n\nUse /ralph resume <name> to continue`, "info");
}
}
updateUI(ctx);
});
This ensures that after compaction (or any session reload), the first active loop found on disk is restored as currentLoop, allowing ralph_done and agent_end to function correctly.
Alternative Considerations
- If multiple loops are active, restoring
active[0] may not be the one the user was working on. A more robust solution might track a "last active" loop or use a dedicated session_compact handler.
- Consider using
pi.appendEntry() to persist loop state in the session itself, making it survive compaction without relying on the session_start rehydration path.
Problem
When pi performs compaction (auto-compaction or
/compact), the Ralph Wiggum loop silently stops working. The agent continues, butralph_donereturns "No active Ralph loop" and the iteration counter freezes.Root Cause
The extension maintains loop state in two places:
.ralph/<name>.state.jsontracks status, iteration count, etc.let currentLoop: string | null = nulltracks which loop is active.When compaction happens, the session reloads and the extension module is re-initialized, resetting
currentLooptonull. The on-disk state remains intact, but the extension has no reference to it.The
session_starthandler finds active loops on disk and notifies the user, but never restorescurrentLoop:After this, all
currentLoop-dependent code silently fails:ralph_done: returns "No active Ralph loop"agent_end: early-returns without checking completion markersbefore_agent_start: early-returns without injecting loop instructionsProposed Fix
Restore
currentLoopfrom disk state in thesession_starthandler:This ensures that after compaction (or any session reload), the first active loop found on disk is restored as
currentLoop, allowingralph_doneandagent_endto function correctly.Alternative Considerations
active[0]may not be the one the user was working on. A more robust solution might track a "last active" loop or use a dedicatedsession_compacthandler.pi.appendEntry()to persist loop state in the session itself, making it survive compaction without relying on thesession_startrehydration path.