fix: pass project cwd to mgrep watch subprocess#137
fix: pass project cwd to mgrep watch subprocess#137mostrub wants to merge 1 commit intomixedbread-ai:mainfrom
Conversation
There was a problem hiding this comment.
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
cwdfrom the hook payload into thesubprocess.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.
| 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) |
There was a problem hiding this comment.
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.
|
|
||
| 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") |
There was a problem hiding this comment.
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.
| 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) |
There was a problem hiding this comment.
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.
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.
df52195 to
0f22366
Compare
Problem
When Claude Code starts a session, the SessionStart hook launches
mgrep watchas a background process. The hook readscwdfrom the hook payload — the project directory Claude was opened in — but never passes it tosubprocess.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 tocwd, but that value is never used. Thesubprocess.Popencall has nocwdargument, so Python falls back toos.getcwd()at the time the hook runs — not the project directory.Fix
Pass
cwd=cwdtosubprocess.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/tmpon 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 watchand removes overly-verbose/sensitive debug logging.Overview
Fixes
mgrep watchstartup by launching the watcher subprocess withcwdfrom 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.