#430
fix: kill Claude subprocess on stop/exit to prevent orphaned agents
Summary
ClaudeCodeBackendnow captures child PIDs after connecting and kills
them explicitly indisconnect()and viaatexit, so theclaudeCLI
subprocess is cleaned up on any exit pathtui.pyon_unmountnow callscontroller.stop()so the controller's
disconnect path actually runs when the TUI closesmain.pyinstalls a SIGTERM handler sodocker stoptriggerssys.exit()
and thereforeatexitcleanup
Root cause
When the Python controller exited (TUI closed, Ctrl+C, or docker stop),
the claude CLI subprocess it spawned was orphaned — re-parented to the
container's bash (PID 1) — and kept running indefinitely. The controller's
stop() method only set an in-memory flag, which does nothing if the Python
process is already gone.
Test plan
- All existing tests pass (
make test) - Start a session, quit via Ctrl+Q — verify no
claudeprocess remains (ps aux) - Start a session, run
docker stop pentestgpt— verify process is gone on restart - Start a session, kill the Python process directly — verify subprocess is cleaned up via
atexit
Activity
4gemini-code-assist[bot]reviewed7mo ago
Code Review
This pull request effectively addresses the issue of orphaned claude subprocesses by implementing cleanup logic on exit, stop, and disconnect paths. The use of atexit, a SIGTERM handler for Docker, and explicit cleanup in the TUI unmount process are all solid improvements. My main feedback is a suggestion to refactor some duplicated code in pentestgpt/core/backend.py to improve maintainability.
Summary of Changes
Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request addresses a critical issue where
claudeCLI subprocesses were being orphaned and left running indefinitely after the main Python controller process exited. The changes ensure that these subprocesses are properly terminated across various exit paths, including TUI closure, Ctrl+C, anddocker stop, by implementing explicit child process tracking and cleanup mechanisms.Highlights
ClaudeCodeBackendnow actively tracks and terminates its childclaudeCLI subprocesses upon disconnection or application exit, preventing orphaned processes.on_unmountmethod was updated to ensure the controller's disconnect logic, including subprocess termination, is properly triggered when the TUI closes.main.pyto gracefully shut down the application and triggeratexitcleanup when adocker stopcommand is issued.🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.
Changelog
atexit,os, andsignalimports for process management._get_child_pidsfunction to identify direct child processes on Linux._subprocess_pidsattribute toClaudeCodeBackendto track spawned subprocesses._kill_subprocessesmethod to terminate all tracked PIDs._kill_subprocesseswithatexitfor automatic cleanup upon program exit.connectmethod to capture and track new child PIDs after establishing a connection._kill_subprocesseswithin thedisconnectmethod to ensure termination on explicit disconnection.resumemethod to also capture and track new child PIDs.signalmodule.main()function to ensuresys.exit()is called, which triggersatexitcleanup, when the process receives a SIGTERM signal (e.g., fromdocker stop).on_unmountmethod to callself._controller.stop(), ensuring proper disconnection and subprocess termination when the TUI application closes._agent_thread.join()timeout from 2.0 to 5.0 seconds to allow more time for the agent thread to finish gracefully.Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point by creating a comment using either
/gemini <command>or@gemini-code-assist <command>. Below is a summary of the supported commands on the current page./gemini review/gemini summary/gemini helpCustomization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a
.gemini/folder in the base of the repository. Detailed instructions can be found here.Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with :thumbsup: and :thumbsdown: on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩