@colinmollenhour/occtl 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +290 -0
- package/SKILL.md +692 -0
- package/dist/client.d.ts +4 -0
- package/dist/client.js +64 -0
- package/dist/commands/session-abort.d.ts +2 -0
- package/dist/commands/session-abort.js +16 -0
- package/dist/commands/session-children.d.ts +2 -0
- package/dist/commands/session-children.js +30 -0
- package/dist/commands/session-create.d.ts +2 -0
- package/dist/commands/session-create.js +39 -0
- package/dist/commands/session-diff.d.ts +2 -0
- package/dist/commands/session-diff.js +35 -0
- package/dist/commands/session-get.d.ts +2 -0
- package/dist/commands/session-get.js +24 -0
- package/dist/commands/session-last.d.ts +2 -0
- package/dist/commands/session-last.js +39 -0
- package/dist/commands/session-list.d.ts +2 -0
- package/dist/commands/session-list.js +91 -0
- package/dist/commands/session-messages.d.ts +2 -0
- package/dist/commands/session-messages.js +44 -0
- package/dist/commands/session-respond.d.ts +2 -0
- package/dist/commands/session-respond.js +78 -0
- package/dist/commands/session-send.d.ts +2 -0
- package/dist/commands/session-send.js +114 -0
- package/dist/commands/session-share.d.ts +3 -0
- package/dist/commands/session-share.js +53 -0
- package/dist/commands/session-status.d.ts +2 -0
- package/dist/commands/session-status.js +45 -0
- package/dist/commands/session-summary.d.ts +2 -0
- package/dist/commands/session-summary.js +87 -0
- package/dist/commands/session-todo.d.ts +2 -0
- package/dist/commands/session-todo.js +41 -0
- package/dist/commands/session-wait-for-text.d.ts +2 -0
- package/dist/commands/session-wait-for-text.js +119 -0
- package/dist/commands/session-wait.d.ts +4 -0
- package/dist/commands/session-wait.js +85 -0
- package/dist/commands/session-watch.d.ts +2 -0
- package/dist/commands/session-watch.js +101 -0
- package/dist/commands/skill.d.ts +3 -0
- package/dist/commands/skill.js +55 -0
- package/dist/commands/worktree.d.ts +5 -0
- package/dist/commands/worktree.js +359 -0
- package/dist/format.d.ts +19 -0
- package/dist/format.js +115 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +63 -0
- package/dist/resolve.d.ts +6 -0
- package/dist/resolve.js +47 -0
- package/dist/sse.d.ts +40 -0
- package/dist/sse.js +128 -0
- package/dist/wait-util.d.ts +23 -0
- package/dist/wait-util.js +118 -0
- package/package.json +49 -0
package/SKILL.md
ADDED
|
@@ -0,0 +1,692 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: occtl
|
|
3
|
+
description: Manage OpenCode sessions from the CLI using occtl. Use when the user wants to list sessions, read session messages, get the last message, watch a session for updates, send messages to sessions, respond to permission requests, check session status, view todos, abort sessions, view diffs, or automate session management. Triggers include "check session", "read messages", "last message", "watch session", "send prompt", "approve permissions", "session status", "session todo", "abort session", or any programmatic OpenCode session interaction.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# occtl - Extended CLI for OpenCode Sessions
|
|
7
|
+
|
|
8
|
+
`occtl` extends the `opencode` CLI with session management commands that are missing from the official tool: reading messages, watching sessions in real-time, responding to permission requests, and more.
|
|
9
|
+
|
|
10
|
+
## Prerequisites
|
|
11
|
+
|
|
12
|
+
- OpenCode must be running (the server is auto-detected from running processes)
|
|
13
|
+
- If auto-detection fails, set `OPENCODE_SERVER_HOST` and `OPENCODE_SERVER_PORT`
|
|
14
|
+
|
|
15
|
+
## Quick Reference
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
occtl create -q # create a new session, print its ID
|
|
19
|
+
occtl list # list all sessions
|
|
20
|
+
occtl last # last message from most recent session
|
|
21
|
+
occtl messages <id> # all messages in a session
|
|
22
|
+
occtl watch <id> --text-only # stream text in real-time
|
|
23
|
+
occtl send "fix the bug" # send a message
|
|
24
|
+
occtl respond --auto-approve -w # auto-approve permissions
|
|
25
|
+
occtl todo # view session todo list
|
|
26
|
+
occtl status # check if sessions are busy/idle
|
|
27
|
+
occtl share # share session, get public URL
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Commands
|
|
31
|
+
|
|
32
|
+
### List Sessions
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
occtl list # sessions for current directory only (default)
|
|
36
|
+
occtl list --all # sessions for ALL directories
|
|
37
|
+
occtl list /path/to/project # sessions for a specific directory
|
|
38
|
+
occtl list --children # include child sessions (sub-agents)
|
|
39
|
+
occtl list --json # JSON output for scripting
|
|
40
|
+
occtl list --detailed # show full details per session
|
|
41
|
+
occtl list --limit 5 # limit results
|
|
42
|
+
occtl list --sort created # sort by: updated (default), created, title
|
|
43
|
+
occtl list --sort title --asc # sort ascending
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Create a Session
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
occtl create # create a new session in the current directory
|
|
50
|
+
occtl create -t "my feature work" # with a title
|
|
51
|
+
occtl create -d /path/to/project # create in a specific project directory
|
|
52
|
+
occtl create -q # quiet mode: only output the session ID
|
|
53
|
+
occtl create --json # full JSON output
|
|
54
|
+
occtl create -p <parent-id> # create a child session
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The `-q` flag is useful in scripts: `SID=$(occtl create -q)`
|
|
58
|
+
|
|
59
|
+
The `-d` flag enables cross-project orchestration: `SID=$(occtl create -q -d /path/to/other/project)`
|
|
60
|
+
|
|
61
|
+
### Get Session Details
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
occtl get <session-id> # detailed info about a session
|
|
65
|
+
occtl get <session-id> --json
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Read Messages
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
occtl messages # all messages from most recent session
|
|
72
|
+
occtl messages <session-id> # all messages from specific session
|
|
73
|
+
occtl messages <id> --role user # only user messages
|
|
74
|
+
occtl messages <id> --role assistant # only assistant messages
|
|
75
|
+
occtl messages <id> --limit 5 # last 5 messages
|
|
76
|
+
occtl messages <id> --text-only # text content only
|
|
77
|
+
occtl messages <id> --verbose # include tool call details
|
|
78
|
+
occtl messages <id> --json # full JSON output
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Get Last Message
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
occtl last # last message (text-only by default)
|
|
85
|
+
occtl last <session-id> # from specific session
|
|
86
|
+
occtl last --role user # last user message
|
|
87
|
+
occtl last --role assistant # last assistant message
|
|
88
|
+
occtl last --verbose # include tool calls and metadata
|
|
89
|
+
occtl last --json # full JSON output
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Watch Session (Real-Time)
|
|
93
|
+
|
|
94
|
+
Connects to the SSE event stream and displays events for a session:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
occtl watch # watch most recent session
|
|
98
|
+
occtl watch <session-id> # watch specific session
|
|
99
|
+
occtl watch --text-only # stream only text content as it arrives
|
|
100
|
+
occtl watch --json # output each event as JSON line
|
|
101
|
+
occtl watch --events message.updated,session.idle # filter event types
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Event types shown: `message.updated`, `message.part.updated` (text deltas, tool calls), `session.status`, `session.idle`, `permission.updated`, `todo.updated`, `session.error`.
|
|
105
|
+
|
|
106
|
+
Press Ctrl+C to stop watching.
|
|
107
|
+
|
|
108
|
+
### Send Messages
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
occtl send "your message here" # send to most recent session
|
|
112
|
+
occtl send -s <session-id> "your message" # send to specific session
|
|
113
|
+
occtl send --async "do this in background" # send and return immediately
|
|
114
|
+
occtl send -w "fix the tests" # send, block until idle, show result
|
|
115
|
+
occtl send --model anthropic/claude-opus-4-6 "hi" # specify model
|
|
116
|
+
occtl send --agent plan "analyze this code" # specify agent
|
|
117
|
+
occtl send --no-reply "context info" # inject context without AI response
|
|
118
|
+
occtl send --stdin < prompt.txt # read message from stdin
|
|
119
|
+
occtl send "message" --json # JSON response output
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The three send modes:
|
|
123
|
+
- **(default)** — synchronous: blocks on the HTTP request until the agent responds, returns the response.
|
|
124
|
+
- **`--async`** — fire-and-forget: sends and exits immediately. Use with `watch` or `wait-for-text` separately.
|
|
125
|
+
- **`--wait` / `-w`** — hybrid: sends async, blocks until `session.idle` via SSE, then fetches and displays the last assistant message. Best for scripts that need the result but want event-driven waiting.
|
|
126
|
+
|
|
127
|
+
### Respond to Permission Requests
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# Respond to a specific permission
|
|
131
|
+
occtl respond <session-id> -p <permission-id> -r once
|
|
132
|
+
|
|
133
|
+
# Wait for and respond to the next permission request
|
|
134
|
+
occtl respond <session-id> --wait -r always
|
|
135
|
+
|
|
136
|
+
# Auto-approve all permissions continuously (for automation)
|
|
137
|
+
occtl respond <session-id> --auto-approve --wait
|
|
138
|
+
|
|
139
|
+
# Response options: once, always, reject
|
|
140
|
+
occtl respond -r reject -p <permission-id>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### View Todos
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
occtl todo # todos from most recent session
|
|
147
|
+
occtl todo <session-id> # todos from specific session
|
|
148
|
+
occtl todo --json # JSON output
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Output format:
|
|
152
|
+
```
|
|
153
|
+
[x]! Completed high-priority task
|
|
154
|
+
[>] In-progress task
|
|
155
|
+
[ ] Pending task
|
|
156
|
+
[-] Cancelled task
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Check Session Status
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
occtl status # all session statuses
|
|
163
|
+
occtl status <session-id> # specific session status
|
|
164
|
+
occtl status --json # JSON output
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Status types: `idle`, `busy`, `retry`.
|
|
168
|
+
|
|
169
|
+
### Abort a Session
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
occtl abort # abort most recent session
|
|
173
|
+
occtl abort <session-id> # abort specific session
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### View Diffs
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
occtl diff # file changes from most recent session
|
|
180
|
+
occtl diff <session-id> # file changes from specific session
|
|
181
|
+
occtl diff --json # JSON output
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Wait for Text
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
occtl wait-for-text "SOME_TEXT" # wait on most recent session
|
|
188
|
+
occtl wait-for-text "SOME_TEXT" <session-id> # wait on specific session
|
|
189
|
+
occtl wait-for-text "DONE" --timeout 300 # timeout after 5 minutes (exit 1)
|
|
190
|
+
occtl wait-for-text "DONE" --no-check-existing # skip checking existing messages
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Checks existing messages first (by default), then watches the SSE stream for new ones. Outputs everything after the matched text and exits 0. Exits 1 on timeout.
|
|
194
|
+
|
|
195
|
+
The default check-existing behavior prevents a race condition where the text appears between `send --async` and `wait-for-text` starting. Use `--no-check-existing` only if you specifically want to wait for a *new* occurrence.
|
|
196
|
+
|
|
197
|
+
### Wait for Idle
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
occtl wait-for-idle # block until most recent session is idle
|
|
201
|
+
occtl wait-for-idle <session-id> # block until specific session is idle
|
|
202
|
+
occtl wait-for-idle --timeout 300 # timeout after 5 minutes (exit 1)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Blocks until the session goes idle. Does a quick status check first — if already idle, exits immediately. Otherwise watches the SSE stream. Exit 0 = idle, exit 1 = timeout.
|
|
206
|
+
|
|
207
|
+
### Wait Any (Multiple Sessions)
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
occtl wait-any <id1> <id2> <id3> # wait for FIRST to go idle, output its ID
|
|
211
|
+
occtl wait-any <id1> <id2> --timeout 600
|
|
212
|
+
occtl wait-any <id1> <id2> --json # {"sessionID": "...", "reason": "idle"}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Watches multiple sessions simultaneously. Outputs the session ID of the first one to go idle and exits. Essential for orchestrating parallel workloads.
|
|
216
|
+
|
|
217
|
+
### Is Idle (Non-Blocking Check)
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
occtl is-idle # exit 0 if idle, exit 1 if busy
|
|
221
|
+
occtl is-idle <session-id>
|
|
222
|
+
occtl is-idle --json # {"sessionID": "...", "idle": true, "status": "idle"}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Non-blocking check. Useful for conditional logic in agent orchestration.
|
|
226
|
+
|
|
227
|
+
### Session Summary
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
occtl summary # compact summary of most recent session
|
|
231
|
+
occtl summary <session-id>
|
|
232
|
+
occtl summary --json # machine-readable summary
|
|
233
|
+
occtl summary -n 500 # longer last-message snippet (default: 200 chars)
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Shows status, todo progress, total cost, file changes, and a snippet of the last assistant message — all in one call. Designed for orchestration agents that need a quick overview without reading full message history.
|
|
237
|
+
|
|
238
|
+
### Share / Unshare
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
occtl share # share most recent session, print URL
|
|
242
|
+
occtl share <session-id> # share a specific session
|
|
243
|
+
occtl share --json # full JSON output
|
|
244
|
+
occtl unshare <session-id> # remove sharing
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### List Child Sessions
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
occtl children # children of most recent session
|
|
251
|
+
occtl children <session-id> # children of specific session
|
|
252
|
+
occtl children --json # JSON output
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Session ID Resolution
|
|
256
|
+
|
|
257
|
+
All commands that accept a session ID support:
|
|
258
|
+
|
|
259
|
+
1. **No ID** - defaults to most recent session
|
|
260
|
+
2. **Full ID** - exact match (e.g., `ses_2e1451cf8ffe7cBLbjmQS8Ogsc`)
|
|
261
|
+
3. **Partial ID** - prefix or substring match (e.g., `ses_2e14` or just `2e14`)
|
|
262
|
+
4. **Title search** - case-insensitive match against session title
|
|
263
|
+
|
|
264
|
+
## Worktrees
|
|
265
|
+
|
|
266
|
+
`occtl worktree` (alias `occtl wt`) manages git worktrees for running parallel, isolated sessions. Each worktree gets its own branch and working directory under `.occtl/worktrees/`, so multiple agents can work on different features simultaneously without file conflicts.
|
|
267
|
+
|
|
268
|
+
### List Worktrees
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
occtl wt list # list all git worktrees
|
|
272
|
+
occtl wt list --json # JSON output
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Create a Worktree
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
occtl wt create auth-feature # creates worktree + branch + session
|
|
279
|
+
occtl wt create auth-feature -b my-branch # custom branch name
|
|
280
|
+
occtl wt create auth-feature --base main # branch from a specific ref
|
|
281
|
+
occtl wt create auth-feature --no-session # just create the worktree, no session
|
|
282
|
+
occtl wt create auth-feature -q # only output the worktree path
|
|
283
|
+
occtl wt create auth-feature --json # JSON output with path, branch, sessionID
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
By default, `create` also creates an OpenCode session scoped to the worktree directory.
|
|
287
|
+
|
|
288
|
+
Worktrees are created under `.occtl/worktrees/<name>` with branch `worktree-<name>`.
|
|
289
|
+
|
|
290
|
+
### Remove a Worktree
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
occtl wt rm auth-feature # remove by name
|
|
294
|
+
occtl wt rm auth-feature --force # force remove even if dirty
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Run a Prompt in a New Worktree
|
|
298
|
+
|
|
299
|
+
The `run` command is a one-liner that creates a worktree, starts a session, and sends a prompt:
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
# Fire-and-forget: create worktree + session, send prompt, exit immediately
|
|
303
|
+
occtl wt run auth-feature "implement JWT authentication"
|
|
304
|
+
|
|
305
|
+
# Wait for completion: block until the session goes idle, show result
|
|
306
|
+
occtl wt run auth-feature -w "implement JWT authentication"
|
|
307
|
+
|
|
308
|
+
# With auto-approve and a specific model
|
|
309
|
+
occtl wt run auth-feature -w --auto-approve \
|
|
310
|
+
--model anthropic/claude-sonnet-4-6 \
|
|
311
|
+
"implement JWT authentication"
|
|
312
|
+
|
|
313
|
+
# Read prompt from a file
|
|
314
|
+
occtl wt run auth-feature -w --stdin < prompts/auth.md
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Parallel Features
|
|
318
|
+
|
|
319
|
+
Launch multiple features in parallel, each in its own worktree:
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
# Start 3 features simultaneously
|
|
323
|
+
occtl wt run auth "implement JWT auth" &
|
|
324
|
+
occtl wt run payments "add Stripe checkout" &
|
|
325
|
+
occtl wt run dashboard "build analytics dashboard" &
|
|
326
|
+
wait
|
|
327
|
+
|
|
328
|
+
# Check status of each
|
|
329
|
+
occtl ls /path/to/repo/.occtl/worktrees/auth
|
|
330
|
+
occtl ls /path/to/repo/.occtl/worktrees/payments
|
|
331
|
+
occtl ls /path/to/repo/.occtl/worktrees/dashboard
|
|
332
|
+
|
|
333
|
+
# When done, review diffs and merge
|
|
334
|
+
for wt in auth payments dashboard; do
|
|
335
|
+
echo "=== $wt ==="
|
|
336
|
+
cd .occtl/worktrees/$wt && git log --oneline main..HEAD && cd -
|
|
337
|
+
done
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Parallel Ralph Loop
|
|
341
|
+
|
|
342
|
+
Combine worktrees with the Ralph Loop to run multiple autonomous task lists in parallel:
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
#!/usr/bin/env bash
|
|
346
|
+
set -e
|
|
347
|
+
|
|
348
|
+
# Each feature gets its own worktree and Ralph loop
|
|
349
|
+
FEATURES=("auth" "payments" "dashboard")
|
|
350
|
+
|
|
351
|
+
for feature in "${FEATURES[@]}"; do
|
|
352
|
+
(
|
|
353
|
+
# Create worktree
|
|
354
|
+
WT_PATH=$(occtl wt create "$feature" -q)
|
|
355
|
+
|
|
356
|
+
for i in $(seq 1 10); do
|
|
357
|
+
SID=$(occtl create -q -t "ralph-${feature}-$i")
|
|
358
|
+
|
|
359
|
+
PROMPT="$(cat "prompts/${feature}.md")
|
|
360
|
+
|
|
361
|
+
## Progress
|
|
362
|
+
$(cat "${WT_PATH}/progress.txt" 2>/dev/null || echo 'Starting fresh.')
|
|
363
|
+
|
|
364
|
+
When done, output RALPH_DONE. If ALL tasks are complete, output ALL_TASKS_COMPLETE."
|
|
365
|
+
|
|
366
|
+
occtl send --async "$PROMPT" -s "$SID"
|
|
367
|
+
occtl respond "$SID" --auto-approve --wait &
|
|
368
|
+
APID=$!
|
|
369
|
+
|
|
370
|
+
occtl wait-for-text "RALPH_DONE" "$SID" --timeout 600 || true
|
|
371
|
+
kill $APID 2>/dev/null || true
|
|
372
|
+
|
|
373
|
+
occtl last "$SID" >> "${WT_PATH}/progress.txt"
|
|
374
|
+
|
|
375
|
+
if occtl wait-for-text "ALL_TASKS_COMPLETE" "$SID" \
|
|
376
|
+
--check-existing --timeout 1; then
|
|
377
|
+
echo "=== $feature complete ==="
|
|
378
|
+
break
|
|
379
|
+
fi
|
|
380
|
+
done
|
|
381
|
+
) &
|
|
382
|
+
done
|
|
383
|
+
|
|
384
|
+
wait
|
|
385
|
+
echo "All features complete. Review worktrees and merge."
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
## Automation Patterns
|
|
389
|
+
|
|
390
|
+
### Continuous permission approval
|
|
391
|
+
|
|
392
|
+
```bash
|
|
393
|
+
# Run in background to auto-approve all permission requests
|
|
394
|
+
occtl respond --auto-approve --wait &
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### Poll session until idle
|
|
398
|
+
|
|
399
|
+
```bash
|
|
400
|
+
while [ "$(occtl status <id> --json | jq -r '.type')" = "busy" ]; do
|
|
401
|
+
sleep 2
|
|
402
|
+
done
|
|
403
|
+
echo "Session is idle"
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### Send message and capture response
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
response=$(occtl send "what files were changed?" --json)
|
|
410
|
+
echo "$response" | jq -r '.parts[] | select(.type == "text") | .text'
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### Watch for text output and pipe it
|
|
414
|
+
|
|
415
|
+
```bash
|
|
416
|
+
occtl watch <id> --text-only | tee session-output.txt
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Chain send + watch for async workflows
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
occtl send --async "refactor the auth module"
|
|
423
|
+
occtl watch --text-only
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
## JSON Output
|
|
427
|
+
|
|
428
|
+
All commands support `--json` for machine-readable output. The JSON structure matches the OpenCode SDK types directly (`Session`, `Message`, `Part`, `Todo`, etc.).
|
|
429
|
+
|
|
430
|
+
## Ralph Mode
|
|
431
|
+
|
|
432
|
+
Ralph Mode turns YOU (the agent reading this skill) into an autonomous project
|
|
433
|
+
orchestrator. Instead of a bash script driving the loop, you ARE the loop. You
|
|
434
|
+
create sessions, send prompts, monitor progress, handle failures, and keep
|
|
435
|
+
iterating until the project is done — all by running `occtl` commands.
|
|
436
|
+
|
|
437
|
+
The user kicks it off with something like:
|
|
438
|
+
> "Use the occtl skill to complete project X using Ralph Mode."
|
|
439
|
+
|
|
440
|
+
And you take it from there.
|
|
441
|
+
|
|
442
|
+
### How It Works
|
|
443
|
+
|
|
444
|
+
The Ralph pattern: break work into atomic tasks, execute each in a fresh session
|
|
445
|
+
(fresh context window), persist progress in the filesystem, repeat until done.
|
|
446
|
+
|
|
447
|
+
You are smarter than a bash loop because you can:
|
|
448
|
+
- Read the worker session's output and decide what to do next
|
|
449
|
+
- Adjust the prompt based on what actually happened
|
|
450
|
+
- Run multiple sessions in parallel on independent tasks
|
|
451
|
+
- Use worktrees to isolate parallel work that would conflict
|
|
452
|
+
- Handle errors, retries, and stuck sessions intelligently
|
|
453
|
+
- Make strategic decisions about task ordering and dependencies
|
|
454
|
+
|
|
455
|
+
### Step-by-Step Procedure
|
|
456
|
+
|
|
457
|
+
When asked to use Ralph Mode, follow this procedure:
|
|
458
|
+
|
|
459
|
+
**1. Assess the project.** Read the codebase, requirements, and any existing
|
|
460
|
+
task files. Understand what needs to be done.
|
|
461
|
+
|
|
462
|
+
**2. Create a task list.** Write a `tasks.md` file (or similar) in the project
|
|
463
|
+
root. Each task should be:
|
|
464
|
+
- Atomic: completable in a single session/context window
|
|
465
|
+
- Verifiable: has clear done criteria (tests pass, file exists, etc.)
|
|
466
|
+
- Independent: minimizes dependencies on other tasks
|
|
467
|
+
|
|
468
|
+
**3. Create a `PROMPT.md` file.** This is the base prompt sent to each worker
|
|
469
|
+
session. It should tell the worker to:
|
|
470
|
+
- Read `tasks.md` and `progress.txt` to understand current state
|
|
471
|
+
- Pick one incomplete task and implement it
|
|
472
|
+
- Run tests/verification before marking done
|
|
473
|
+
- Update `tasks.md` (mark task done) and `progress.txt` (append summary)
|
|
474
|
+
- Commit changes
|
|
475
|
+
|
|
476
|
+
**4. Execute the loop.** For each iteration:
|
|
477
|
+
|
|
478
|
+
```bash
|
|
479
|
+
# Create a fresh session
|
|
480
|
+
occtl create -q -t "ralph-iteration-N"
|
|
481
|
+
# Returns: ses_xxxxx
|
|
482
|
+
|
|
483
|
+
# Send the prompt (async so you don't block)
|
|
484
|
+
occtl send --async "$(cat PROMPT.md)" -s ses_xxxxx
|
|
485
|
+
|
|
486
|
+
# Auto-approve permissions for this session
|
|
487
|
+
occtl respond ses_xxxxx --auto-approve --wait
|
|
488
|
+
# (this runs in background via the shell — use & in bash)
|
|
489
|
+
|
|
490
|
+
# Wait for the session to finish
|
|
491
|
+
occtl wait-for-idle ses_xxxxx --timeout 600
|
|
492
|
+
|
|
493
|
+
# Check what happened
|
|
494
|
+
occtl summary ses_xxxxx
|
|
495
|
+
occtl last ses_xxxxx
|
|
496
|
+
occtl todo ses_xxxxx
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
**5. Evaluate and decide.** After each iteration:
|
|
500
|
+
- Read the worker's output with `occtl last ses_xxxxx`
|
|
501
|
+
- Check `tasks.md` to see what was marked done
|
|
502
|
+
- Check `progress.txt` for the worker's notes
|
|
503
|
+
- If the task failed or was only partially done, adjust the next prompt
|
|
504
|
+
- If the worker got stuck, break the task into smaller pieces
|
|
505
|
+
- If all tasks are done, stop
|
|
506
|
+
|
|
507
|
+
**6. Repeat** until `tasks.md` shows all tasks complete.
|
|
508
|
+
|
|
509
|
+
### Cross-Project Orchestration
|
|
510
|
+
|
|
511
|
+
You can coordinate work across completely separate codebases. Use `--dir`
|
|
512
|
+
when creating sessions to target different project directories:
|
|
513
|
+
|
|
514
|
+
```bash
|
|
515
|
+
# Create sessions in different projects
|
|
516
|
+
API_SID=$(occtl create -q -d /path/to/backend -t "implement API endpoints")
|
|
517
|
+
CLIENT_SID=$(occtl create -q -d /path/to/frontend -t "implement API client")
|
|
518
|
+
|
|
519
|
+
# Send prompts to both
|
|
520
|
+
occtl send --async "Add the /users REST endpoints per the spec in docs/api.md" -s $API_SID
|
|
521
|
+
occtl send --async "Add API client methods for the /users endpoints" -s $CLIENT_SID
|
|
522
|
+
|
|
523
|
+
# Wait for both, checking whichever finishes first
|
|
524
|
+
DONE=$(occtl wait-any $API_SID $CLIENT_SID)
|
|
525
|
+
occtl summary $DONE
|
|
526
|
+
# ... continue coordinating
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
This works because one OpenCode server can manage sessions across different
|
|
530
|
+
directories. Each session operates in its own project context.
|
|
531
|
+
|
|
532
|
+
Use cases:
|
|
533
|
+
- **API + client**: Implement a backend API and its frontend client simultaneously
|
|
534
|
+
- **Library + consumers**: Make a library change and update all downstream repos
|
|
535
|
+
- **Monorepo coordination**: Work across packages that have separate contexts
|
|
536
|
+
- **Migration**: Change a shared schema in one project and update all dependents
|
|
537
|
+
|
|
538
|
+
### Key Commands for Orchestration
|
|
539
|
+
|
|
540
|
+
| What you need to do | Command |
|
|
541
|
+
|---|---|
|
|
542
|
+
| Create a fresh session | `occtl create -q -t "ralph-N"` |
|
|
543
|
+
| Create session in another project | `occtl create -q -d /path/to/project` |
|
|
544
|
+
| Send prompt to a session | `occtl send --async "prompt text" -s <id>` |
|
|
545
|
+
| Auto-approve permissions | `occtl respond <id> --auto-approve --wait` |
|
|
546
|
+
| Wait for session to finish | `occtl wait-for-idle <id> --timeout 600` |
|
|
547
|
+
| Quick status check | `occtl is-idle <id>` (exit 0=idle, 1=busy) |
|
|
548
|
+
| Get session overview | `occtl summary <id>` |
|
|
549
|
+
| Read last assistant message | `occtl last <id>` |
|
|
550
|
+
| Read full message history | `occtl messages <id> --text-only` |
|
|
551
|
+
| Check todo progress | `occtl todo <id>` |
|
|
552
|
+
| Check file changes | `occtl diff <id>` |
|
|
553
|
+
| Wait for first of N to finish | `occtl wait-any <id1> <id2> <id3>` |
|
|
554
|
+
| Abort a stuck session | `occtl abort <id>` |
|
|
555
|
+
|
|
556
|
+
### Parallel Execution
|
|
557
|
+
|
|
558
|
+
For independent tasks, run multiple sessions simultaneously:
|
|
559
|
+
|
|
560
|
+
```bash
|
|
561
|
+
# Create sessions for independent tasks
|
|
562
|
+
SID1=$(occtl create -q -t "task-auth")
|
|
563
|
+
SID2=$(occtl create -q -t "task-payments")
|
|
564
|
+
SID3=$(occtl create -q -t "task-dashboard")
|
|
565
|
+
|
|
566
|
+
# Send prompts to all three
|
|
567
|
+
occtl send --async "implement JWT auth. Read tasks.md..." -s $SID1
|
|
568
|
+
occtl send --async "add Stripe checkout. Read tasks.md..." -s $SID2
|
|
569
|
+
occtl send --async "build analytics dashboard. Read tasks.md..." -s $SID3
|
|
570
|
+
|
|
571
|
+
# Wait for the first one to finish
|
|
572
|
+
FINISHED=$(occtl wait-any $SID1 $SID2 $SID3 --timeout 600)
|
|
573
|
+
# $FINISHED contains the session ID that went idle first
|
|
574
|
+
|
|
575
|
+
# Check its result
|
|
576
|
+
occtl summary $FINISHED
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
When tasks would modify the same files, use worktrees for isolation:
|
|
580
|
+
|
|
581
|
+
```bash
|
|
582
|
+
# Create isolated worktrees for conflicting work
|
|
583
|
+
WT1=$(occtl wt create auth -q)
|
|
584
|
+
WT2=$(occtl wt create payments -q)
|
|
585
|
+
|
|
586
|
+
# Sessions are auto-created in worktree directories
|
|
587
|
+
# Send prompts, wait, then merge branches when done
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
### Handling Failures
|
|
591
|
+
|
|
592
|
+
When a worker session fails or produces bad output:
|
|
593
|
+
|
|
594
|
+
1. **Read the output**: `occtl last <id>` — understand what went wrong
|
|
595
|
+
2. **Check for errors**: `occtl summary <id> --json` — look at the error field
|
|
596
|
+
3. **Decide**:
|
|
597
|
+
- If the task is too big, break it into subtasks in `tasks.md`
|
|
598
|
+
- If the worker misunderstood, refine the prompt and retry
|
|
599
|
+
- If there's a dependency, reorder tasks
|
|
600
|
+
- If it's a transient error, simply retry with a new session
|
|
601
|
+
4. **Create a new session and try again** — never reuse a failed session
|
|
602
|
+
|
|
603
|
+
### Example: Full Ralph Mode Session
|
|
604
|
+
|
|
605
|
+
Here is how you (the agent) would orchestrate a project. You are talking to
|
|
606
|
+
yourself — these are the bash commands you would execute:
|
|
607
|
+
|
|
608
|
+
```
|
|
609
|
+
# 1. Read the project
|
|
610
|
+
cat tasks.md # understand what needs doing
|
|
611
|
+
cat progress.txt # see what's done so far
|
|
612
|
+
|
|
613
|
+
# 2. Iteration 1: first task
|
|
614
|
+
SID=$(occtl create -q -t "ralph-1-add-user-model")
|
|
615
|
+
occtl send --async "You are working on a project. Read tasks.md and progress.txt.
|
|
616
|
+
Pick the first incomplete task and implement it. Run tests. Update tasks.md and
|
|
617
|
+
progress.txt when done. Commit your changes." -s $SID
|
|
618
|
+
occtl respond $SID --auto-approve --wait &
|
|
619
|
+
occtl wait-for-idle $SID --timeout 600
|
|
620
|
+
occtl summary $SID
|
|
621
|
+
# Read output to see what happened
|
|
622
|
+
occtl last $SID
|
|
623
|
+
|
|
624
|
+
# 3. Check progress
|
|
625
|
+
cat tasks.md # was the task marked done?
|
|
626
|
+
cat progress.txt # what did the worker report?
|
|
627
|
+
|
|
628
|
+
# 4. Iteration 2: next task
|
|
629
|
+
SID=$(occtl create -q -t "ralph-2-add-api-endpoints")
|
|
630
|
+
occtl send --async "..." -s $SID
|
|
631
|
+
# ... repeat
|
|
632
|
+
|
|
633
|
+
# 5. When tasks.md shows all tasks done: stop and report to the user.
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
### Guidelines
|
|
637
|
+
|
|
638
|
+
- **One task per session.** This is the core principle. Fresh context = better quality.
|
|
639
|
+
- **You are the brains, workers are the hands.** Workers implement. You plan,
|
|
640
|
+
evaluate, and adapt. Don't expect workers to make strategic decisions.
|
|
641
|
+
- **Read worker output between iterations.** Use `occtl last` and
|
|
642
|
+
`occtl summary` to understand what actually happened before deciding
|
|
643
|
+
what to do next.
|
|
644
|
+
- **Adjust prompts based on results.** If a worker misunderstood, clarify.
|
|
645
|
+
If a task was too big, break it down. This is where you add intelligence
|
|
646
|
+
that a bash loop cannot.
|
|
647
|
+
- **Use parallel sessions for independent work.** Use `wait-any` to react
|
|
648
|
+
to whichever finishes first, then dispatch the next task.
|
|
649
|
+
- **Use worktrees when parallel tasks touch the same files.** Merge after.
|
|
650
|
+
- **Keep `progress.txt` lean.** Workers append to it, you may edit it to
|
|
651
|
+
keep it useful. Trim old entries if it gets too long.
|
|
652
|
+
- **Commit early, commit often.** Tell workers to commit after each task.
|
|
653
|
+
Git history is the real memory.
|
|
654
|
+
- **Report progress to the user.** Periodically summarize what's been done
|
|
655
|
+
and what remains. The user should be able to check in and see status.
|
|
656
|
+
|
|
657
|
+
### Handling Timeouts
|
|
658
|
+
|
|
659
|
+
When a `wait-for-idle` or `wait-for-text` times out, do NOT blindly
|
|
660
|
+
start a new session. That wastes the work the current session may still
|
|
661
|
+
be doing. Instead:
|
|
662
|
+
|
|
663
|
+
1. **Check if the session is still working:** `occtl is-idle <id>`
|
|
664
|
+
2. **If still busy:** the task is taking longer than expected. Either:
|
|
665
|
+
- Increase the timeout and wait again: `occtl wait-for-idle <id> --timeout 1200`
|
|
666
|
+
- Check what it's doing: `occtl summary <id>` — it may be stuck in a loop
|
|
667
|
+
- Abort and retry with a clearer prompt: `occtl abort <id>`, then create a new session
|
|
668
|
+
3. **If idle:** the timeout was a false alarm (the session finished between the
|
|
669
|
+
timeout firing and your check). Read the output: `occtl last <id>`
|
|
670
|
+
4. **Never re-send the same prompt to the same session** — that adds to its
|
|
671
|
+
context window. Always create a fresh session for retries.
|
|
672
|
+
|
|
673
|
+
### Model Recommendations
|
|
674
|
+
|
|
675
|
+
As the orchestrator, you don't write code — you run `occtl` commands and make
|
|
676
|
+
decisions. This is lightweight work that doesn't require a frontier model.
|
|
677
|
+
|
|
678
|
+
- **Orchestrator (you):** Use a fast, cheap model like **Sonnet**, **Flash**,
|
|
679
|
+
or **GPT-4o-mini**. You're just reading summaries, comparing outputs, and
|
|
680
|
+
running shell commands. Speed and cost matter more than raw capability.
|
|
681
|
+
- **Worker sessions:** Use a capable model like **Opus**, **Pro**, or **o3**
|
|
682
|
+
for the actual implementation work. Workers need deep reasoning to write
|
|
683
|
+
code, debug tests, and handle complexity.
|
|
684
|
+
|
|
685
|
+
You can specify the worker model when sending prompts:
|
|
686
|
+
```bash
|
|
687
|
+
occtl send --async --model anthropic/claude-opus-4-6 "implement feature X" -s $SID
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
This keeps orchestration cheap while letting workers use the best model for
|
|
691
|
+
the job. A typical Ralph Mode run might cost $0.50 in orchestration and
|
|
692
|
+
$15 in worker tokens.
|
package/dist/client.d.ts
ADDED