This asciinema recording demonstrates a critical bug in the original @zenobius/opencode-background plugin for OpenCode.
The session starts a simple Python echo server in the background using createBackgroundProcess, which succeeds and returns a task ID.
Immediately after, calling getBackgroundProcess to check the task status fails with “Tool execution aborted”.
The root cause is a Pydantic validation error (invalid_union / invalid_type) from malformed streaming output handling (expected string but received object, missing part/delta fields).
This breaks reliable monitoring of background tasks in the original package.
Recommendation: Switch to the actively maintained fork @mbanucu/opencode-background, which fixes this issue by publishing the latest version as npm package.
OpenCode session transcript
Testing echo_server manually with curl in background
Session ID: ses_46fb37130ffervLyJrmkYNeLN0 Created: 1/5/2026, 11:34:55 PM Updated: 1/5/2026, 11:35:03 PM
User
test the echo_server manually by running it in background and sending some data with curl commands
Assistant (Build · grok-code · 3.7s)
Thinking:
The user wants to test the echo_server manually by running it in background and sending some data with curl commands.
Tool: glob
**Input:**
```json
{
"pattern": "*.py"
}
```
**Output:**
```
/home/michi/dev/opencode-background/demo/Running background processes/python server/echo_server.py
```
Assistant (Build · grok-code · 1.4s)
Thinking:
Found echo_server.py. Now, read it to understand how to run it.
Tool: read
**Input:**
```json
{
"filePath": "/home/michi/dev/opencode-background/demo/Running background processes/python server/echo_server.py"
}
```
**Output:**
```
<file>
00001| import http.server
00002| import socketserver
00003| from datetime import datetime
00004| import json
00005|
00006| class EchoHandler(http.server.BaseHTTPRequestHandler):
00007| def do_POST(self):
00008| content_length = int(self.headers['Content-Length'])
00009| post_data = self.rfile.read(content_length)
00010| msg = post_data.decode('utf-8')
00011| print(msg, flush=True)
00012| now = datetime.now().astimezone().isoformat(timespec='seconds')
00013| try:
00014| server_ip, server_port = self.connection.getsockname()[:2]
00015| server_info = f'{server_ip}:{server_port}'
00016| except Exception:
00017| server_info = 'unknown'
00018| log_object = {
00019| 'timestamp': now,
00020| 'message': msg,
00021| 'client_ip': self.client_address[0],
00022| 'server': server_info
00023| }
00024| log_line = json.dumps(log_object, indent=2)
00025| with open('echo_server.log', 'a') as f:
00026| f.write(log_line + '\n')
00027| self.send_response(200)
00028| self.send_header('Content-Type', 'application/json')
00029| self.end_headers()
00030| self.wfile.write(log_line.encode('utf-8'))
00031|
00032| if __name__ == '__main__':
00033| with socketserver.TCPServer(("", 0), EchoHandler) as httpd:
00034| port = httpd.server_address[1]
00035| print(f"Server running on port {port}", flush=True)
00036| httpd.serve_forever()
(End of file - total 36 lines)
</file>
```
Assistant (Build · grok-code · 3.2s)
Thinking:
The echo_server.py is an HTTP server that listens on a random port (port 0 means assign any available port). It handles POST requests, echoes the message back, and logs it to echo_server.log.
Examining echo_server.py
- The echo_server.py is an HTTP server that operates on a dynamically assigned port, using port 0 to let the system choose an available one.
Tool: createBackgroundProcess
**Input:**
```json
{
"command": "python3 echo_server.py",
"name": "echo_server"
}
```
**Output:**
```
task-0yg582k
```
Assistant (Build · grok-code · 1.2s)
Thinking:
The task ID is task-0yg582k.
Tool: getBackgroundProcess
**Input:**
```json
{
"taskId": "task-0yg582k"
}
```
**Error:**
```
Tool execution aborted
```