Skip to content

Ralph Loop accepts an untagged response as a completion promise #282

Description

@abhinavgautam01

Description

ralph-loop/hooks/capture-response.sh is intended to recognize a completion promise only when an assistant response contains:

<promise>EXPECTED TEXT</promise>

The current Perl expression uses -p:

PROMISE_TEXT=$(echo "$RESPONSE_TEXT" | perl -0777 -pe 's/.*?<promise>(.*?)<\/promise>.*/$1/s; s/^\s+|\s+$//g; s/\s+/ /g' 2>/dev/null || echo "")

Perl's -p mode prints the pattern space even when the <promise> substitution does not match. Consequently, an untagged response is returned as PROMISE_TEXT after whitespace normalization.

If that response exactly matches the configured completion promise, the hook creates .cursor/ralph/done. The stop hook then treats the loop as complete and terminates it, even though the required <promise> tag was absent.

Affected files

  • ralph-loop/hooks/capture-response.sh, lines 39–44
  • ralph-loop/hooks/stop-hook.sh, lines 43–48 and 73–77

Steps to reproduce

Run the current extraction expression with an untagged response:

printf '%s' 'ALL TESTS PASS' | \
  perl -0777 -pe 's/.*?<promise>(.*?)<\/promise>.*/$1/s; s/^\s+|\s+$//g; s/\s+/ /g'

Actual output:

ALL TESTS PASS

In an active Ralph Loop whose configured completion promise is ALL TESTS PASS, this untagged response satisfies the equality check and creates the done flag.

Expected behavior

When the response does not contain a complete <promise>...</promise> element, PROMISE_TEXT should be empty and the done flag should not be created.

Actual behavior

An untagged response is treated as the extracted promise text and can prematurely complete the loop when it equals the configured promise.

Proposed fix

Use non-printing mode and print only after an explicit tag match:

PROMISE_TEXT=$(echo "$RESPONSE_TEXT" | perl -0777 -ne '
  if (/<promise>(.*?)<\/promise>/s) {
    my $p = $1;
    $p =~ s/^\s+|\s+$//g;
    $p =~ s/\s+/ /g;
    print $p;
  }
' 2>/dev/null || echo "")

Acceptance criteria

  • An untagged response that equals the configured completion promise does not create the done flag.
  • A correctly tagged promise still creates the done flag.
  • Whitespace inside a tagged promise continues to be normalized before comparison.
  • Empty, malformed, or partially closed promise tags do not complete the loop.
  • Tests cover both tagged and untagged responses.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions