personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(runner): redirect supervised task stdin to DEVNULL

When the supervisor is launched on a controlling tty (tmux pane), every supervised task inherited that tty as stdin. Tasks that read stdin, including ffmpeg via prepare_audio_segments, ran in a background process group, so the first read raised SIGTTIN and stopped the whole process group; supervisor managed.wait() did not distinguish stopped from running, so hourly sync:plaud runs only surfaced the hang when the 1800s max_runtime watchdog killed them, which has been happening since 2026-05-05.

Pass stdin=subprocess.DEVNULL from ManagedProcess.spawn so every supervised process gets null stdin regardless of how the supervisor was launched, and add -nostdin to the two ffmpeg invocations in think/importers/audio.py as defense in depth.

A future hardening pass should detect WIFSTOPPED in think/supervisor.py::enforce_deadlines, or via os.waitpid(..., os.WUNTRACED), so a buried stop is surfaced immediately instead of at the 1800s cap.

Co-Authored-By: Codex <codex@openai.com>

+33
+29
tests/test_runner.py
··· 311 311 listener.stop() 312 312 313 313 314 + def test_spawned_process_sees_eof_on_stdin(journal_path, mock_callosum): 315 + r_fd, w_fd = os.pipe() 316 + saved_stdin = os.dup(0) 317 + 318 + try: 319 + os.write(w_fd, b"smuggled\n") 320 + os.close(w_fd) 321 + w_fd = -1 322 + os.dup2(r_fd, 0) 323 + os.close(r_fd) 324 + r_fd = -1 325 + 326 + managed = ManagedProcess.spawn(["sh", "-c", "read x; echo got=$x"]) 327 + exit_code = managed.wait() 328 + managed.cleanup() 329 + 330 + content = managed.log_writer.path.read_text() 331 + assert exit_code == 0 332 + assert "got=" in content 333 + assert "got=smuggled" not in content 334 + finally: 335 + os.dup2(saved_stdin, 0) 336 + os.close(saved_stdin) 337 + if r_fd != -1: 338 + os.close(r_fd) 339 + if w_fd != -1: 340 + os.close(w_fd) 341 + 342 + 314 343 def test_process_creates_health_log(journal_path, mock_callosum): 315 344 """Test that process output is logged to health directory.""" 316 345 managed = ManagedProcess.spawn(["echo", "logged output"])
+1
tests/test_supervisor.py
··· 34 34 35 35 def fake_popen( 36 36 cmd, 37 + stdin=None, 37 38 stdout=None, 38 39 stderr=None, 39 40 text=False,
+2
think/importers/audio.py
··· 36 36 """ 37 37 cmd = [ 38 38 "ffmpeg", 39 + "-nostdin", 39 40 "-ss", 40 41 str(start_seconds), 41 42 "-i", ··· 55 56 logger.debug(f"Stream copy failed, re-encoding: {output_path}") 56 57 cmd_reencode = [ 57 58 "ffmpeg", 59 + "-nostdin", 58 60 "-ss", 59 61 str(start_seconds), 60 62 "-i",
+1
think/runner.py
··· 286 286 try: 287 287 proc = subprocess.Popen( 288 288 cmd, 289 + stdin=subprocess.DEVNULL, 289 290 stdout=subprocess.PIPE, 290 291 stderr=subprocess.PIPE, 291 292 text=True,