Skip to content

fix: pass project cwd to mgrep watch subprocess#137

Open
mostrub wants to merge 1 commit intomixedbread-ai:mainfrom
mostrub:fix/mgrep-watch-cwd
Open

fix: pass project cwd to mgrep watch subprocess#137
mostrub wants to merge 1 commit intomixedbread-ai:mainfrom
mostrub:fix/mgrep-watch-cwd

Conversation

@mostrub
Copy link

@mostrub mostrub commented Mar 12, 2026

Problem

When Claude Code starts a session, the SessionStart hook launches mgrep watch as a background process. The hook reads cwd from the hook payload — the project directory Claude was opened in — but never passes it to subprocess.Popen. The watcher inherits the working directory of the hook runner instead, which is typically the home directory. It immediately hits the home-directory guard and exits with "Cannot watch home directory or any parent directory." The watcher never starts, and because the failure is silent, it looks like mgrep simply is not indexing anything.

Root cause

In mgrep_watch.py, payload.get("cwd") is called and assigned to cwd, but that value is never used. The subprocess.Popen call has no cwd argument, so Python falls back to os.getcwd() at the time the hook runs — not the project directory.

Fix

Pass cwd=cwd to subprocess.Popen. One argument, no other behaviour changes.

I also removed the debug_log(f"All environment variables: {os.environ}") line. It was writing the full process environment to a file under /tmp on every session start. That includes anything sensitive in the environment — API keys, tokens, whatever the user has set. It is not something that should be sitting in a world-readable temp directory, and it was not adding anything useful once the actual bug was fixed.

Testing

Tested on macOS 15 with Claude Code and the mgrep plugin installed. Before the fix, every session start produced the home-directory error in the watcher log. After the fix, the watcher starts in the correct project directory and the initial sync completes. Verified against a project with 223 files — all indexed cleanly on first run.


Note

Low Risk
Low risk change limited to the SessionStart hook: it only adjusts the working directory used to launch mgrep watch and removes overly-verbose/sensitive debug logging.

Overview
Fixes mgrep watch startup by launching the watcher subprocess with cwd from the hook payload so it runs in the project directory instead of the hook runner’s default directory.

Also tightens logging by writing watcher stdout/stderr to a single per-session log file and removing the debug line that dumped all environment variables to disk under /tmp.

Written by Cursor Bugbot for commit 0f22366. This will update automatically on new commits. Configure here.

Copilot AI review requested due to automatic review settings March 12, 2026 14:34
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes mgrep watch startup in the SessionStart hook by ensuring the watcher subprocess runs from the actual project directory rather than inheriting the hook runner’s working directory (often ~/), which can cause watch initialization failures.

Changes:

  • Pass cwd from the hook payload into the subprocess.Popen(["mgrep", "watch"], ...) invocation.
  • Add a debug log line indicating which working directory the watcher is being started in.
  • Consolidate watcher stdout/stderr into a single session-scoped log file handle.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +42 to +44
debug_log(f"Starting mgrep watch in cwd: {cwd}")
log_file = open(f"/tmp/mgrep-watch-command-{payload.get('session_id')}.log", "w")
process = subprocess.Popen(["mgrep", "watch"], cwd=cwd, preexec_fn=os.setsid, stdout=log_file, stderr=log_file)
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cwd is taken from the hook payload and passed directly to subprocess.Popen. If the payload is missing/invalid or cwd is None/not a directory, this will either crash earlier (payload.get) or raise in Popen, making the hook fail in a hard-to-diagnose way. Consider validating payload and cwd (non-empty, exists, is a directory) and exiting with a clear debug log if it’s not usable.

Copilot uses AI. Check for mistakes.

process = subprocess.Popen(["mgrep", "watch"], preexec_fn=os.setsid, stdout=open(f"/tmp/mgrep-watch-command-{payload.get('session_id')}.log", "w"), stderr=open(f"/tmp/mgrep-watch-command-{payload.get('session_id')}.log", "w"))
debug_log(f"Starting mgrep watch in cwd: {cwd}")
log_file = open(f"/tmp/mgrep-watch-command-{payload.get('session_id')}.log", "w")
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

session_id from the hook payload is interpolated into the log filename. If session_id contains path separators or .., this could write/overwrite unexpected paths under /tmp (or just produce invalid filenames). Consider sanitizing session_id to a safe character set or generating the filename via tempfile/a UUID, while still including the session id in the file contents for correlation.

Copilot uses AI. Check for mistakes.
Comment on lines +43 to +44
log_file = open(f"/tmp/mgrep-watch-command-{payload.get('session_id')}.log", "w")
process = subprocess.Popen(["mgrep", "watch"], cwd=cwd, preexec_fn=os.setsid, stdout=log_file, stderr=log_file)
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The log file handle is opened and then the script continues (and exits) without explicitly closing it. Although the OS will close it on process exit, using a context manager (or explicitly closing after Popen) avoids reliance on interpreter shutdown semantics and ensures the FD isn’t kept open if this script ever grows to do more work.

Copilot uses AI. Check for mistakes.
The SessionStart hook reads cwd from the hook payload but never passes
it to subprocess.Popen. The watcher inherits the hook runner's working
directory instead, typically ~/, and immediately hits the home-directory
guard.

Fix: add cwd=cwd to the Popen call so the watcher starts in the actual
project directory. Also removes the debug line that was dumping all
environment variables into a world-readable /tmp log file on every
session start.
@mostrub mostrub force-pushed the fix/mgrep-watch-cwd branch from df52195 to 0f22366 Compare March 14, 2026 19:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants