| name | openconductor-tester |
| description | Run and test OpenConductor interactively using tmux. Use when you need to:
- Test a fix by running the app with real agents
- Debug heuristic detection issues (spinner, permission, question dialogs)
- Verify scrollback behavior
- Check Telegram notification flow
- Reproduce a user-reported bug
Triggers on: "test this", "run the app", "try it", "verify the fix", "check if it works", "reproduce the bug", "manual test"
|
OpenConductor Interactive Testing
Run OpenConductor in tmux to test changes with real agents.
Quick Start
Build and Run
go build -o /tmp/oc-test ./cmd/openconductor
tmux new-session -d -s oc-test -x 200 -y 50 "/tmp/oc-test --debug"
OC_CONFIG_PATH=/tmp/oc-test-config.yaml \
OC_LOG_DIR=/tmp/oc-test-logs \
OC_STATE_PATH=/tmp/oc-test-state.json \
tmux new-session -d -s oc-test -x 200 -y 50 "/tmp/oc-test --debug"
Read Terminal State
tmux capture-pane -t oc-test -p
tmux capture-pane -t oc-test -p -S 0 -E 5
tmux capture-pane -t oc-test -p -S -5
Take Visual Screenshots
Render the terminal to a PNG image that looks like the user's screen:
BODY=$(tmux capture-pane -e -p -t oc-test | aha --no-header)
cat > /tmp/oc-screen.html << EOF
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<style>
body {
background: #1a1a2e; color: #c8c8c8;
font-family: "Menlo", "Monaco", "Courier New", "DejaVu Sans Mono", monospace;
font-size: 13px; line-height: 1.35;
padding: 12px 16px; margin: 0; white-space: pre; overflow-x: auto;
}
</style></head><body>
$BODY
</body></html>
EOF
This gives you a pixel-accurate rendering with dark background, monospace font,
correct Unicode box-drawing characters, and ANSI colors — matching what the user
sees in their native terminal.
Send Mouse Events
tmux send-keys -t oc-test -l $'\x1b[<64;60;20M'
tmux send-keys -t oc-test -l $'\x1b[<65;60;20M'
for i in $(seq 1 10); do
tmux send-keys -t oc-test -l $'\x1b[<64;60;20M'
sleep 0.05
done
Send Keystrokes
tmux send-keys -t oc-test "fix the login bug" Enter
tmux send-keys -t oc-test Enter
tmux send-keys -t oc-test Escape
tmux send-keys -t oc-test C-c
tmux send-keys -t oc-test C-s
tmux send-keys -t oc-test C-j
tmux send-keys -t oc-test C-k
tmux send-keys -t oc-test Tab
tmux send-keys -t oc-test -l $'\x1b[A'
tmux send-keys -t oc-test -l $'\x1b[B'
tmux send-keys -t oc-test -l $'\x1b[C'
tmux send-keys -t oc-test -l $'\x1b[D'
Read Logs
tail -f /tmp/oc-test-logs/openconductor.log
grep 'attention check' /tmp/oc-test-logs/openconductor.log | tail -5
grep 'heuristic.*claude' /tmp/oc-test-logs/openconductor.log | tail -5
grep 'auto-approve' /tmp/oc-test-logs/openconductor.log | tail -5
grep 'auto-confirm' /tmp/oc-test-logs/openconductor.log | tail -5
grep 'telegram' /tmp/oc-test-logs/openconductor.log | tail -5
grep 'no signal' /tmp/oc-test-logs/openconductor.log | tail -5
Cleanup
tmux kill-session -t oc-test
rm -f /tmp/oc-test
Testing Workflows
Test Spinner Detection (Claude Code)
- Start the app with a Claude Code project
- Send a prompt:
tmux send-keys -t oc-test "What is 2+2?" Enter
- Check logs:
grep 'claude-code spinner detected' /tmp/oc-test-logs/openconductor.log | tail -3
- Check screen:
tmux capture-pane -t oc-test -p | grep -i 'working\|spinner'
- Expected: log shows "isWorking: true", sidebar shows "working" badge
Test Permission Detection (OpenCode)
- Start with an OpenCode project
- Send a prompt that triggers file access outside the repo
- Check logs:
grep 'permission' /tmp/oc-test-logs/openconductor.log | tail -5
- Check screen:
tmux capture-pane -t oc-test -p | grep -i 'permission required\|allow once'
- Expected: sidebar shows "permission" badge, log shows NeedsPermission
Test Auto-Approve
- Verify auto-approve is configured (LLM section in config)
- Trigger a permission dialog
- Check logs:
grep 'auto-approve' /tmp/oc-test-logs/openconductor.log | tail -5
- Expected: log shows "auto-approve: sending keystroke" then "auto-confirm: confirmed always-allow dialog"
Test Scrollback (Claude Code)
- Send a prompt that produces long output:
tmux send-keys -t oc-test "Run go test ./..." Enter
- Wait for completion
- Scroll up:
tmux send-keys -t oc-test -l $'\x1b[5~' (PageUp — only works if not alt-screen)
- Check screen:
tmux capture-pane -t oc-test -p
- Expected: scrollback shows earlier output without gaps
Test Question Series (OpenCode)
- Send a prompt designed to trigger AskUser:
tmux send-keys -t oc-test "Ask me which framework to use before starting" Enter
- Check logs:
grep 'NeedsAnswer\|question' /tmp/oc-test-logs/openconductor.log | tail -5
- Check screen:
tmux capture-pane -t oc-test -p | grep -i 'select\|dismiss'
- Expected: question dialog detected, state shows "asking"
Config File Format
For E2E testing, create a minimal config:
projects:
- name: TestProject
repo: /path/to/test/repo
agent: claude-code
llm:
provider: anthropic
model: claude-sonnet-4-20250514
api_key: ANTHROPIC_API_KEY
telegram:
enabled: false
Key Log Messages
| Log Message | Meaning |
|---|
"attention check" | Periodic check with hasEvent, isWorking fields |
"attention state transition" | State changed — from and to fields |
"heuristic: claude-code spinner detected" | Spinner found |
"heuristic: claude-code no signal" | Nothing detected — check lines field |
"heuristic: opencode scan result" | OpenCode detection flags |
"auto-approve: sending keystroke" | Auto-approve fired |
"auto-approve: stuck, falling through" | Auto-approve failed too many times |
"auto-confirm: confirmed always-allow dialog" | Second-stage confirm auto-dismissed |
"auto-confirm: submitted question series confirm tab" | Question confirm auto-submitted |
"telegram: sending permission keystroke" | Telegram button callback processed |
"session: PTY write failed" | Write to PTY returned error |
Architecture Reference
- Session:
internal/session/session.go — PTY + vt10x wrapper
- Agent adapters:
internal/agent/claude.go, internal/agent/opencode.go
- Attention loop:
internal/tui/app.go:checkAttention() — runs every 2s
- Scrollback:
internal/tui/app.go:checkScrollback() — runs every 100ms
- Telegram handler:
internal/telegram/handler.go:HandleCallback()
- Auto-approve:
internal/tui/app.go — runs before state transition for NeedsPermission
- CSI filter:
internal/agent/claude.go:csiFilter — strips kitty keyboard sequences