Skip to content

Post-completion hook and session continuation for finished loops #314

@akuehner

Description

@akuehner

Two related gaps in loop lifecycle after a loop finishes.

B1: No post-completion action

When a loop passes, finishLoop("pass") (project-loop.js ~line 621) fires a push notification but has no mechanism to run a follow-up action (a slash command, a git operation, or any user-defined callback).

Suggested implementation

Add an onPass field to the loop registry schema. In lib/scheduler.js update() (~line 347), add:

if (data.onPass !== undefined) rec.onPass = data.onPass;

In lib/project-loop.js finishLoop() (~line 638, after the registry recordRun call), add:

if (reason === "pass" && loopState.loopId) {
  var source = loopRegistry.getById(loopState.loopId);
  if (source && source.onPass) {
    var followUp = sm.createSession();
    followUp.title = (source.name || "Task") + " — post-completion";
    sm.saveSessionFile(followUp);
    sm.broadcastSessionList();
    var userMsg = { type: "user_message", text: source.onPass };
    followUp.history.push(userMsg);
    sm.appendToSessionFile(followUp, userMsg);
    followUp.isProcessing = true;
    onProcessingChanged();
    followUp.sentToolResults = {};
    sdk.startQuery(followUp, source.onPass, undefined, getLinuxUserForSession(followUp));
  }
}

The scheduler detail Meta tab would need a field to set onPass (e.g., a text input labeled "Run on success").

B2: Completed loop sessions are not interactive

All loop sessions (coder + judge) are created with singleTurn = true (project-loop.js lines 479, 595), which calls messageQueue.end() in the SDK worker (sdk-worker.js:314). After completion, sessions are read-only transcripts.

Re-opening a closed message queue is not safe. A cleaner path is a "Continue" action that creates a new session seeded with the loop context.

Suggested implementation

lib/project-loop.js — add a new message handler:

if (msg.type === "loop_continue_session") {
  var sourceSession = sm.sessions.get(msg.sessionId);
  if (!sourceSession || !sourceSession.loop) {
    sendTo(ws, { type: "error", text: "Session not found or not a loop session" });
    return true;
  }
  var contSession = sm.createSession();
  contSession.title = (sourceSession.title || "Loop") + " (continued)";
  contSession.parentLoopSession = msg.sessionId;
  sm.saveSessionFile(contSession);
  sm.broadcastSessionList();
  sendTo(ws, { type: "loop_continue_ready", sessionId: contSession.localId });
  return true;
}

The frontend would add a "Continue" button on completed loop sessions (in the session header or sidebar context menu) that sends this message and switches to the new session.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions