OpenCode ACP Skill v2.0
Control OpenCode directly via the Agent Client Protocol (ACP) with automatic recovery and stuck detection.
🆕 What's New in v2.0
| Feature | Description |
|---|
| Auto-retry | Automatically retries on failure (max 3 attempts) |
| Stuck detection |
Detects when OpenCode is not responding |
|
Lock cleanup | Automatically removes stale lock files |
|
Adaptive polling | Polls faster at start, slower when stable |
|
Health checks | Periodic checks that OpenCode is alive |
|
Configurable timeouts | Shorter timeouts with escalation |
|
Session recovery | Can recover from crashes mid-task |
Quick Reference
| Action | How |
|---|
| Start OpenCode | INLINECODE0 |
| Send message |
process.write(sessionId, data: "<json-rpc>\n") |
| Read response |
process.poll(sessionId) - adaptive polling |
| Health check |
process.poll(sessionId, timeout: 5000) - only when no output >60s |
| Stop OpenCode |
process.kill(sessionId) + cleanup locks |
| Clean locks |
exec(command: "rm -f ~/.openclaw/agents/*/sessions/*.lock") |
| List sessions |
exec(command: "opencode session list", workdir: "...") |
| Resume session | List sessions →
session/load |
🚀 Quick Start (Simple)
For most use cases, use this simple workflow:
CODEBLOCK0
📁 Skill Files
| File | Purpose |
|---|
| INLINECODE8 | This file - main documentation |
| INLINECODE9 |
Default configuration (copy to
config.json to customize) |
|
templates.md | Prompt templates for common tasks |
⚙️ Configuration
Option 1: Use defaults
All defaults are built-in. No config file needed.
Option 2: Customize
Copy
config.default.json to
config.json in the same folder and modify:
CODEBLOCK1
Config structure:
{
"timeouts": { "initialize": 10000, "prompt": {...} },
"retry": { "maxAttempts": 3, "initialDelay": 2000 },
"polling": { "initial": 1000, "active": 2000 },
"healthCheck": { "noOutputThreshold": 60000 },
"recovery": { "autoRecover": true },
"mcpServers": { "default": [], "supabase": ["supabase"] }
}
Timeouts (Configurable)
| Operation | Default | Max | When to increase |
|---|
| Initialize | 10s | 30s | Slow machine |
| Session new |
10s | 30s | Large project |
| Prompt (simple) | 60s | 120s | Complex query |
| Prompt (complex) | 120s | 300s | Refactor, code gen |
| Health check | 5s | 10s | Network issues |
Retry Configuration
| Setting | Default | Description |
|---|
| Max retries | 3 | How many times to retry on failure |
| Retry delay |
2s | Initial delay between retries |
| Backoff multiplier | 2 | Delay doubles each retry |
| Max retry delay | 10s | Maximum delay between retries |
Adaptive Polling
| Phase | Interval | Duration |
|---|
| Initial | 1s | First 10s |
| Active |
2s | 10s - 60s |
| Stable | 3s | 60s - 120s |
| Slow | 5s | 120s+ |
🔄 Automatic Recovery
Stuck Detection
OpenCode is considered "stuck" when:
- - No response after 2x expected timeout
- Health check fails 3 times in a row
- Process is still running but not responding to polls
Recovery Steps
When stuck is detected:
CODEBLOCK3
Lock Cleanup
Lock files can become stale when OpenCode crashes. Always clean up:
CODEBLOCK4
📋 Step-by-Step Workflow
Step 1: Pre-flight Check
Before starting, verify environment:
CODEBLOCK5
Step 2: Start OpenCode
CODEBLOCK6
Step 3: Initialize (with retry)
CODEBLOCK7
Retry logic:
CODEBLOCK8
Step 4: Create Session (with retry)
CODEBLOCK9
Same retry logic as initialize.
Step 5: Send Prompts (with adaptive polling)
CODEBLOCK10
Adaptive polling:
CODEBLOCK11
Step 6: Health Check (Smart - No Token Waste)
⚠️ Don't poll constantly - wastes tokens!
Only do health checks when:
- 1. No output for >60s (possible stuck)
- Approaching timeout (verify before declaring stuck)
- Something looks wrong (partial errors, etc.)
DO NOT health check when:
- - OpenCode is actively generating output
- <60s since last output
CODEBLOCK12
Step 7: Cleanup
When done, always clean up:
CODEBLOCK13
🛠️ Error Handling
Common Errors and Solutions
| Error | Detection | Solution |
|---|
| Process died | INLINECODE14 returns "No active session" | Restart OpenCode, resume session |
| Stuck (no response) |
No response after 2x timeout | Cancel, kill, clean locks, restart |
| Lock file exists |
.lock file from previous run | Remove stale locks (>30min old) |
| JSON parse error | Malformed response | Skip line, continue polling |
| Timeout |
elapsed >= maxWait | Check if stuck, retry or escalate |
| Rate limited | HTTP 429 from OpenCode | Exponential backoff, max 10s |
Recovery Function
CODEBLOCK14
🔌 Session Management
Multiple Sessions
OpenCode supports multiple concurrent sessions. Track them:
CODEBLOCK15
Session Recovery
If OpenCode crashes mid-task:
CODEBLOCK16
📊 Monitoring
Health Metrics
Track these to detect problems early:
| Metric | Healthy | Warning | Critical |
|---|
| Response time | <5s | 5-15s | >15s |
| Polls without data |
<10 | 10-30 | >30 |
| Lock file age | <5min | 5-30min | >30min |
| Consecutive errors | 0 | 1-2 | ≥3 |
Logging
Log important events for debugging:
CODEBLOCK17
🎯 Best Practices
DO:
- - ✅ Always clean up locks before starting
- ✅ Use adaptive polling (saves tokens)
- ✅ Implement retry logic (makes it robust)
- ✅ Track session state (enables recovery)
- ✅ Set appropriate timeouts per task type
- ✅ Kill and restart if stuck >2x timeout
DON'T:
- - ❌ Poll every 2s for 5 minutes (wastes tokens)
- ❌ Health check every 30s when output is active (wastes tokens)
- ❌ Ignore stuck processes (blocks future work)
- ❌ Leave lock files after crashes
- ❌ Use same timeout for all operations
- ❌ Skip health checks when no output for >60s (misses stuck detection)
📝 Example: Robust Implementation
CODEBLOCK18
🔧 Utility Functions
cleanupStaleLocks()
CODEBLOCK19
isStuck(sessionId)
CODEBLOCK20
getAdaptiveInterval(elapsedMs)
CODEBLOCK21
📝 Prompt Templates
📝 Prompt Templates
See templates.md for pre-built prompts for common tasks:
| Category | Templates |
|---|
| Refactoring | Extract function, convert to TS, improve readability |
| Features |
Add endpoint, add component, implement feature |
|
Bug fixes | Debug and fix, TypeScript errors |
|
Testing | Unit tests, integration tests |
|
Documentation | JSDoc/TSDoc, README updates |
|
Database | Migrations, RLS policies |
|
Performance | Query optimization, bundle size |
|
Security | Security audit |
Usage:
1. Read templates.md
2. Find appropriate template
3. Replace placeholders with your specifics
4. Send as prompt
📊 Metrics & Monitoring
Track these for health monitoring:
| Metric | How to track | Healthy | Warning | Critical |
|---|
| Avg response time | Log timestamps | <30s | 30-60s | >60s |
| Polls per request |
Counter | <20 | 20-50 | >50 |
|
Retry rate | Retries/requests | <5% | 5-15% | >15% |
|
Stuck rate | Stucks/sessions | <1% | 1-5% | >5% |
|
Success rate | Completed/started | >95% | 85-95% | <85% |
Logging format:
CODEBLOCK23
Log levels:
- -
ERROR - Failures, exceptions, stuck detected - INLINECODE19 - Retries, slow responses, near-timeout
- INLINECODE20 - Start, complete, cleanup
- INLINECODE21 - Detailed output, updates received
📦 Skill Files
CODEBLOCK24
🚀 Helper Script (Recommended)
Use opencode-session.sh for automatic workflow:
CODEBLOCK25
Script options:
| Option | Description |
|---|
| INLINECODE23 | Project directory (required) |
| INLINECODE24 |
Prompt to send (required if no template) |
|
--template NAME | Use template from templates.md |
|
--timeout TYPE | simple (60s) \| medium (120s) \| complex (300s) |
|
--mcp SERVERS | MCP servers as JSON array |
|
--verbose | Enable debug logging |
|
--dry-run | Show JSON-RPC without executing |
|
--help | Show help |
What the script provides:
The script outputs a complete workflow with:
- - ✅ Pre-flight cleanup
- ✅ Exact JSON-RPC messages to send
- ✅ Retry logic hints
- ✅ Adaptive polling intervals
- ✅ Health check thresholds
- ✅ Cleanup commands
CYPHER should:
- 1. Execute the script with options
- Parse the output
- Execute the steps in order
- Log metrics at the end
Version 2.2.0 - Released 2026-03-05
Changes: Added opencode-session.sh helper script
OpenCode ACP 技能 v2.0
通过自动恢复和卡死检测,直接经由代理客户端协议(ACP)控制 OpenCode。
🆕 v2.0 新特性
| 特性 | 描述 |
|---|
| 自动重试 | 失败时自动重试(最多 3 次) |
| 卡死检测 |
检测 OpenCode 无响应的情况 |
|
锁清理 | 自动移除过期的锁文件 |
|
自适应轮询 | 启动时轮询更快,稳定时轮询更慢 |
|
健康检查 | 定期检查 OpenCode 是否存活 |
|
可配置超时 | 较短的超时时间,并带有升级机制 |
|
会话恢复 | 可在任务中途从崩溃中恢复 |
快速参考
| 操作 | 方法 |
|---|
| 启动 OpenCode | exec(command: opencode acp --cwd /path, background: true) |
| 发送消息 |
process.write(sessionId, data:
\n) |
| 读取响应 | process.poll(sessionId) - 自适应轮询 |
| 健康检查 | process.poll(sessionId, timeout: 5000) - 仅在无输出超过 60 秒时 |
| 停止 OpenCode | process.kill(sessionId) + 清理锁 |
| 清理锁 | exec(command: rm -f ~/.openclaw/agents//sessions/.lock) |
| 列出会话 | exec(command: opencode session list, workdir: ...) |
| 恢复会话 | 列出会话 → session/load |
🚀 快速入门(简单版)
对于大多数用例,请使用此简单工作流:
- 1. exec(command: opencode acp --cwd /path/to/project, background: true)
-> sessionId: bg_42
- 2. process.write(sessionId: bg42, data: initializejson + \n)
process.poll(sessionId: bg_42, timeout: 10000)
- 3. process.write(sessionId: bg42, data: sessionnew_json + \n)
process.poll(sessionId: bg_42, timeout: 10000)
-> opencodeSessionId: sess_xyz
- 4. process.write(sessionId: bg42, data: promptjson + \n)
adaptivePoll(sessionId: bg_42, maxWaitMs: 120000)
- 5. 完成后:process.kill(sessionId: bg_42)
cleanupLocks()
📁 技能文件
| 文件 | 用途 |
|---|
| SKILL.md | 本文件 - 主要文档 |
| config.default.json |
默认配置(复制为 config.json 以自定义) |
| templates.md | 常见任务的提示模板 |
⚙️ 配置
选项 1:使用默认值
所有默认值均已内置。无需配置文件。
选项 2:自定义
将 config.default.json 复制到同一文件夹中的 config.json 并进行修改:
bash
cp config.default.json config.json
使用您的偏好编辑 config.json
配置结构:
json
{
timeouts: { initialize: 10000, prompt: {...} },
retry: { maxAttempts: 3, initialDelay: 2000 },
polling: { initial: 1000, active: 2000 },
healthCheck: { noOutputThreshold: 60000 },
recovery: { autoRecover: true },
mcpServers: { default: [], supabase: [supabase] }
}
超时时间(可配置)
| 操作 | 默认值 | 最大值 | 何时增加 |
|---|
| 初始化 | 10秒 | 30秒 | 机器速度慢 |
| 新建会话 |
10秒 | 30秒 | 大型项目 |
| 提示(简单) | 60秒 | 120秒 | 复杂查询 |
| 提示(复杂) | 120秒 | 300秒 | 重构、代码生成 |
| 健康检查 | 5秒 | 10秒 | 网络问题 |
重试配置
| 设置 | 默认值 | 描述 |
|---|
| 最大重试次数 | 3 | 失败时重试的次数 |
| 重试延迟 |
2秒 | 重试之间的初始延迟 |
| 退避乘数 | 2 | 每次重试延迟加倍 |
| 最大重试延迟 | 10秒 | 重试之间的最大延迟 |
自适应轮询
2秒 | 10秒 - 60秒 |
| 稳定 | 3秒 | 60秒 - 120秒 |
| 缓慢 | 5秒 | 120秒以上 |
🔄 自动恢复
卡死检测
当出现以下情况时,OpenCode 被视为卡死:
- - 在 2倍预期超时时间 后无响应
- 健康检查连续失败 3 次
- 进程仍在运行但未响应轮询
恢复步骤
检测到卡死时:
- 1. 取消当前操作:session/cancel
- 等待 2 秒
- 如果仍然卡死:process.kill
- 清理锁
- 重启 OpenCode
- 从最后一个已知会话恢复(如果可用)
锁清理
当 OpenCode 崩溃时,锁文件可能会变得过时。始终清理:
bash
在启动新会话之前
exec(command: find ~/.openclaw/agents -name *.lock -mmin +30 -delete)
在杀死卡死进程后
exec(command: rm -f ~/.openclaw/agents//sessions/.lock)
📋 分步工作流
步骤 1:预检
在开始之前,验证环境:
bash
检查 OpenCode 是否已安装
exec(command: opencode --version)
清理过时的锁(超过 30 分钟)
exec(command: find ~/.openclaw/agents -name *.lock -mmin +30 -delete)
步骤 2:启动 OpenCode
bash
exec(
command: opencode acp --cwd /path/to/project,
background: true,
workdir: /path/to/project
)
保存 sessionId 以供所有后续操作使用
步骤 3:初始化(带重试)
json
// 发送初始化
{jsonrpc:2.0,id:0,method:initialize,params:{protocolVersion:1,clientCapabilities:{fs:{readTextFile:true,writeTextFile:true},terminal:true},clientInfo:{name:clawdbot,title:Clawdbot,version:2.0.0}}}
重试逻辑:
for attempt in 1..3:
process.write(sessionId, initialize_json + \n)
response = process.poll(sessionId, timeout: 10000)
if response contains protocolVersion:
break # 成功
if attempt < 3:
sleep(2 * attempt) # 退避:2秒,4秒
else:
# 恢复模式
process.kill(sessionId)
cleanupLocks()
restart from Step 2
步骤 4:创建会话(带重试)
json
{jsonrpc:2.0,id:1,method:session/new,params:{cwd:/path/to/project,mcpServers:[]}}
与初始化相同的重试逻辑。
步骤 5:发送提示(带自适应轮询)
json
{jsonrpc:2.0,id:2,method:session/prompt,params:{sessionId:sess_xyz,prompt:[{type:text,text:您的问题在这里}]}}
自适应轮询:
elapsed = 0
interval = 1000 # 从 1 秒开始
maxWait = 120000 # 复杂任务 2 分钟
while elapsed < maxWait:
response = process.poll(sessionId, timeout: interval)
if response contains stopReason:
return response # 完成
if response contains error:
handle_error(response)
break
# 自适应间隔
elapsed += interval
if elapsed < 10000:
interval = 1000 # 前 10