Ralph Loop: Stop hook `decision: block` resets VSCode permission mode from bypass to edit

Resolved 💬 3 comments Opened Mar 25, 2026 by Master-Rensei Closed Mar 28, 2026

Bug Description

When using the Ralph Loop plugin in the VSCode extension (Antigravity), each loop iteration resets the permission mode from bypassPermissions to editMode. This makes Ralph Loop unusable for unattended/overnight autonomous operation.

Steps to Reproduce

  1. Set VSCode Claude Code to bypassPermissions mode (Shift+Tab)
  2. Verify claudeCode.initialPermissionMode: "bypassPermissions" in VSCode settings
  3. Start a Ralph Loop: /ralph-loop "task description" --max-iterations 5
  4. Wait for the first iteration to complete
  5. Observe: permission mode resets to editMode when the Stop hook blocks and re-injects

Expected Behavior

Permission mode should be preserved across Ralph Loop iterations. The decision: block response should not trigger a permission state reset.

Root Cause

The Ralph Loop Stop hook (stop-hook.sh) outputs:

{
  "decision": "block",
  "reason": "<prompt>",
  "systemMessage": "<iteration info>"
}

When the VSCode extension processes this blocked stop, it re-initializes the session context. During re-initialization, the extension reads the permission mode from its state database (state.vscdb) but appears to reset it to a default restrictive mode instead of preserving the current runtime state.

The Stop hook API has no mechanism to pass permission state through the block response.

Environment

  • VSCode extension: Antigravity (Claude Code)
  • Platform: Windows 11 (Git Bash)
  • Plugin: ralph-loop (official, claude-plugins-official)
  • Settings: claudeCode.initialPermissionMode: "bypassPermissions", claudeCode.allowDangerouslySkipPermissions: true

Workaround

Created a companion Stop hook that uses Python's sqlite3 module to update the VSCode state database (state.vscdb) and force bypassPermissions before the session reinitializes:

#!/bin/bash
# Only run if Ralph Loop is active
[[ ! -f ".claude/ralph-loop.local.md" ]] && exit 0

py -3 -c "
import sqlite3, os, glob
appdata = os.environ.get('APPDATA', '')
if not appdata: exit(0)
dbs = [os.path.join(appdata, 'Antigravity', 'User', 'globalStorage', 'state.vscdb')]
dbs += glob.glob(os.path.join(appdata, 'Antigravity', 'User', 'workspaceStorage', '*', 'state.vscdb'))
for db_path in dbs:
    if not os.path.exists(db_path): continue
    try:
        conn = sqlite3.connect(db_path)
        conn.execute(\"UPDATE ItemTable SET value='\\\"bypassPermissions\\\"' WHERE key LIKE '%permissionMode%' AND value!='\\\"bypassPermissions\\\"'\")
        conn.commit()
        conn.close()
    except: pass
" 2>/dev/null || true

Suggested Fix

Either:

  1. Preserve the current permission mode across Stop hook block responses
  2. Add a preservePermissions: true field to the Stop hook response schema
  3. Re-read claudeCode.initialPermissionMode from VSCode settings on re-initialization instead of resetting to a default

Labels

bug, ralph-loop, vscode-extension

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗