fix: background observer fails closed on confirmation/permission prompts (#400)#403
Conversation
…-m#400) - Redirect observer output to temp log before appending to main log - Check temp log for confirmation/permission language immediately after start - Fail closed with exit 2 if detected, preventing retry loops
📝 WalkthroughWalkthroughAdds sentinel-based guard and prompt-detection to the continuous-learning-v2 observer: new sentinel file handling, CLI --reset/status/stop controls, prompt-pattern scanning on start, observer PID/USR1 signaling, Windows Python detection, secret-scrubbing improvements, and tests for sentinel/guard behavior. Changes
Sequence Diagram(s)mermaid Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
skills/continuous-learning-v2/agents/start-observer.sh (1)
156-171:⚠️ Potential issue | 🟡 MinorTemp log file not cleaned up on successful start.
OBSERVER_LOG_TMPis only removed on abort (line 180). On successful startup, the temp file persists indefinitely and output continues writing to it instead ofLOG_FILE. Either merge the temp log into the main log and delete it, or redirect subsequent output toLOG_FILEafter the check passes.🔧 Proposed fix: Clean up temp log on success
Add after line 182 (before the PID file check):
fi + + # Merge temp log into main log and clean up + if [ -f "$OBSERVER_LOG_TMP" ]; then + cat "$OBSERVER_LOG_TMP" >> "$LOG_FILE" + rm -f "$OBSERVER_LOG_TMP" + fi if [ -f "$PID_FILE" ]; then🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/continuous-learning-v2/agents/start-observer.sh` around lines 156 - 171, The temp log OBSERVER_LOG_TMP created before launching OBSERVER_LOOP_SCRIPT is left behind and continues receiving output; after verifying the background process started (the existing PID_FILE/PID check), append or move the contents of OBSERVER_LOG_TMP into the intended LOG_FILE, remove OBSERVER_LOG_TMP, and ensure future output goes to LOG_FILE (i.e., update redirection so nohup's stdout/stderr ultimately target LOG_FILE or rotate the file and reopen descriptors). Locate the startup block using OBSERVER_LOG_TMP, OBSERVER_LOOP_SCRIPT, LOG_FILE and PID_FILE and add the merge/delete and redirection fix immediately after the startup check so no temp file persists.
🧹 Nitpick comments (2)
skills/continuous-learning-v2/hooks/observe.sh (1)
36-46: Windows Python paths are limited to specific versions.The hardcoded paths only check Python 3.10, 3.11, and 3.12. Consider using a glob pattern or loop to discover Python installations more dynamically, which would handle future Python versions (e.g., 3.13+) without code changes.
💡 Optional: Use glob pattern for more flexible detection
- for win_py in \ - "/c/Users/$USER/AppData/Local/Programs/Python/Python311/python" \ - "/c/Users/$USER/AppData/Local/Programs/Python/Python312/python" \ - "/c/Users/$USER/AppData/Local/Programs/Python/Python310/python"; do - if [ -x "$win_py" ]; then - printf '%s\n' "$win_py" - return 0 - fi - done + # Check Windows Python install paths with glob pattern + for win_py in /c/Users/"$USER"/AppData/Local/Programs/Python/Python3*/python; do + if [ -x "$win_py" ]; then + printf '%s\n' "$win_py" + return 0 + fi + done🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/continuous-learning-v2/hooks/observe.sh` around lines 36 - 46, Replace the hardcoded version-specific list in the Windows-check loop with a glob-based discovery so future Python versions are found automatically: modify the loop that iterates over win_py (currently enumerating Python310/311/312) to iterate over the pattern "/c/Users/$USER/AppData/Local/Programs/Python/Python*/python" (or similar glob) and keep the existing -x check and printf/return behavior in the same loop in observe.sh so any matching Python executable is picked up without updating versions.skills/continuous-learning-v2/agents/start-observer.sh (1)
131-147: No recovery path from circuit-breaker state.Once
observe.shwrites the sentinel file (.observer.lock), the observer is permanently disabled. Thestartcommand doesn't check for or offer to remove the sentinel file, requiring users to manually delete it. Consider adding a--resetflag or checking the sentinel on explicit start.💡 Suggested: Add sentinel check and optional reset
start) # Check if observer is disabled in config if [ "$OBSERVER_ENABLED" != "true" ]; then echo "Observer is disabled in config.json (observer.enabled: false)." echo "Set observer.enabled to true in config.json to enable." exit 1 fi + # Check for circuit-breaker sentinel + SENTINEL_FILE="${PROJECT_DIR}/.observer.lock" + if [ -f "$SENTINEL_FILE" ]; then + echo "Observer was previously disabled due to confirmation/permission prompt." + echo "Sentinel file: $SENTINEL_FILE" + if [ "${2:-}" = "--reset" ]; then + echo "Resetting circuit-breaker..." + rm -f "$SENTINEL_FILE" + else + echo "Run '$0 start --reset' to clear the sentinel and retry." + exit 1 + fi + fi + # Check if already running🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/continuous-learning-v2/agents/start-observer.sh` around lines 131 - 147, The start branch currently never checks or clears the circuit-breaker sentinel (e.g., .observer.lock), so once written the observer cannot be restarted; update the start command logic in start-observer.sh to detect the sentinel file (introduce/inspect a variable like SENTINEL_FILE or OBSERVER_LOCK alongside PID_FILE), exit with a clear message if the sentinel exists, and support an explicit override flag (e.g., --reset passed to the script) that safely removes the sentinel before continuing startup; ensure the start case honors the flag, performs safe existence checks and removal of the sentinel file, and then proceeds with the existing PID_FILE/running checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@skills/continuous-learning-v2/agents/start-observer.sh`:
- Around line 176-182: The abort branch exits without stopping the background
observer, leaving an orphaned process; capture or use the observer PID (the
variable set when launching the observer, e.g., the PID saved from $!—refer to
where the observer is started) and terminate that process before exiting: send a
graceful kill (SIGTERM) to the observer PID, wait for it to exit and if it
doesn’t, escalate to SIGKILL, then append the tmp log to LOG_FILE, clean up
OBSERVER_LOG_TMP, and finally exit 2; ensure you handle the case where the PID
is empty or the process is already gone to avoid errors.
In `@skills/continuous-learning-v2/hooks/observe.sh`:
- Around line 216-224: The grep pattern used to detect confirmation/permission
prompts is inconsistent between observe.sh (the pattern in the echo "$PARSED" |
grep -E -i -q "once granted access|grant.*access" branch) and start-observer.sh
which omits those tokens; unify them by extracting the regex into a single
shared constant (e.g., export OBSERVER_PROMPT_PATTERN in a common sourced file
or environment variable) and replace both inline grep calls to use that constant
(reference PARSED, the grep invocation, and SENTINEL_FILE for the abort flow) so
both scripts detect the same prompts and the sentinel/circuit-breaker behavior
stays consistent.
---
Outside diff comments:
In `@skills/continuous-learning-v2/agents/start-observer.sh`:
- Around line 156-171: The temp log OBSERVER_LOG_TMP created before launching
OBSERVER_LOOP_SCRIPT is left behind and continues receiving output; after
verifying the background process started (the existing PID_FILE/PID check),
append or move the contents of OBSERVER_LOG_TMP into the intended LOG_FILE,
remove OBSERVER_LOG_TMP, and ensure future output goes to LOG_FILE (i.e., update
redirection so nohup's stdout/stderr ultimately target LOG_FILE or rotate the
file and reopen descriptors). Locate the startup block using OBSERVER_LOG_TMP,
OBSERVER_LOOP_SCRIPT, LOG_FILE and PID_FILE and add the merge/delete and
redirection fix immediately after the startup check so no temp file persists.
---
Nitpick comments:
In `@skills/continuous-learning-v2/agents/start-observer.sh`:
- Around line 131-147: The start branch currently never checks or clears the
circuit-breaker sentinel (e.g., .observer.lock), so once written the observer
cannot be restarted; update the start command logic in start-observer.sh to
detect the sentinel file (introduce/inspect a variable like SENTINEL_FILE or
OBSERVER_LOCK alongside PID_FILE), exit with a clear message if the sentinel
exists, and support an explicit override flag (e.g., --reset passed to the
script) that safely removes the sentinel before continuing startup; ensure the
start case honors the flag, performs safe existence checks and removal of the
sentinel file, and then proceeds with the existing PID_FILE/running checks.
In `@skills/continuous-learning-v2/hooks/observe.sh`:
- Around line 36-46: Replace the hardcoded version-specific list in the
Windows-check loop with a glob-based discovery so future Python versions are
found automatically: modify the loop that iterates over win_py (currently
enumerating Python310/311/312) to iterate over the pattern
"/c/Users/$USER/AppData/Local/Programs/Python/Python*/python" (or similar glob)
and keep the existing -x check and printf/return behavior in the same loop in
observe.sh so any matching Python executable is picked up without updating
versions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: ba0dbe6b-ef06-4256-b5ab-d5906d24a3df
📒 Files selected for processing (2)
skills/continuous-learning-v2/agents/start-observer.shskills/continuous-learning-v2/hooks/observe.sh
| # Check for confirmation-seeking output in the observer log | ||
| if grep -E -i -q "Can you confirm|requires permission|Awaiting|confirm I should proceed" "$OBSERVER_LOG_TMP"; then | ||
| echo "OBSERVER_ABORT: Confirmation or permission prompt detected in observer output. Failing closed." | ||
| cat "$OBSERVER_LOG_TMP" >> "$LOG_FILE" | ||
| rm -f "$OBSERVER_LOG_TMP" | ||
| exit 2 | ||
| fi |
There was a problem hiding this comment.
Observer process not terminated on abort.
When a confirmation prompt is detected, the script exits with code 2 but the backgrounded observer process (launched at line 171) continues running. This leaves an orphaned process that may continue consuming resources or producing unwanted behavior.
🔧 Proposed fix: Kill the observer process on abort
# Check for confirmation-seeking output in the observer log
if grep -E -i -q "Can you confirm|requires permission|Awaiting|confirm I should proceed" "$OBSERVER_LOG_TMP"; then
echo "OBSERVER_ABORT: Confirmation or permission prompt detected in observer output. Failing closed."
cat "$OBSERVER_LOG_TMP" >> "$LOG_FILE"
rm -f "$OBSERVER_LOG_TMP"
+ # Kill the backgrounded observer process
+ if [ -f "$PID_FILE" ]; then
+ pid=$(cat "$PID_FILE")
+ kill "$pid" 2>/dev/null || true
+ rm -f "$PID_FILE"
+ fi
exit 2
fi🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/continuous-learning-v2/agents/start-observer.sh` around lines 176 -
182, The abort branch exits without stopping the background observer, leaving an
orphaned process; capture or use the observer PID (the variable set when
launching the observer, e.g., the PID saved from $!—refer to where the observer
is started) and terminate that process before exiting: send a graceful kill
(SIGTERM) to the observer PID, wait for it to exit and if it doesn’t, escalate
to SIGKILL, then append the tmp log to LOG_FILE, clean up OBSERVER_LOG_TMP, and
finally exit 2; ensure you handle the case where the PID is empty or the process
is already gone to avoid errors.
| # FIX: Detect confirmation/permission prompts in observer output and fail closed. | ||
| # A non-interactive background observer must never ask for user confirmation. | ||
| # If detected: log once, write sentinel to suppress all future retries, exit non-zero. | ||
| if echo "$PARSED" | grep -E -i -q "Can you confirm|requires permission|Awaiting|confirm I should proceed|once granted access|grant.*access"; then | ||
| echo "[observe] OBSERVER_ABORT: Confirmation or permission prompt detected in observer output. This observer run is non-actionable." >&2 | ||
| echo "[observe] Writing sentinel to suppress retries: ${SENTINEL_FILE}" >&2 | ||
| echo "$PARSED" > "$SENTINEL_FILE" | ||
| exit 2 | ||
| fi |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify the pattern mismatch between the two files
echo "=== Pattern in observe.sh ==="
grep -n "Can you confirm" skills/continuous-learning-v2/hooks/observe.sh
echo ""
echo "=== Pattern in start-observer.sh ==="
grep -n "Can you confirm" skills/continuous-learning-v2/agents/start-observer.sh
echo ""
echo "=== Diff of patterns ==="
# Extract and compare the patterns
obs_pattern=$(grep -oP 'grep -E -i -q "\K[^"]+' skills/continuous-learning-v2/hooks/observe.sh | head -1)
start_pattern=$(grep -oP 'grep -E -i -q "\K[^"]+' skills/continuous-learning-v2/agents/start-observer.sh | head -1)
echo "observe.sh: $obs_pattern"
echo "start-observer.sh: $start_pattern"Repository: affaan-m/everything-claude-code
Length of output: 646
Pattern mismatch between observe.sh and start-observer.sh creates detection gaps.
The grep pattern at observe.sh:219 includes "once granted access|grant.*access", but the corresponding check in start-observer.sh:177 omits these patterns. This inconsistency means start-observer.sh will miss prompts that observe.sh would catch, leaving gaps in the circuit-breaker coverage.
Extract the pattern to a shared constant or synchronize both files to use identical patterns.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/continuous-learning-v2/hooks/observe.sh` around lines 216 - 224, The
grep pattern used to detect confirmation/permission prompts is inconsistent
between observe.sh (the pattern in the echo "$PARSED" | grep -E -i -q "once
granted access|grant.*access" branch) and start-observer.sh which omits those
tokens; unify them by extracting the regex into a single shared constant (e.g.,
export OBSERVER_PROMPT_PATTERN in a common sourced file or environment variable)
and replace both inline grep calls to use that constant (reference PARSED, the
grep invocation, and SENTINEL_FILE for the abort flow) so both scripts detect
the same prompts and the sentinel/circuit-breaker behavior stays consistent.
There was a problem hiding this comment.
5 issues found across 2 files
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="skills/continuous-learning-v2/agents/start-observer.sh">
<violation number="1" location="skills/continuous-learning-v2/agents/start-observer.sh:171">
P1: Observer output is permanently redirected to the temp file `.observer.tmp.log` instead of `observer.log`. On the success path (no confirmation detected), neither `cat` nor `rm` is called on the temp file, so the running observer process writes all its output to a file nobody monitors. The `status` command tells users to check `$LOG_FILE`, which will be empty.
Consider keeping the original `>> "$LOG_FILE"` redirect and grepping `$LOG_FILE` for the confirmation check instead.</violation>
<violation number="2" location="skills/continuous-learning-v2/agents/start-observer.sh:177">
P1: The abort path doesn't kill the background observer process. When confirmation language is detected, the code exits 2 but the `nohup`'d process keeps running as an orphan. Capture the PID after launch and kill it before exiting.</violation>
<violation number="3" location="skills/continuous-learning-v2/agents/start-observer.sh:177">
P1: Duplicate confirmation pattern regex differs between observe.sh and start-observer.sh</violation>
</file>
<file name="skills/continuous-learning-v2/hooks/observe.sh">
<violation number="1" location="skills/continuous-learning-v2/hooks/observe.sh:219">
P1: The bare keyword `Awaiting` in this grep pattern is far too broad and will cause false positives on normal tool output (e.g., "Awaiting build completion", "awaiting API response"). Since a match writes a sentinel file that **permanently disables the observer**, a false positive silently breaks the feature until a user manually removes the lock file. Consider using a more specific phrase like `Awaiting.*confirmation` or `Awaiting.*permission`.</violation>
<violation number="2" location="skills/continuous-learning-v2/hooks/observe.sh:222">
P1: The raw `$PARSED` JSON (containing unscrubbed tool input/output) is written to the sentinel file, bypassing the secret-redaction logic that the rest of the script carefully applies before persisting to `observations.jsonl`. If the tool I/O that triggered detection contained credentials, they'd be written in plaintext. Consider writing only a short marker message or scrubbing the content first.</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-aiwith guidance or docs links (includingllms.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.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
skills/continuous-learning-v2/agents/start-observer.sh (1)
51-69:⚠️ Potential issue | 🟠 MajorThe startup fail-closed path can still miss and leak a prompted observer.
It samples the log once after a fixed 2-second delay and can only abort through
PID_FILE. If the prompt appears after that window, it is missed; if it appears beforeobserver-loop.shwrites the pid file, the freshly launched child keeps running in the background. Capture$!from thenohuplaunch and keep watching the appended log for a bounded startup window before returning success.Also applies to: 191-219
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/continuous-learning-v2/agents/start-observer.sh` around lines 51 - 69, When starting the observer (the nohup launch of observer-loop.sh), capture the child PID via $! immediately, write that PID to PID_FILE, then monitor/tail the observer log (LOG_FILE) for the specific prompt string within a bounded timeout (e.g., 5–10s); if the prompt appears return success, otherwise kill the captured PID, remove PID_FILE and return failure. Update the start logic that currently relies solely on PID_FILE and a fixed sleep to: use nohup ... & pid=$!; echo "$pid" > "$PID_FILE"; follow the log (tail -n +1 -F "$LOG_FILE" | timeout ...) watching for the prompt, and always cleanup PID_FILE and the process on timeout or error. Ensure the same pattern is applied to the other start path mentioned (lines 191-219) so both branches use $!, immediate pid-file write, bounded log-watch, and reliable cleanup.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@skills/continuous-learning-v2/hooks/observe.sh`:
- Around line 36-43: The Git Bash-specific Python probe currently only exists in
observe.sh and must be moved into the shared resolver used by
start-observer.sh/detect-project.sh so both scripts get a real Python path;
update the resolver in skills/continuous-learning-v2/scripts/detect-project.sh
(the code that sets CLV2_PYTHON_CMD) to include the same Windows Git Bash loop
that searches /c/Users/"$USER"/AppData/Local/Programs/Python/Python3*/python,
assign the result to CLV2_PYTHON_CMD (and export it if other scripts read it),
and remove the duplicate probe from observe.sh so start-observer.sh no longer
falls back to the Microsoft Store alias.
- Around line 263-270: The check is scanning the whole PARSED payload (which may
include tool_input) and falsely matching user commands; modify the
prompt-detection to extract only the observer "output" field from PARSED and run
the grep against that value (instead of full PARSED). Update the conditional
that uses PARSED and CLV2_OBSERVER_PROMPT_PATTERN so it pipes/parses only the
.output (or equivalent observer output variable) into grep, keep the same error
messages and call to write_guard_sentinel on match, and ensure the variable you
parse is empty-safe (use a default empty string) to avoid crashes in
write_guard_sentinel and exit 2 paths.
---
Duplicate comments:
In `@skills/continuous-learning-v2/agents/start-observer.sh`:
- Around line 51-69: When starting the observer (the nohup launch of
observer-loop.sh), capture the child PID via $! immediately, write that PID to
PID_FILE, then monitor/tail the observer log (LOG_FILE) for the specific prompt
string within a bounded timeout (e.g., 5–10s); if the prompt appears return
success, otherwise kill the captured PID, remove PID_FILE and return failure.
Update the start logic that currently relies solely on PID_FILE and a fixed
sleep to: use nohup ... & pid=$!; echo "$pid" > "$PID_FILE"; follow the log
(tail -n +1 -F "$LOG_FILE" | timeout ...) watching for the prompt, and always
cleanup PID_FILE and the process on timeout or error. Ensure the same pattern is
applied to the other start path mentioned (lines 191-219) so both branches use
$!, immediate pid-file write, bounded log-watch, and reliable cleanup.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 6aba866e-2d31-4c19-b6cf-31258d645015
📒 Files selected for processing (4)
skills/continuous-learning-v2/agents/start-observer.shskills/continuous-learning-v2/hooks/observe.shskills/continuous-learning-v2/scripts/detect-project.shtests/hooks/hooks.test.js
| # FIX: Windows Git Bash — probe Python install paths directly because | ||
| # `command -v python` can hit the Microsoft Store alias instead. | ||
| for win_py in /c/Users/"$USER"/AppData/Local/Programs/Python/Python3*/python; do | ||
| if [ -x "$win_py" ]; then | ||
| printf '%s\n' "$win_py" | ||
| return 0 | ||
| fi | ||
| done |
There was a problem hiding this comment.
Move the Git Bash Python probe into the shared resolver.
These lines only fix observe.sh. start-observer.sh still reads CLV2_PYTHON_CMD from skills/continuous-learning-v2/scripts/detect-project.sh, whose resolver still falls through to the Microsoft Store alias. On Git Bash that leaves the launcher without a Python interpreter, so it never reads config.json and treats the observer as disabled.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/continuous-learning-v2/hooks/observe.sh` around lines 36 - 43, The Git
Bash-specific Python probe currently only exists in observe.sh and must be moved
into the shared resolver used by start-observer.sh/detect-project.sh so both
scripts get a real Python path; update the resolver in
skills/continuous-learning-v2/scripts/detect-project.sh (the code that sets
CLV2_PYTHON_CMD) to include the same Windows Git Bash loop that searches
/c/Users/"$USER"/AppData/Local/Programs/Python/Python3*/python, assign the
result to CLV2_PYTHON_CMD (and export it if other scripts read it), and remove
the duplicate probe from observe.sh so start-observer.sh no longer falls back to
the Microsoft Store alias.
| # Detect confirmation/permission prompts in observer output and fail closed. | ||
| # A non-interactive background observer must never ask for user confirmation. | ||
| if echo "$PARSED" | grep -E -i -q "$CLV2_OBSERVER_PROMPT_PATTERN"; then | ||
| echo "[observe] OBSERVER_ABORT: Confirmation or permission prompt detected in observer output. This observer run is non-actionable." >&2 | ||
| echo "[observe] Writing sentinel to suppress retries: ${SENTINEL_FILE}" >&2 | ||
| write_guard_sentinel | ||
| exit 2 | ||
| fi |
There was a problem hiding this comment.
Only scan the parsed output for prompt text.
PARSED also includes tool_input on pre-hook events. Any user command or file body containing requires permission or confirm I should proceed will currently create the sentinel even though no observer prompt occurred.
🎯 Proposed fix
-# Detect confirmation/permission prompts in observer output and fail closed.
-# A non-interactive background observer must never ask for user confirmation.
-if echo "$PARSED" | grep -E -i -q "$CLV2_OBSERVER_PROMPT_PATTERN"; then
+# Detect confirmation/permission prompts in observer output and fail closed.
+# A non-interactive background observer must never ask for user confirmation.
+parsed_output=$(printf '%s' "$PARSED" | "$PYTHON_CMD" -c 'import json,sys; print(json.load(sys.stdin).get("output") or "")' 2>/dev/null || true)
+if [ "$HOOK_PHASE" = "post" ] && [ -n "$parsed_output" ] && printf '%s' "$parsed_output" | grep -E -i -q "$CLV2_OBSERVER_PROMPT_PATTERN"; then
echo "[observe] OBSERVER_ABORT: Confirmation or permission prompt detected in observer output. This observer run is non-actionable." >&2
echo "[observe] Writing sentinel to suppress retries: ${SENTINEL_FILE}" >&2
write_guard_sentinel
exit 2
fi🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/continuous-learning-v2/hooks/observe.sh` around lines 263 - 270, The
check is scanning the whole PARSED payload (which may include tool_input) and
falsely matching user commands; modify the prompt-detection to extract only the
observer "output" field from PARSED and run the grep against that value (instead
of full PARSED). Update the conditional that uses PARSED and
CLV2_OBSERVER_PROMPT_PATTERN so it pipes/parses only the .output (or equivalent
observer output variable) into grep, keep the same error messages and call to
write_guard_sentinel on match, and ensure the variable you parse is empty-safe
(use a default empty string) to avoid crashes in write_guard_sentinel and exit 2
paths.
fix: background observer fails closed on confirmation/permission prompts (affaan-m#400)
Problem
Fixes #400
The background observer does not fail closed when it encounters confirmation/permission flows. Instead it:
Changes
skills/continuous-learning-v2/hooks/observe.shSENTINEL_FILEdefinition to afterdetect-project.shsoPROJECT_DIRis setskills/continuous-learning-v2/agents/start-observer.shTesting
observe.shwith simulated tool input — exits 0, writes clean observation to logSummary by cubic
Make the background observer fail closed on confirmation/permission prompts to stop timeouts, retries, and wasted usage. Adds a shared prompt guard, a sentinel-based circuit breaker, early log scanning at startup, and a Windows Git Bash Python fix.
CLV2_OBSERVER_PROMPT_PATTERN; exit 2 and write.observer.lockin the project root (usestart-observer.sh --resetto clear).CLV2_OBSERVER_PROMPT_PATTERNandCLV2_OBSERVER_SENTINEL_FILEfromdetect-project.shsoobserve.shandstart-observer.shshare the same config.observer.log, scan newly written lines immediately for prompt language, and fail closed before continuing.Written for commit 1c1a9ef. Summary will update on new commits.
Summary by CodeRabbit
New Features
Bug Fixes / Stability
Tests