You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Feature Request: Support Long-Running Bash Processes in the Background (Async Execution)
Summary
Claude Code includes a feature that allows developers to run bash commands in the background without blocking the agent/chat interface. This enables long-running tasks (e.g., builds, servers, data processing) to continue running while the developer interacts with the AI for other tasks.
I propose adding similar functionality to OpenCode.
Motivation
Currently, when a bash command is run in OpenCode via the bash tool, the session is blocked until the command completes. This makes workflows involving:
Development servers
Continuous monitoring scripts
Large builds or data processing jobs
…slow and cumbersome, since you can’t continue using the AI assistant while those commands are still running.
Background execution would:
Keep the AI assistant responsive
Allow parallel workstreams
Reduce the need to switch out of OpenCode to manage long-running jobs in a separate shell
Reference: Claude Code’s Implementation
Claude Code provides Background Commands with a simple shortcut (Ctrl+b) to run bash processes asynchronously.
Reference: Claude Code FAQ – Background Commands
“Background commands allow you to run bash processes in the background using Ctrl+b, enabling Claude to continue working on other tasks while long-running processes execute. Great for development servers and monitoring.”
Proposed Design Ideas
Syntax Option: Add a background: true parameter to the bash tool.
Shortcut Key: Similar to Claude Code, provide a hotkey to run the currently typed bash command as a background job.
Job Management: Include a simple job list/kill command to view or stop background processes.
Output Handling: Stream or store background process logs for later inspection.
Workarounds Today
Using & or nohup inside the bash tool sometimes works, but behavior is inconsistent and often tied to the session lifecycle.
Running tasks outside of OpenCode in a multiplexer (tmux, screen)—but this defeats the purpose of integrated AI-assisted workflows.
Impact
Implementing this feature would make OpenCode far more usable for developers with mixed workloads and align it with modern AI coding assistants’ capabilities.
While these issues address different aspects of bash tool problems (hanging, getting stuck, output handling), none specifically address background/async execution like your feature request. Your proposal for background bash execution appears to be a new and distinct feature request.
idk if it helps but this is what i had created a while ago to handle running dev servers without the agent trying to start multiple, getting stuck by not realizing its an infinite process, and being able to look at logs as needed while we work.
this is just for "dev" mode but conceptually it could be used for other processes besides a dev server.
#!/bin/bash# Generic development process manager# Usage: ./dev.sh start "your dev command here"
PID_FILE=".dev.pid"
LOG_FILE=".dev.log"run() {
case"$1"in
start) shift; start "$@" ;;
stop) stop ;;
restart) shift; restart "$@" ;;
logs) shift; logs "$@" ;;
status) status ;;
*) echo"Usage: $0 {start|stop|restart|logs|status} [command]" ;;
esac
}
start() {
if [ $#-eq 0 ];thenecho"Usage: $0 start \"command to run\""return 1
fiif [ -f"$PID_FILE" ];thenifkill -0 $(cat "$PID_FILE")2>/dev/null;thenecho"Process already running (PID: $(cat $PID_FILE))"return 1
elseecho"Removing stale PID file"
rm "$PID_FILE"fifiecho"Starting: $*"echo"=== Started at $(date) ===">"$LOG_FILE""$@">>"$LOG_FILE"2>&1&
PID=$!echo$PID>"$PID_FILE"echo"Process started (PID: $PID)"# Give it a moment to start
sleep 2
# Verify it's still runningifkill -0 "$PID"2>/dev/null;thenecho"Process is running. Logs: ./dev.sh logs"elseecho"Process failed to start. Check logs: ./dev.sh logs"
rm "$PID_FILE"fi
}
stop() {
if [ -f"$PID_FILE" ];then
PID=$(cat "$PID_FILE")ifkill -0 "$PID"2>/dev/null;thenecho"Stopping process (PID: $PID)"kill"$PID"
rm "$PID_FILE"elseecho"Process not running"
rm "$PID_FILE"fielseecho"No PID file found"fi
}
restart() {
if [ $#-eq 0 ];thenecho"Usage: $0 restart \"command to run\""return 1
fi
stop
sleep 1
start "$@"
}
logs() {
if [ !-f"$LOG_FILE" ];thenecho"No log file found"return 1
ficase"${1:-tail}"in
tail|follow)
echo"Following logs (Ctrl+C to exit)..."
tail -f "$LOG_FILE"
;;
recent)
lines="${2:-50}"echo"Last $lines lines:"
tail -"$lines""$LOG_FILE"
;;
clear)
>"$LOG_FILE"echo"Log file cleared"
;;
all)
cat "$LOG_FILE"
;;
search)
if [ -z"$2" ];thenecho"Usage: $0 logs search <pattern>"echo"Example: $0 logs search ERROR"return 1
fiecho"Searching for: $2"
grep -n --color=auto "$2""$LOG_FILE"
;;
*)
echo"Usage: $0 logs [tail|recent|clear|all|search] [args]"echo" tail/follow - Follow logs in real-time (default)"echo" recent [N] - Show last N lines (default: 50)"echo" clear - Clear log file"echo" all - Show entire log"echo" search <pattern> - Search logs with grep"echo""echo"Examples:"echo"$0 logs recent 100 # Last 100 lines"echo"$0 logs search ERROR # Find error messages"echo"$0 logs search 'POST.*ws' # Find WebSocket POST requests"
;;
esac
}
status() {
if [ -f"$PID_FILE" ];then
PID=$(cat "$PID_FILE")ifkill -0 "$PID"2>/dev/null;thenecho"Process running (PID: $PID)"echo"Log file: $LOG_FILE"elseecho"Process not running (stale PID file)"fielseecho"Process not running"fi
}
run
tmux works really well for running commands in background
it can
start bash commands (sessions) in background with a name
list sessions
kill sessions
get last N logs for a session
that's all you need, with the added advantage that you can attach to these sessions yourself to send interactive commands yourself! something that Claude Code does not have
I’m planning a narrow PR for this: add an opt-in TUI keybind that submits normal prompts via the existing prompt_async path. No changes to sidebar/running-state UI, subagent visibility, or background-task orchestration. I’ll keep default behavior unchanged and make the keybind opt-in rather than remapping ctrl+b by default.
Basically runs the dev command through cmd /c with output redirected to a log file — no blocking, can read the output anytime. Works on Windows with PowerShell, covers the usual dev servers (npm, streamlit, go run, etc).
Not a native solution, but does the job while you wait for the official feature.
Posting a concrete implementation proposal for this issue. I have a working branch implementing background bash execution with a completion-notification mechanism; sharing the design here for maintainer review before opening a PR.
This proposal covers the programmatic side — the equivalent of CC's run_in_background: true flag on the bash tool. It does not cover a TUI keybind for mid-flight backgrounding of a running command; that's listed under "not in scope" below and would be a natural follow-up.
Proposed approach
Add an optional run_in_background: boolean parameter to the bash tool. When true, the spawn returns immediately with a task ID + output file path; the command runs detached, with output streamed to a file in opencode's existing truncation directory (TRUNCATION_DIR).
Add a bash_kill (or generic task_stop) tool that takes a task ID and terminates the running task. Reading partial/final output uses the existing Read tool against the output file path — no new bash_output tool needed.
On natural completion or stall-detection, attach a synthetic part to the next user message handed to the LLM (status, exit code, output file path). This reuses opencode's existing insertReminders / synthetic-text-part convention rather than introducing a new attachment vocabulary.
A one-shot stall watchdog detects commands blocked on stdin (heuristic on the output tail) and emits a notification with a kill-and-rerun-with-piped-input recovery instruction.
Internally: a BackgroundTask service forks workers into the instance scope (so they survive the bash tool returning), publishes Bus events on lifecycle transitions, and a notifier subscribes to those events and queues per-session notifications. Drain happens at the same loop seam as insertReminders in SessionPrompt.runLoop.
The design deliberately replaces CC's notified flag (which is set in two places — enqueueShellNotification and stopTask) with a structural single-chokepoint: kill() does not publish the Exited event, and the worker's catchCause swallows interrupt-causes. Result: the only path to a notification is a natural worker exit. No flag coordination across two call sites.
Open questions for maintainers
I'd value direction on these before opening a PR:
Naming / scope. Strictly a bash feature (BashTasks service, bash_kill tool), or generic background-task framework now (BackgroundTask service, task_stop tool with bash being the first kind)? Affects future extensibility for things like [feat] True Async/Background Sub-Agent Delegation #5887.
Notification envelope. CC wraps the completion notification in a <task-notification> XML structure; my current draft uses opencode's <system-reminder> envelope for consistency with insertReminders. Match CC's format for closer behavioral alignment, or keep the opencode convention?
Feature flag. Ship behind an experimental flag (e.g. OPENCODE_EXPERIMENTAL_BASH_BACKGROUND) until it has real-world soak time?
Kill-after-completion semantics. CC throws "not running" if you try to kill a finished task; I made it a no-op returning the existing status. Either is defensible — preference?
Not in scope (deferred from CC parity)
Calling these out so it's clear what's not being proposed for v1:
Auto-backgrounding of long-blocking commands (CC moves them to background after ~15s in assistant mode)
Mid-flight backgrounding via TUI keybind (the Ctrl+B referenced in this issue's title)
Per-agent notification routing (would scope by sessionID for now)
TUI-side fold of consecutive completion notifications
Notification priority levels
Each could be a follow-up if there's demand.
Status
Working branch committed locally; ready to open a PR once design questions have direction. Originally filed as #24885 before realizing this thread existed — closing that one and consolidating here.
I've been using the opencode-pty plugin to replace this feature. As expected, it also stopped working in recent opencode versions. Looking forward to having similar functionality built-in.
Activity
github-actions commentedon Aug 15, 2025
This issue might be a duplicate of existing issues. Please check:
While these issues address different aspects of bash tool problems (hanging, getting stuck, output handling), none specifically address background/async execution like your feature request. Your proposal for background bash execution appears to be a new and distinct feature request.
the-vampiire commentedon Aug 15, 2025
idk if it helps but this is what i had created a while ago to handle running dev servers without the agent trying to start multiple, getting stuck by not realizing its an infinite process, and being able to look at logs as needed while we work.
this is just for "dev" mode but conceptually it could be used for other processes besides a dev server.
ironbelly commentedon Oct 9, 2025
Agreed that tmux is a workaround but would be nice to have this built in to be on part with claude code
rekram1-node commentedon Oct 9, 2025
yeah makes sense
waylaidwanderer commentedon Nov 28, 2025
I built an MCP server for this, which is a solid alternative for now:
https://github.com/waylaidwanderer/background-process-mcp
remorses commentedon Dec 6, 2025
tmux works really well for running commands in background
it can
that's all you need, with the added advantage that you can attach to these sessions yourself to send interactive commands yourself! something that Claude Code does not have
you can give this document to your agent to let it know the commands to use https://github.com/remorses/AGENTS.md/blob/main/tmux.md
junmediatek commentedon Dec 18, 2025
hi @thdxr & @rekram1-node
Could you share the estimated completion time for this feature?
rekram1-node commentedon Dec 18, 2025
no official timeline I guess we would prolly roll out experimental version first and see how it does
junmediatek commentedon Dec 18, 2025
@rekram1-node So when will the experimental version be released?
shekohex commentedon Dec 19, 2025
you can also use
opencode-ptyplugin, it does exactly that and more: https://github.com/shekohex/opencode-ptyPlaneInABottle commentedon Feb 12, 2026
opencde-ptyhas a major limitation, you have to configure the permissions beforehand, it can't triggerask permissiontool of the opencode.shekohex commentedon Feb 12, 2026
That's a limitation of opencode plugins API rather than the plugin itself.
PlaneInABottle commentedon Feb 12, 2026
Oh yes, sorry for that, I have described wrongly.
We should either have support in the plugins API or native background bash execution.
Shane0xM commentedon Mar 16, 2026
I’m planning a narrow PR for this: add an opt-in TUI keybind that submits normal prompts via the existing
prompt_asyncpath. No changes to sidebar/running-state UI, subagent visibility, or background-task orchestration. I’ll keep default behavior unchanged and make the keybind opt-in rather than remappingctrl+bby default.workdocyeye commentedon Apr 25, 2026
Ran into this myself and threw together a skill that handles it:
https://github.com/workdocyeye/server-manager
Basically runs the dev command through cmd /c with output redirected to a log file — no blocking, can read the output anytime. Works on Windows with PowerShell, covers the usual dev servers (npm, streamlit, go run, etc).
Not a native solution, but does the job while you wait for the official feature.
abrar360 commentedon Apr 29, 2026
Posting a concrete implementation proposal for this issue. I have a working branch implementing background bash execution with a completion-notification mechanism; sharing the design here for maintainer review before opening a PR.
This proposal covers the programmatic side — the equivalent of CC's
run_in_background: trueflag on the bash tool. It does not cover a TUI keybind for mid-flight backgrounding of a running command; that's listed under "not in scope" below and would be a natural follow-up.Proposed approach
run_in_background: booleanparameter to the bash tool. When true, the spawn returns immediately with a task ID + output file path; the command runs detached, with output streamed to a file in opencode's existing truncation directory (TRUNCATION_DIR).bash_kill(or generictask_stop) tool that takes a task ID and terminates the running task. Reading partial/final output uses the existingReadtool against the output file path — no newbash_outputtool needed.insertReminders/ synthetic-text-part convention rather than introducing a new attachment vocabulary.Internally: a
BackgroundTaskservice forks workers into the instance scope (so they survive the bash tool returning), publishes Bus events on lifecycle transitions, and a notifier subscribes to those events and queues per-session notifications. Drain happens at the same loop seam asinsertRemindersinSessionPrompt.runLoop.The design deliberately replaces CC's
notifiedflag (which is set in two places —enqueueShellNotificationandstopTask) with a structural single-chokepoint:kill()does not publish theExitedevent, and the worker'scatchCauseswallows interrupt-causes. Result: the only path to a notification is a natural worker exit. No flag coordination across two call sites.Open questions for maintainers
I'd value direction on these before opening a PR:
BashTasksservice,bash_killtool), or generic background-task framework now (BackgroundTaskservice,task_stoptool with bash being the first kind)? Affects future extensibility for things like [feat] True Async/Background Sub-Agent Delegation #5887.<task-notification>XML structure; my current draft uses opencode's<system-reminder>envelope for consistency withinsertReminders. Match CC's format for closer behavioral alignment, or keep the opencode convention?OPENCODE_EXPERIMENTAL_BASH_BACKGROUND) until it has real-world soak time?Not in scope (deferred from CC parity)
Calling these out so it's clear what's not being proposed for v1:
sessionIDfor now)Each could be a follow-up if there's demand.
Status
Working branch committed locally; ready to open a PR once design questions have direction. Originally filed as #24885 before realizing this thread existed — closing that one and consolidating here.
pan17 commentedon Jun 10, 2026
I've been using the opencode-pty plugin to replace this feature. As expected, it also stopped working in recent opencode versions. Looking forward to having similar functionality built-in.
ImBIOS commentedon Jun 15, 2026
Isn't it already shipped? If yes, this issue should be closed or automatically closed if 90 days without further activities.
Ploppy3 commentedon Jun 23, 2026
No this is for agents only, and I think it's currently behind an experimental flag.
github-actions commentedon Aug 23, 2026
To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.