The run_long_command project (v1.0.2) provides a Gemini CLI extension that enables the agent to execute long-running shell commands in the background without blocking the agent's interaction loop. It utilizes tmux to notify the agent upon command completion.
- Execute arbitrary shell commands in the background.
- Return control to Gemini immediately.
- Notify Gemini via
tmux send-keyswhen the command completes. - robust error handling and reporting.
- Background Execution: Uses Node.js
spawnwithdetached: trueto run commands independent of the request cycle. - Tmux Integration: Safely wakes up the Gemini agent by injecting commands into the
gemini-clitmux session. - Context Awareness: Inherits the user's current working directory (CWD), allowing relative paths (e.g.,
.venv/bin/python) to work correctly. - Feedback: Provides immediate PID and CWD feedback, and asynchronous completion/failure notifications.
- Output Capture: Captures and reports the first 200 characters of stdout/stderr in the completion notification to assist with debugging.
- Agent Instructions: Includes a
GEMINI.mdfile to provide persistent context and instructions to the agent on how to use the tool and what to expect from its responses.
- Integration Test (30s sleep): Passed (Exit code 0)
- CWD & Env Var Test: Passed (Verified via verification.log)
- GitHub Install Verification: Passed (Exit code 0).
- Manual Verification (10s sleep): Passed (echo "hello" && sleep 10 && echo "world").
- Manual Verification (60s sleep): Passed (date && sleep 60 && date).
- Self-Test Verification (5s sleep): Passed (sleep 5 && echo "Test successful: background command completed"). Current test suite status:
- Pass Rate: 100% (7/7 tests passed)
- Pass Rate: 100% (6/6 tests passed)
- Coverage: Verified tool registration, tmux session checks, spawn logic, notification mechanism, and output capturing.
The extension uses tmux send-keys to inject a message directly into the gemini-cli session's active pane. This triggers the Gemini CLI to resume and process the notification as a new user message.
Yes, each call to run_long_command spawns a new independent process. You will receive notifications for each one as they complete.
The background processes will continue to run (since they are detached), but the notification will fail because it won't be able to find the gemini-cli session.
To help debug issues where commands exit unexpectedly (e.g., immediate exit due to quoting errors), the tool now captures a summary of the command's output and includes it in the completion message.
- Ensure you have Node.js (v18+) and
tmuxinstalled. - Clone the repository.
- Install dependencies:
npm install. - Build the extension:
npm run build. - Link to Gemini CLI:
gemini extensions link ..
Execute the test suite using:
npm testThis runs jest against run_long_command.test.ts.
To reproduce the environment:
- Initialize a new Gemini CLI environment.
- Install this extension.
- Start a tmux session named
gemini-cli. - Run
geminiinside that session. - Use the
run_long_commandtool.
@modelcontextprotocol/sdk: For MCP server implementation.zod: For input validation.jest&ts-jest: For testing.typescript: For the codebase.
- Challenge: Exit Code 127 in user projects.
- Detail: When the MCP server was started with a fixed
cwd, it couldn't find scripts or binaries relative to the user's project root. - Optimal Solution: Removing the
cwdfromgemini-extension.jsonensures the server inherits the CLI's working directory, which is exactly what's needed for local project commands.
- Detail: When the MCP server was started with a fixed
- Challenge: Asynchronous Notification.
- Detail: Standard tool calls must return a response immediately. We needed a way to "call back" later.
- Optimal Solution:
tmuxprovides a reliable IPC mechanism to "wake up" the CLI by simulating user input. This avoids the need for a persistent polling connection or complex webhooks.
- Challenge: Debugging Immediate Exits.
- Detail: Users were confused when commands returned immediately due to shell syntax errors (e.g. quoting).
- Optimal Solution: Capturing
stdoutandstderrand including a truncated summary in the notification allows users to see why a command finished, rather than just that it finished.
- Challenge: Implementation Details
The core logic resides in
run_long_command.ts. It useschild_process.spawnwith{ detached: true, stdio: ['ignore', 'pipe', 'pipe'] }. The server maintains a reference to the child process'scloseevent. When triggered, it executes a shell command:tmux send-keys -t gemini-cli "The background command ... finished. Output: [...]" C-m.