
Opencode
- 94 installs
- 27.9k repo stars
- Updated August 4, 2026
- volcengine/openviking
Helps with ai & agent building tasks.
About
opencode is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- opencode
- AI & Agent Building
- AI-coding skill
Opencode by the numbers
- 94 all-time installs (skills.sh)
- +2 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #4,644 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/volcengine/openviking --skill opencodeAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 94 |
|---|---|
| repo stars | ★ 27.9k |
| Last updated | August 4, 2026 |
| Repository | volcengine/openviking ↗ |
What it does
Helps with ai & agent building tasks.
Files
OpenCode Skill
Use helper scripts to manage your OpenCode instances.
Helper Scripts
All scripts are in the workspace skills directory. Run them with:
uv run python skills/opencode/script_name.pyNote: Do not kill the opencode process.
Scripts
list_sessions.py
Listing all OpenCode sessions
Example: uv run python skills/opencode/list_sessions.py
list_messages_of_session.py
Listing latest OpenCode messages by session_id
Example: uv run python skills/opencode/list_sessions.py {session_id}
Session Status Types
- 🟢 WAITING: Last message was from user - agent is waiting for input
- 🔴 WORKING: Last message was from assistant - agent recently finished or may be working
- 🟡 UNKNOWN: Cannot determine status
#!/usr/bin/env python3
"""Test listing OpenCode sessions"""
import json
import time
from opencode_ai import Opencode
from opencode_utils import (
check_serve_status,
execute_cmd,
read_new_messages,
read_status,
write_status,
list_project,
)
from pydantic import BaseModel
print("=" * 80)
print("Listing OpenCode Sessions")
print("=" * 80)
check_serve_status()
client = Opencode(base_url="http://127.0.0.1:4096")
class ViewSession(BaseModel):
title: str
session_id: str
last_modify_time: str
create_time: str
directory: str
status: str
new_messages: str
try:
session_notify_status = read_status()
project_list = list_project(client)
sessions = []
for project in project_list:
r = execute_cmd(f"cd {project['path']};opencode session list --format=json")
if r is None:
continue
try:
project_sessions = json.loads(r)
sessions.extend(project_sessions)
except Exception:
pass
# print(f'sessions={sessions}')
v_sessions = []
for session in sessions:
# 去掉超过一天没变化的
if time.time() - session.get("updated") / 1000 > 24 * 3600:
continue
v_session = ViewSession(
title=session.get("title"),
session_id=session.get("id"),
last_modify_time=time.strftime(
"%Y-%m-%d %H:%M:%S", time.localtime(session.get("updated") / 1000)
),
create_time=time.strftime(
"%Y-%m-%d %H:%M:%S", time.localtime(session.get("created") / 1000)
),
directory=session.get("directory"),
status="",
new_messages="",
)
status, new_messages_list, next_ts = read_new_messages(
client,
session_id=v_session.session_id,
last_ts=session_notify_status.get(v_session.session_id, 0),
)
v_session.status = status
if status == "finished":
message_texts = []
for msg in new_messages_list:
if msg.parts:
for part in msg.parts:
if hasattr(part, "text") and part.text:
message_texts.append(part.text)
v_session.new_messages = "\n\n".join(message_texts)
session_notify_status[v_session.session_id] = next_ts
v_sessions.append(v_session)
print(f"Success! Found {len(v_sessions)} session(s)")
print()
for i, vs in enumerate(v_sessions, 1):
print(f"--- Session {i} ---")
print(f"Title: {vs.title}")
print(f"Session ID: {vs.session_id}")
print(f"Status: {vs.status}")
print(f"Last Modified: {vs.last_modify_time}")
print(f"Created: {vs.create_time}")
print(f"Directory: {vs.directory}")
if vs.new_messages:
print(f"New Messages To User:\n{vs.new_messages}")
else:
print("New Messages To User: (none)")
print()
write_status(session_notify_status)
except Exception as e:
print(f" Error: {e}")
import traceback
traceback.print_exc()
print("\n" + "=" * 80)
#!/usr/bin/env python3
"""Simple test for opencode-ai SDK"""
import json
import os
import subprocess
import sys
import time
import traceback
from opencode_ai import Opencode
def execute_cmd(cmd):
try:
result = subprocess.run(
cmd,
shell=True,
text=True,
encoding="utf-8",
stdout=subprocess.PIPE,
stderr=subprocess.PIPE, # 捕获错误输出
check=True, # 等价于check_output的行为,命令失败会抛异常
)
stdout = result.stdout.strip() # 去除空白符(换行/空格)
return stdout
except subprocess.CalledProcessError as e:
# 捕获命令执行失败的异常(返回码非0)
print(f"命令执行失败:{e}")
return None
except Exception as e:
# 捕获其他异常(如命令不存在、超时等)
print(f"执行异常:{str(e)}")
return None
def start_opencode():
"""子进程函数:启动opencode serve并完全脱离子进程控制"""
pid = None
try:
if sys.platform == "win32":
# Windows:使用CREATE_NEW_PROCESS_GROUP创建独立进程组,detach脱离父进程
creationflags = subprocess.CREATE_NEW_PROCESS_GROUP | subprocess.DETACHED_PROCESS
proc = subprocess.Popen(
["opencode", "serve"],
shell=False,
creationflags=creationflags,
stdout=subprocess.DEVNULL, # 重定向输出避免控制台关联
stderr=subprocess.DEVNULL,
stdin=subprocess.DEVNULL,
)
pid = proc.pid
else:
# Linux/macOS:使用os.setsid创建新会话,完全脱离控制终端
# 先fork一次,再启动进程,确保脱离所有父进程关联
cmd = ["opencode", "serve"]
# 创建新会话 + 重定向所有输出
with open("opencode.log", "a", encoding="utf-8") as log_file:
proc = subprocess.Popen(
cmd,
preexec_fn=os.setsid, # 关键:创建新的会话ID
stdout=log_file,
stderr=subprocess.STDOUT,
stdin=subprocess.DEVNULL,
)
pid = proc.pid
print(f"opencode serve已启动,PID: {pid}")
# 短暂等待确保进程启动成功
time.sleep(2)
return pid
except Exception as e:
print(f"启动opencode失败: {e}")
traceback.print_exc()
return None
def check_serve_status():
"""测试opencode连接,失败则启动服务并重试"""
try:
client = Opencode(base_url="http://127.0.0.1:4096")
client.app.modes()
except Exception as e:
print(f"连接opencode失败,错误: {e}")
# 启动服务
pid = start_opencode()
if pid:
# 启动后重试连接
time.sleep(3)
def read_new_messages(client, session_id, last_ts):
"""
读取上一次之后的消息, 通过client.session.messages实现,注意
"""
messages = client.session.messages(id=session_id, extra_query={"limit": 10})
next_ts = last_ts
new_messages = []
has_finished = False
for message in messages:
created_time = 0
if hasattr(message, "info") and message.info:
if hasattr(message.info, "time") and message.info.time:
if hasattr(message.info.time, "created"):
created_time = message.info.time.created
if created_time > last_ts:
new_messages.append(message)
if created_time > next_ts:
next_ts = created_time
if messages:
last_message = messages[-1]
if last_message.parts:
for part in last_message.parts:
if hasattr(part, "type") and part.type == "step-finish":
has_finished = True
status = "finished" if has_finished else "running"
return status, new_messages, next_ts
file_path = "status.json"
def read_status():
# 检查文件是否存在
if not os.path.exists(file_path):
return {}
# 读取并解析JSON文件
try:
with open(file_path, "r", encoding="utf-8") as f:
data = json.load(f)
return data
except Exception as e:
# 捕获其他未知异常
print(f"读取 {file_path} 时发生错误:{e}")
return {}
def write_status(status):
try:
with open(file_path, "w", encoding="utf-8") as f:
f.write(json.dumps(status))
except Exception as e:
# 捕获其他未知异常
print(f"写入 {file_path} 时发生错误:{e}")
def list_project(client):
import httpx
http_client = httpx.Client(base_url="http://127.0.0.1:4096")
response = http_client.get("/project")
projects = response.json()
project_list = []
for p in projects:
project_list.append({"id": p.get("id"), "path": p.get("worktree")})
return project_list
{"ses_37e6f7aaaffebcNKWA5sk09F6K": 1771705418600.0, "ses_385e39be5ffeeV7ilnnzy4yDAQ": 1771705404886.0, "ses_3840324c5ffe8oxcxtnepcBMUA": 1771681820419.0, "ses_3841828aaffekkJXyw5G51UMs5": 1771681740410.0, "ses_3844371a1ffed59rH2hPT6m2tV": 1771610393424.0, "ses_383d30ee5ffeB48f0WUibBMSmM": 1771609846075.0, "ses_383d3da13ffennEpy1NF11rm4w": 1771609794108.0, "ses_383e8ccc4ffe7ZScb5uXAjRkpY": 1771608442629.0, "ses_38463e4d3ffevqo4d3B6ebhMLW": 1771601915087.0, "ses_3861b37a7ffec5IG3MY9nUVpWb": 1771574574499.0, "ses_386236c6cffesXHmovcojjXk2F": 1771571691339.0, "ses_38624bea6ffenDvoHbVJSkhnjk": 1771570986217.0, "ses_38a5b5f9fffeESwGW8QGLOlptN": 1771570765276.0, "ses_389029e43ffext960XkQX5mZrk": 1771522961494.0, "ses_3891afb63ffengfHd1OK6FcT0R": 1771522178391.0, "ses_38ad2eebaffeb5q7gt0tJn5f72": 1771520924370.0, "ses_38ad4021affe6SgOZZnksIsASB": 1771493130684.0, "ses_38d974056ffea3x21l7Qy3dzSJ": 1771492919187.0, "ses_38b86fe00ffexkiJZhUv6ppmWv": 1771492295098.0, "ses_38e976af5ffeJbH2b5cREgvmIt": 1771449514840.0, "ses_38edfc368ffeD19B652q5PpG2A": 1771443663144.0, "ses_38e0f270dffeBwWEbwcJ86kdRs": 1771440834608.0, "ses_38ee03d35ffeFSY29g4GeO18Dd": 1771432511618.0, "ses_38ee72471ffeP4mNs8xy5FlRMx": 1771424171041.0, "ses_38f49d34affeiSGvF4oEeel5dh": 1771422765870.0, "ses_38fdb15c2ffetAl4uvwfj7Lq4G": 1771416967161.0, "ses_38fdb676effehJ38xfN0I1HuCf": 1771408168150.0, "ses_38fedc993ffejJ1FsH3whq5obq": 1771407810512.0, "ses_390ba90d2ffeM5Y0SX2Mcod8SX": 1771406394631.0, "ses_38ff50978ffe1yuURiyn7xOZBD": 1771406343237.0, "ses_39073ac1effe5gErJaxT1vqlae": 1771406099720.0, "ses_393d6ce9dffeZKwtixT1lmaoAC": 1771403306062.0, "ses_390b3bd7bffepm7vThtNoFSRxl": 1771397743743.0, "ses_3935ab0deffemx7CZICbyToDqa": 1771393253621.0, "ses_394cea387ffe6LRdyrF4MFkB6B": 1771334704882.0, "ses_3984ede39ffetKGBJzsV1NTqDC": 1771324772615.0, "ses_395387f6cffeWZAHwWYViFJJAw": 1771318072243.0, "ses_398930557ffe54pZx1A4qiF5NE": 1771315609370.0, "ses_39a7761f6ffecUbraoAPRMpdm5": 1771260506122.0, "ses_3992c45a4ffeIjVcUAlazG9DnI": 1771253818807.0, "ses_3994672edffe51xgCr7v3xt6vQ": 1771251365312.0, "ses_39e2278bdffepEMoolVdagCvZZ": 1771232393079.0, "ses_3a3fe979dffezZ6mD20id0kXmv": 1771138324753.0, "ses_3a2c4c8ebffeB5yR7SBn27rIYN": 1771137308133.0, "ses_3a2ffc4f9ffeGP66Du0M7iqRsn": 1771087354518.0, "ses_3a35d62f2ffeQzmmHDv0D0I4Kp": 1771083219683.0, "ses_3a4c84867ffeZ3NwPkyB3yCA5A": 1771079806473.0, "ses_3a4aed9fdffec3zH3pfLoIFC0k": 1771058607645.0, "ses_3a5935745ffeogNcnmipkbyKFv": 1771056505081.0, "ses_3a54305f0ffef3RswP7vRevVma": 1771049837211.0, "ses_3e14e05beffevX72vAtAfDROvs": 1770046038165.0, "ses_4169b0accffeWMepr20GYg0uzb": 1769268597312.0, "ses_41726157affehPRxs4HLb4ylc0": 1769139426432.0, "ses_420b42042ffe56ms45qI1wNj7Z": 1769096075354.0, "ses_420ac3190ffepiPPs4XELPCis7": 1768988104702.0, "ses_3cd851a46ffedTxNP8NZFfGUAD": 1770375314519.0, "ses_3dd056e4bffeC17HbyPeX0qvo3": 1770132409750.0, "ses_3dbe7678dffewFFcHlm717CXRs": 1770132117877.0, "ses_3dbe81743ffeNRGJOHbCeBsp2U": 1770132072926.0, "ses_3dbeb534dffehta70BcTcIIXGs": 1770131860899.0, "ses_3dbee418dffeTh2Fra8VF1Obq6": 1770131668837.0, "ses_3dbf93841ffeN2vTtxzrP7Wu1l": 1770130950323.0, "ses_3a000ea5bffeypqv7O9mCGqE7g": 1771137692230.0, "ses_3a015ab7cffe5OuChV0mWREpx5": 1771136331901.0, "ses_3aa99d1d2ffeU5xTLEzwuhYxPN": 1770984561255.0, "ses_3ae0fcd78ffewpOR1UCKI4Idgz": 1770903420864.0, "ses_3b52f49caffejF5J2FM4BFF36p": 1770782100102.0, "ses_3c1fb5fbaffe6g34QBoAMQG71I": 1770647156977.0, "ses_3bd49cb33ffe2z3MpMnmKYEa09": 1770646237923.0, "ses_3be092bfeffeWOOixnz6IvIeOe": 1770639593632.0, "ses_3c3b9561bffesX0GRPQxGnt8PQ": 1770569225806.0, "ses_3c3dbc2d5ffe6SyN40etNtKh0C": 1770536840287.0, "ses_3dc4c0127ffeQVFhhaTcOwtXAV": 1770125525055.0, "ses_3dc7bc9a2ffe69K3qaiFlQQxYR": 1770122434387.0, "ses_3dd6564eeffeOmR20r80ytp5Jr": 1770113276387.0, "ses_3de0466c6ffe7J5XA2fG0oZT1s": 1770098125714.0, "ses_419ae3300ffeNw9K9THrXci0m0": 1769096028020.0, "ses_41b358f11ffe5wj5zBIx60abTv": 1769077219885.0, "ses_42041fcb6ffe82eywi2rnl7ZAZ": 1768989743967.0, "ses_4208da21cffeItI0dU5syhMUd8": 1768982263170.0, "ses_423b26c03ffe6EDjYBBpC7smF3": 1768973926302.0, "ses_423ad2c78ffePjJ4XRHmXT963v": 1768928660271.0, "ses_423b72381ffeKYSgEltqp3AI6Y": 1768927875028.0, "ses_4297f33c3ffeWKXohAhwiYvsP6": 1768830482116.0, "ses_439d9c695ffeSre77yzr6HHJtm": 1768825102282.0, "ses_429e13120ffe46zz5f0M7KPclQ": 1768824354235.0, "ses_4408e7b46ffe100EhnGvdIxK9x": 1768823800015.0, "ses_43fa48016ffe0VP3ph8mB4Uw6Z": 1768461699920.0, "ses_444a662dbffe2a1EX1dFsoFMxf": 1768441375805.0, "ses_4453d8101ffeGvNKjYoBZbkq9l": 1768374440698.0, "ses_44552a9dbffeykv5eLXIdjTw1O": 1768364768860.0, "ses_44f2f79a0ffeDu9r8fQUtGSic1": 1768200091377.0, "ses_44f368ab0ffef0V8xcz7ELwiW0": 1768197605330.0, "ses_44f39ba2dffeRzUsOyTpFw0MQc": 1768197365549.0, "ses_44f3ad063ffekshs4rCrtpO0L8": 1768197318601.0, "ses_44f3c7cc9ffeZ23zlysikVQwF6": 1768197205652.0}Related skills
AI & Agent Buildingagents