Bug Description
When OpenSpace CLI is run as a launchd service (macOS background daemon), it enters an infinite EOFError loop because the interactive-mode input() call has no TTY. This causes:
- Massive log growth: 100GB+ of EOFError messages within hours
- 100% CPU usage: Single Python process spins endlessly on
input()
- launchd restart loop: Service keeps respawning and failing
Environment
- macOS (Apple Silicon, ARM64)
- OpenSpace installed via Homebrew:
brew install hkusd/opspace/opspace
- Launched via
launchd plist with KeepAlive: true
Root Cause
The openspace CLI defaults to interactive mode when run without arguments:
# openspace/__main__.py (simplified)
query = input(f"\n{prompt}").strip() # blocks waiting for stdin
When launched by launchd, there is no TTY/stdin — input() immediately returns EOFError. The error is caught and logged, then the process exits. Because KeepAlive: true, launchd restarts it immediately, creating an infinite restart loop.
Reproduction
Minimal reproduction (no launchd needed)
# This simulates what launchd does — run openspace with no stdin
printf '' | /opt/homebrew/bin/openspace
Expected: Process should fail fast with a clear error message
Actual: Infinite EOFError loop with massive log output
Full launchd reproduction
- Create a plist at
~/Library/LaunchAgents/com.example.openspace.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.example.openspace</string>
<key>ProgramArguments</key>
<array>
<string>/opt/homebrew/bin/openspace</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>
- Load it:
launchctl bootstrap gui/501 ~/Library/LaunchAgents/com.example.openspace.plist
- Watch the log grow:
tail -f ~/Library/Logs/OpenSpace/*.log # or wherever logs are written
Suggested Fixes
Option 1: Detect non-TTY and exit fast with a clear error
In openspace/__main__.py, check if stdin is a TTY at startup:
import sys
import os
if not sys.stdin.isatty():
print("ERROR: openspace interactive mode requires a terminal."
"For background/service use, run: openspace communication run",
file=sys.stderr)
sys.exit(1)
Option 2: Add explicit daemon/service mode
If openspace communication run is the intended production mode, add a prominent note in README and --help output.
Additional Issue: Invalid FEISHU_GROUP_POLICY value
When running openspace communication run, an invalid environment variable value causes a validation error:
FEISHU_GROUP_POLICY=open is set in the environment
- The config schema only allows:
'disabled' | 'mention_only' | 'reply_or_mention' | 'all'
- This causes pydantic ValidationError on startup
Quick fix: Set FEISHU_GROUP_POLICY=all (or any valid value) in the launchd environment.
Impact
- For macOS users wanting to run OpenSpace as a background service (common for MCP integration), the current CLI is unusable with launchd.
- The massive log growth can fill up disk space quickly.
- The
KeepAlive restart loop means the service never stabilizes.
Bug Description
When OpenSpace CLI is run as a launchd service (macOS background daemon), it enters an infinite EOFError loop because the interactive-mode
input()call has no TTY. This causes:input()Environment
brew install hkusd/opspace/opspacelaunchdplist withKeepAlive: trueRoot Cause
The
openspaceCLI defaults to interactive mode when run without arguments:When launched by launchd, there is no TTY/stdin —
input()immediately returns EOFError. The error is caught and logged, then the process exits. BecauseKeepAlive: true, launchd restarts it immediately, creating an infinite restart loop.Reproduction
Minimal reproduction (no launchd needed)
Expected: Process should fail fast with a clear error message
Actual: Infinite EOFError loop with massive log output
Full launchd reproduction
~/Library/LaunchAgents/com.example.openspace.plist:launchctl bootstrap gui/501 ~/Library/LaunchAgents/com.example.openspace.plistSuggested Fixes
Option 1: Detect non-TTY and exit fast with a clear error
In
openspace/__main__.py, check if stdin is a TTY at startup:Option 2: Add explicit daemon/service mode
If
openspace communication runis the intended production mode, add a prominent note in README and--helpoutput.Additional Issue: Invalid
FEISHU_GROUP_POLICYvalueWhen running
openspace communication run, an invalid environment variable value causes a validation error:FEISHU_GROUP_POLICY=openis set in the environment'disabled' | 'mention_only' | 'reply_or_mention' | 'all'Quick fix: Set
FEISHU_GROUP_POLICY=all(or any valid value) in the launchd environment.Impact
KeepAliverestart loop means the service never stabilizes.