claws-code 0.8.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.
Files changed (180) hide show
  1. package/.claude/commands/claws-auto.md +90 -0
  2. package/.claude/commands/claws-bin.md +28 -0
  3. package/.claude/commands/claws-cleanup.md +28 -0
  4. package/.claude/commands/claws-do.md +82 -0
  5. package/.claude/commands/claws-fix.md +40 -0
  6. package/.claude/commands/claws-goal.md +111 -0
  7. package/.claude/commands/claws-help.md +54 -0
  8. package/.claude/commands/claws-plan.md +103 -0
  9. package/.claude/commands/claws-report.md +29 -0
  10. package/.claude/commands/claws-status.md +37 -0
  11. package/.claude/commands/claws-update.md +32 -0
  12. package/.claude/commands/claws.md +64 -0
  13. package/.claude/rules/claws-default-behavior.md +76 -0
  14. package/.claude/settings.json +112 -0
  15. package/.claude/settings.local.json +19 -0
  16. package/.claude/skills/claws-auto-engine/SKILL.md +97 -0
  17. package/.claude/skills/claws-goal-tracker/SKILL.md +106 -0
  18. package/.claude/skills/claws-prompt-templates/SKILL.md +203 -0
  19. package/.claude/skills/claws-wave-lead/SKILL.md +126 -0
  20. package/.claude/skills/claws-wave-subworker/SKILL.md +60 -0
  21. package/CHANGELOG.md +1949 -0
  22. package/LICENSE +21 -0
  23. package/README.md +420 -0
  24. package/bin/cli.js +84 -0
  25. package/cli.js +223 -0
  26. package/docs/ARCHITECTURE.md +511 -0
  27. package/docs/event-protocol.md +588 -0
  28. package/docs/features.md +562 -0
  29. package/docs/guide.md +891 -0
  30. package/docs/index.html +716 -0
  31. package/docs/protocol.md +323 -0
  32. package/extension/.vscodeignore +15 -0
  33. package/extension/CHANGELOG.md +1906 -0
  34. package/extension/LICENSE +21 -0
  35. package/extension/README.md +137 -0
  36. package/extension/docs/features.md +424 -0
  37. package/extension/docs/protocol.md +197 -0
  38. package/extension/esbuild.mjs +25 -0
  39. package/extension/icon.png +0 -0
  40. package/extension/native/.metadata.json +10 -0
  41. package/extension/native/node-pty/LICENSE +69 -0
  42. package/extension/native/node-pty/README.md +165 -0
  43. package/extension/native/node-pty/lib/conpty_console_list_agent.js +16 -0
  44. package/extension/native/node-pty/lib/conpty_console_list_agent.js.map +1 -0
  45. package/extension/native/node-pty/lib/eventEmitter2.js +47 -0
  46. package/extension/native/node-pty/lib/eventEmitter2.js.map +1 -0
  47. package/extension/native/node-pty/lib/index.js +52 -0
  48. package/extension/native/node-pty/lib/index.js.map +1 -0
  49. package/extension/native/node-pty/lib/interfaces.js +7 -0
  50. package/extension/native/node-pty/lib/interfaces.js.map +1 -0
  51. package/extension/native/node-pty/lib/shared/conout.js +11 -0
  52. package/extension/native/node-pty/lib/shared/conout.js.map +1 -0
  53. package/extension/native/node-pty/lib/terminal.js +190 -0
  54. package/extension/native/node-pty/lib/terminal.js.map +1 -0
  55. package/extension/native/node-pty/lib/types.js +7 -0
  56. package/extension/native/node-pty/lib/types.js.map +1 -0
  57. package/extension/native/node-pty/lib/unixTerminal.js +346 -0
  58. package/extension/native/node-pty/lib/unixTerminal.js.map +1 -0
  59. package/extension/native/node-pty/lib/utils.js +39 -0
  60. package/extension/native/node-pty/lib/utils.js.map +1 -0
  61. package/extension/native/node-pty/lib/windowsConoutConnection.js +125 -0
  62. package/extension/native/node-pty/lib/windowsConoutConnection.js.map +1 -0
  63. package/extension/native/node-pty/lib/windowsPtyAgent.js +320 -0
  64. package/extension/native/node-pty/lib/windowsPtyAgent.js.map +1 -0
  65. package/extension/native/node-pty/lib/windowsTerminal.js +199 -0
  66. package/extension/native/node-pty/lib/windowsTerminal.js.map +1 -0
  67. package/extension/native/node-pty/lib/worker/conoutSocketWorker.js +22 -0
  68. package/extension/native/node-pty/lib/worker/conoutSocketWorker.js.map +1 -0
  69. package/extension/native/node-pty/package.json +64 -0
  70. package/extension/native/node-pty/prebuilds/darwin-arm64/pty.node +0 -0
  71. package/extension/native/node-pty/prebuilds/darwin-arm64/spawn-helper +0 -0
  72. package/extension/native/node-pty/prebuilds/darwin-x64/pty.node +0 -0
  73. package/extension/native/node-pty/prebuilds/darwin-x64/spawn-helper +0 -0
  74. package/extension/native/node-pty/prebuilds/win32-arm64/conpty/OpenConsole.exe +0 -0
  75. package/extension/native/node-pty/prebuilds/win32-arm64/conpty/conpty.dll +0 -0
  76. package/extension/native/node-pty/prebuilds/win32-arm64/conpty.node +0 -0
  77. package/extension/native/node-pty/prebuilds/win32-arm64/conpty_console_list.node +0 -0
  78. package/extension/native/node-pty/prebuilds/win32-arm64/pty.node +0 -0
  79. package/extension/native/node-pty/prebuilds/win32-arm64/winpty-agent.exe +0 -0
  80. package/extension/native/node-pty/prebuilds/win32-arm64/winpty.dll +0 -0
  81. package/extension/native/node-pty/prebuilds/win32-x64/conpty/OpenConsole.exe +0 -0
  82. package/extension/native/node-pty/prebuilds/win32-x64/conpty/conpty.dll +0 -0
  83. package/extension/native/node-pty/prebuilds/win32-x64/conpty.node +0 -0
  84. package/extension/native/node-pty/prebuilds/win32-x64/conpty_console_list.node +0 -0
  85. package/extension/native/node-pty/prebuilds/win32-x64/pty.node +0 -0
  86. package/extension/native/node-pty/prebuilds/win32-x64/winpty-agent.exe +0 -0
  87. package/extension/native/node-pty/prebuilds/win32-x64/winpty.dll +0 -0
  88. package/extension/package-lock.json +605 -0
  89. package/extension/package.json +343 -0
  90. package/extension/scripts/bundle-native.mjs +104 -0
  91. package/extension/scripts/deploy-dev.mjs +60 -0
  92. package/extension/src/ansi-strip.ts +52 -0
  93. package/extension/src/backends/vscode/claws-pty.ts +483 -0
  94. package/extension/src/backends/vscode/status-bar.ts +99 -0
  95. package/extension/src/backends/vscode/vscode-backend.ts +282 -0
  96. package/extension/src/capture-store.ts +125 -0
  97. package/extension/src/event-log.ts +629 -0
  98. package/extension/src/event-schemas.ts +478 -0
  99. package/extension/src/extension.js +492 -0
  100. package/extension/src/extension.ts +873 -0
  101. package/extension/src/lifecycle-engine.ts +60 -0
  102. package/extension/src/lifecycle-rules.ts +171 -0
  103. package/extension/src/lifecycle-store.ts +506 -0
  104. package/extension/src/peer-registry.ts +176 -0
  105. package/extension/src/pipeline-registry.ts +82 -0
  106. package/extension/src/platform.ts +64 -0
  107. package/extension/src/protocol.ts +532 -0
  108. package/extension/src/server-config.ts +98 -0
  109. package/extension/src/server.ts +2210 -0
  110. package/extension/src/task-registry.ts +51 -0
  111. package/extension/src/terminal-backend.ts +211 -0
  112. package/extension/src/terminal-manager.ts +395 -0
  113. package/extension/src/topic-registry.ts +70 -0
  114. package/extension/src/topic-utils.ts +46 -0
  115. package/extension/src/transport.ts +45 -0
  116. package/extension/src/uninstall-cleanup.ts +232 -0
  117. package/extension/src/wave-registry.ts +314 -0
  118. package/extension/src/websocket-transport.ts +153 -0
  119. package/extension/tsconfig.json +23 -0
  120. package/lib/capabilities.js +145 -0
  121. package/lib/dry-run.js +43 -0
  122. package/lib/install.js +1018 -0
  123. package/lib/mcp-setup.js +92 -0
  124. package/lib/platform.js +240 -0
  125. package/lib/preflight.js +152 -0
  126. package/lib/shell-hook.js +343 -0
  127. package/lib/uninstall.js +162 -0
  128. package/lib/verify.js +166 -0
  129. package/mcp_server.js +3529 -0
  130. package/package.json +48 -0
  131. package/rules/claws-default-behavior.md +72 -0
  132. package/scripts/_helpers/atomic-file.mjs +137 -0
  133. package/scripts/_helpers/fix-repair.js +64 -0
  134. package/scripts/_helpers/json-safe.mjs +218 -0
  135. package/scripts/bump-version.sh +84 -0
  136. package/scripts/codegen/gen-docs.mjs +61 -0
  137. package/scripts/codegen/gen-json-schema.mjs +62 -0
  138. package/scripts/codegen/gen-mcp-tools.mjs +358 -0
  139. package/scripts/codegen/gen-types.mjs +172 -0
  140. package/scripts/codegen/index.mjs +42 -0
  141. package/scripts/dev-hooks/check-extension-dirs.js +77 -0
  142. package/scripts/dev-hooks/check-open-claws-terminals.js +70 -0
  143. package/scripts/dev-hooks/check-stale-main.js +55 -0
  144. package/scripts/dev-hooks/check-tag-pushed.js +51 -0
  145. package/scripts/dev-hooks/check-tag-vs-main.js +56 -0
  146. package/scripts/dev-vsix-install.sh +60 -0
  147. package/scripts/fix.sh +702 -0
  148. package/scripts/gen-client-types.mjs +81 -0
  149. package/scripts/git-hooks/pre-commit +31 -0
  150. package/scripts/hooks/lifecycle-state.js +61 -0
  151. package/scripts/hooks/package.json +4 -0
  152. package/scripts/hooks/post-tool-use-claws.js +292 -0
  153. package/scripts/hooks/pre-bash-no-verify-block.js +72 -0
  154. package/scripts/hooks/pre-tool-use-claws.js +206 -0
  155. package/scripts/hooks/session-start-claws.js +97 -0
  156. package/scripts/hooks/stop-claws.js +88 -0
  157. package/scripts/inject-claude-md.js +205 -0
  158. package/scripts/inject-dev-hooks.js +96 -0
  159. package/scripts/inject-global-claude-md.js +140 -0
  160. package/scripts/inject-settings-hooks.js +370 -0
  161. package/scripts/install.ps1 +146 -0
  162. package/scripts/install.sh +1729 -0
  163. package/scripts/monitor-arm-watch.js +155 -0
  164. package/scripts/rebuild-node-pty.sh +245 -0
  165. package/scripts/report.sh +232 -0
  166. package/scripts/shell-hook.fish +164 -0
  167. package/scripts/shell-hook.ps1 +33 -0
  168. package/scripts/shell-hook.sh +232 -0
  169. package/scripts/stream-events.js +399 -0
  170. package/scripts/terminal-wrapper.sh +36 -0
  171. package/scripts/test-enforcement.sh +132 -0
  172. package/scripts/test-install.sh +174 -0
  173. package/scripts/test-installer-parity.sh +135 -0
  174. package/scripts/test-template-enforcement.sh +76 -0
  175. package/scripts/uninstall.sh +143 -0
  176. package/scripts/update.sh +337 -0
  177. package/scripts/verify-release.sh +323 -0
  178. package/scripts/verify-wrapped.sh +194 -0
  179. package/templates/CLAUDE.global.md +135 -0
  180. package/templates/CLAUDE.project.md +37 -0
package/docs/guide.md ADDED
@@ -0,0 +1,891 @@
1
+ # The Complete Claws Guide
2
+
3
+ A comprehensive course-level guide to mastering terminal control with Claws — from first install to production AI orchestration fleets.
4
+
5
+ > **Note:** The Python client shown in later chapters is **optional**. The MCP server (Node.js) provides terminal control natively in Claude Code with zero install. If you are using Claude Code, everything works through MCP tool calls and slash commands out of the box.
6
+
7
+ ---
8
+
9
+ ## Slash Commands (quick reference)
10
+
11
+ After install, these commands are available inside Claude Code sessions in your project:
12
+
13
+ | Command | What it does |
14
+ |---|---|
15
+ | `/claws` | Live status dashboard — forwards to `/claws-do` |
16
+ | `/claws-do <task>` | Universal verb: auto-classifies into shell / worker / fleet / wave |
17
+ | `/claws-plan` | Read task context, audit relevant code, produce a structured plan doc |
18
+ | `/claws-auto <goal>` | Autonomous orchestration loop — plan → dispatch waves → audit → repeat until goal met |
19
+ | `/claws-goal <goal>` | Break a high-level goal into subtasks, track progress, surface blockers |
20
+ | `/claws-status` | Live terminal + lifecycle state table |
21
+ | `/claws-help` | Full command and MCP tool reference |
22
+ | `/claws-cleanup` | Close all worker terminals you own |
23
+ | `/claws-fix` | Diagnose and auto-repair a broken Claws install |
24
+ | `/claws-report` | Bundle logs and diagnostics for a bug report |
25
+ | `/claws-update` | Pull the latest version |
26
+ | `/claws-bin [name]` | View or change the worker binary (for multi-account setups) |
27
+
28
+ **Typical flows:**
29
+
30
+ ```
31
+ # Run one thing
32
+ /claws-do run my tests
33
+
34
+ # Parallelize
35
+ /claws-do lint, test, and build in parallel
36
+
37
+ # Spawn a worker to fix code
38
+ /claws-do fix the auth bug in src/auth.ts
39
+
40
+ # Plan before acting
41
+ /claws-plan refactor the auth module
42
+
43
+ # Fully autonomous (best for well-defined goals)
44
+ /claws-auto add unit tests to every file in src/utils/
45
+
46
+ # Track a larger goal interactively
47
+ /claws-goal ship the v0.9 release
48
+ ```
49
+
50
+ Bug reports: https://github.com/neunaha/claws/issues
51
+
52
+ ---
53
+
54
+ ## Table of Contents
55
+
56
+ 1. [Chapter 1 — Getting Started](#chapter-1--getting-started)
57
+ 2. [Chapter 2 — Your First Terminal Control](#chapter-2--your-first-terminal-control)
58
+ 3. [Chapter 3 — Wrapped Terminals Deep Dive](#chapter-3--wrapped-terminals-deep-dive)
59
+ 4. [Chapter 4 — Command Execution Patterns](#chapter-4--command-execution-patterns)
60
+ 5. [Chapter 5 — The Safety Gate](#chapter-5--the-safety-gate)
61
+ 6. [Chapter 6 — Event Streaming and Monitoring](#chapter-6--event-streaming-and-monitoring)
62
+ 7. [Chapter 7 — AI Pair Programming](#chapter-7--ai-pair-programming)
63
+ 8. [Chapter 8 — Parallel Worker Fleets](#chapter-8--parallel-worker-fleets)
64
+ 9. [Chapter 9 — Advanced Patterns](#chapter-9--advanced-patterns)
65
+ 10. [Chapter 10 — Cross-Device Control](#chapter-10--cross-device-control)
66
+ 11. [Chapter 11 — Troubleshooting](#chapter-11--troubleshooting)
67
+ 12. [Chapter 12 — Architecture Internals](#chapter-12--architecture-internals)
68
+
69
+ ---
70
+
71
+ ## Chapter 1 — Getting Started
72
+
73
+ ### Prerequisites
74
+
75
+ - VS Code 1.93.0 or later
76
+ - macOS, Linux, or Windows (all three supported as of v0.8)
77
+ - Node.js 18+ (bundled with most systems; ships with VS Code)
78
+
79
+ ### Installation
80
+
81
+ **Three platform paths:**
82
+
83
+ ```bash
84
+ # Mac / Linux — npm (recommended)
85
+ npx claws-code install
86
+
87
+ # Mac / Linux — one-liner
88
+ curl -fsSL https://raw.githubusercontent.com/neunaha/claws/main/scripts/install.sh | bash
89
+
90
+ # Windows — PowerShell (run from your project root)
91
+ iwr https://raw.githubusercontent.com/neunaha/claws/main/scripts/install.ps1 | iex
92
+ ```
93
+
94
+ **VS Code Marketplace** (v0.8+): Extensions panel → search **Claws** → install `neunaha.claws`. Then `npx claws-code install` from your project root to add the project-local MCP config.
95
+
96
+ Run the installer **from the project root you want Claws in**. Each project gets its own independent Claws setup.
97
+
98
+ Open VS Code. Press `Cmd+Shift+P` → "Developer: Reload Window".
99
+
100
+ ### Verification
101
+
102
+ Open the Output panel (`Cmd+Shift+U`) and select "Claws" from the dropdown. You should see:
103
+
104
+ ```
105
+ [claws] activating
106
+ [claws] listening on /your/workspace/.claws/claws.sock
107
+ ```
108
+
109
+ If you see this, Claws is running. Try listing terminals:
110
+
111
+ ```bash
112
+ echo '{"id":1,"cmd":"list"}' | nc -U .claws/claws.sock
113
+ ```
114
+
115
+ You should get back a JSON response with all your open terminals.
116
+
117
+ ### Installing the Python Client
118
+
119
+ ```bash
120
+ cd claws
121
+ pip install -e clients/python
122
+ ```
123
+
124
+ Verify:
125
+
126
+ ```python
127
+ python3 -c "from claws import ClawsClient; print('OK')"
128
+ ```
129
+
130
+ ---
131
+
132
+ ## Chapter 2 — Your First Terminal Control
133
+
134
+ ### Listing Terminals
135
+
136
+ ```python
137
+ from claws import ClawsClient
138
+
139
+ client = ClawsClient(".claws/claws.sock")
140
+ for t in client.list():
141
+ print(f"{t.id} {t.name} pid={t.pid} active={t.active}")
142
+ ```
143
+
144
+ Every terminal gets a stable numeric ID. This ID persists for the terminal's lifetime — use it for all subsequent commands.
145
+
146
+ ### Creating a Terminal
147
+
148
+ ```python
149
+ term = client.create("my-first-terminal")
150
+ print(f"Created: id={term.id}")
151
+ ```
152
+
153
+ A new terminal tab appears in VS Code. You can see it in the terminal panel.
154
+
155
+ ### Sending Text
156
+
157
+ ```python
158
+ client.send(term.id, "echo hello from Claws")
159
+ ```
160
+
161
+ Switch to VS Code — you'll see the command typed and executed in the terminal you created.
162
+
163
+ ### Closing a Terminal
164
+
165
+ ```python
166
+ client.close(term.id)
167
+ ```
168
+
169
+ The terminal tab disappears from VS Code. Clean up after yourself.
170
+
171
+ ### The Full Loop
172
+
173
+ ```python
174
+ from claws import ClawsClient
175
+ import time
176
+
177
+ client = ClawsClient(".claws/claws.sock")
178
+
179
+ # Create
180
+ term = client.create("demo")
181
+ time.sleep(1) # let shell initialize
182
+
183
+ # Execute
184
+ result = client.exec(term.id, "echo hello && date && whoami")
185
+ print(f"exit {result.exit_code}")
186
+ print(result.output)
187
+
188
+ # Close
189
+ client.close(term.id)
190
+ ```
191
+
192
+ This is the fundamental pattern: create → use → close. Everything else builds on this.
193
+
194
+ ---
195
+
196
+ ## Chapter 3 — Wrapped Terminals Deep Dive
197
+
198
+ ### The Problem with Regular Terminals
199
+
200
+ When you `send` text into a regular terminal, it goes in — but nothing comes back through the Claws API. You're writing into a black box. The `exec` command works around this with file-based capture, but that only captures individual commands. You can't read an ongoing interactive session.
201
+
202
+ ### What Wrapping Does
203
+
204
+ A wrapped terminal runs your shell inside `script(1)`:
205
+
206
+ ```
207
+ Your Terminal Tab
208
+ └── script(1) — logs every byte to .claws/terminals/claws-N.log
209
+ └── /bin/zsh — your actual shell
210
+ └── whatever you run
211
+ ```
212
+
213
+ Every character that appears on screen is recorded in the log file. Claws can then read this file back with ANSI escapes stripped, giving you clean text.
214
+
215
+ ### Creating a Wrapped Terminal
216
+
217
+ ```python
218
+ term = client.create("worker", wrapped=True)
219
+ print(f"Log: {term.log_path}")
220
+ # Log: /your/workspace/.claws/terminals/claws-5.log
221
+ ```
222
+
223
+ Or from the VS Code UI: click the dropdown arrow next to `+` in the terminal panel → "Claws Wrapped Terminal".
224
+
225
+ ### Reading the Log
226
+
227
+ ```python
228
+ import time
229
+
230
+ # Send some commands
231
+ client.send(term.id, "ls -la")
232
+ time.sleep(1)
233
+ client.send(term.id, "git status")
234
+ time.sleep(1)
235
+
236
+ # Read back everything
237
+ log = client.read_log(term.id, lines=30)
238
+ print(log)
239
+ ```
240
+
241
+ Output (ANSI-stripped):
242
+
243
+ ```
244
+ $ ls -la
245
+ total 96
246
+ drwxr-xr-x 15 user staff 480 Apr 18 01:00 .
247
+ -rw-r--r-- 1 user staff 9067 Apr 18 00:30 CLAUDE.md
248
+ ...
249
+ $ git status
250
+ On branch main
251
+ nothing to commit, working tree clean
252
+ $
253
+ ```
254
+
255
+ ### Incremental Tailing
256
+
257
+ For real-time monitoring, use offset-based reading:
258
+
259
+ ```python
260
+ cursor = 0
261
+ while True:
262
+ # This is the raw socket approach; the Python client wraps this
263
+ resp = client._send({
264
+ "cmd": "readLog",
265
+ "id": term.id,
266
+ "offset": cursor,
267
+ "strip": True,
268
+ })
269
+ if resp["nextOffset"] > cursor:
270
+ new_text = resp["bytes"]
271
+ print(new_text, end="")
272
+ cursor = resp["nextOffset"]
273
+ time.sleep(1)
274
+ ```
275
+
276
+ ### Reading TUI Sessions
277
+
278
+ The real power of wrapped terminals: reading interactive programs that shell integration can't capture.
279
+
280
+ ```python
281
+ # Launch Claude Code in a wrapped terminal
282
+ term = client.create("ai-session", wrapped=True)
283
+ time.sleep(2)
284
+ client.send(term.id, "claude")
285
+ time.sleep(5)
286
+
287
+ # Read the Claude Code welcome screen
288
+ log = client.read_log(term.id, lines=30)
289
+ print(log)
290
+ # Shows: Claude Code banner, model info, session state
291
+ ```
292
+
293
+ This works for vim, htop, python3 REPL, node REPL, irb — anything that renders to a terminal.
294
+
295
+ ### Log Buffering
296
+
297
+ `script(1)` buffers output before writing to disk (~1-2 second delay). This is intentional — aggressive flushing (`-F` flag) corrupts Ink-based TUI renderers like Claude Code. Accept the delay; it doesn't affect usability.
298
+
299
+ ### Detecting Wrapped Terminals
300
+
301
+ ```python
302
+ for t in client.list():
303
+ if t.log_path:
304
+ print(f"{t.id} {t.name} — WRAPPED (log: {t.log_path})")
305
+ else:
306
+ print(f"{t.id} {t.name} — regular")
307
+ ```
308
+
309
+ ### Environment Variable
310
+
311
+ Inside a wrapped terminal, `CLAWS_WRAPPED=1` is set in the environment. Your scripts can detect this:
312
+
313
+ ```bash
314
+ if [ "${CLAWS_WRAPPED:-}" = "1" ]; then
315
+ echo "I'm in a Claws-wrapped terminal"
316
+ fi
317
+ ```
318
+
319
+ ---
320
+
321
+ ## Chapter 4 — Command Execution Patterns
322
+
323
+ ### exec — Structured Output
324
+
325
+ `exec` is for when you need the output back programmatically:
326
+
327
+ ```python
328
+ result = client.exec(term.id, "python3 -c 'import sys; print(sys.version)'")
329
+ assert result.exit_code == 0
330
+ print(result.output) # "3.11.9 (main, ...)\n"
331
+ ```
332
+
333
+ ### send — Fire and Forget
334
+
335
+ `send` is for when you just need text to arrive at the terminal's input:
336
+
337
+ ```python
338
+ client.send(term.id, "npm start")
339
+ # No output captured — use readLog to see what happened
340
+ ```
341
+
342
+ ### When to Use Which
343
+
344
+ | Scenario | Use |
345
+ |---|---|
346
+ | Run a command, check the output | `exec` |
347
+ | Type into a shell prompt | `send` |
348
+ | Type into a TUI (vim, claude, REPL) | `send` |
349
+ | Send Ctrl+C / Ctrl+D | `send` with `\x03` / `\x04` |
350
+ | Run a long-running process | `send` + monitor with `readLog` |
351
+ | Run a command in a specific directory | `exec` with `cd /path && cmd` |
352
+
353
+ ### Multi-line Commands
354
+
355
+ Claws auto-wraps multi-line text in bracketed paste mode:
356
+
357
+ ```python
358
+ script = """
359
+ for i in range(5):
360
+ print(f"Line {i}")
361
+ """
362
+ client.send(term.id, f"python3 -c '{script}'")
363
+ ```
364
+
365
+ The shell receives this as one atomic paste, not 3 separate Enter presses.
366
+
367
+ ### Timeouts
368
+
369
+ `exec` waits up to 180 seconds by default. For longer commands:
370
+
371
+ ```python
372
+ result = client.exec(term.id, "npm run build", timeout_ms=600000) # 10 minutes
373
+ ```
374
+
375
+ If it times out, you get a `ClawsError` with whatever partial output was captured.
376
+
377
+ ### Auto-Created Exec Terminal
378
+
379
+ If you call `exec` without a terminal ID, Claws creates (or reuses) a terminal named `claws-work`:
380
+
381
+ ```python
382
+ # No need to create a terminal first
383
+ result = client.exec(None, "echo quick one-off")
384
+ ```
385
+
386
+ ---
387
+
388
+ ## Chapter 5 — The Safety Gate
389
+
390
+ ### What It Protects Against
391
+
392
+ Imagine you have a terminal running vim. You send `ls -la` via Claws, intending it as a shell command. Instead, vim receives "ls -la" as normal-mode keystrokes — jumping to line `l`, then `s` enters insert mode, then `- la` types literal characters. Your file is corrupted.
393
+
394
+ The safety gate prevents this by checking what's actually running in the terminal before sending.
395
+
396
+ ### How It Works
397
+
398
+ 1. Claws reads the terminal's shell PID from VS Code
399
+ 2. Runs `pgrep -P <pid>` to find the foreground child process
400
+ 3. If the child is a known shell (bash, zsh, fish, sh, dash, ksh) → safe
401
+ 4. If it's anything else (claude, vim, less, python3, node) → warning
402
+
403
+ ### Default Behavior (warn + proceed)
404
+
405
+ ```python
406
+ # Terminal is running vim
407
+ client.send(term.id, "hello")
408
+ # Response includes: [warning: foreground is 'vim' (not a shell)]
409
+ # But the text IS sent — Claws doesn't block by default
410
+ ```
411
+
412
+ ### Strict Mode (block)
413
+
414
+ ```python
415
+ # Block sends into non-shell TUIs
416
+ client._send({
417
+ "cmd": "send",
418
+ "id": term.id,
419
+ "text": "hello",
420
+ "strict": True,
421
+ })
422
+ # Returns: {"ok": false, "error": "BLOCKED (strict): ..."}
423
+ ```
424
+
425
+ ### Why Warn Instead of Block
426
+
427
+ The primary use case for Claws is AI pair programming — where you **intentionally** send prompts into Claude Code's TUI. Blocking that defeats the purpose. The warning is for accidental sends; intentional TUI interaction should proceed.
428
+
429
+ ---
430
+
431
+ ## Chapter 6 — Event Streaming and Monitoring
432
+
433
+ ### poll — Shell Integration Events
434
+
435
+ VS Code's shell integration fires an event when a command finishes. Claws captures these in a ring buffer:
436
+
437
+ ```python
438
+ events, cursor = client.poll(since=0)
439
+ for e in events:
440
+ print(f"[{e['terminalName']}] $ {e['commandLine']}")
441
+ print(f" exit={e['exitCode']}, {len(e['output'])} bytes output")
442
+ ```
443
+
444
+ Save the cursor and pass it next time to get only new events:
445
+
446
+ ```python
447
+ cursor = 0
448
+ while True:
449
+ events, cursor = client.poll(since=cursor)
450
+ for e in events:
451
+ print(f"[{e['terminalName']}] {e['commandLine']} → {e['exitCode']}")
452
+ time.sleep(2)
453
+ ```
454
+
455
+ ### poll Limitations
456
+
457
+ - Requires VS Code shell integration to be active
458
+ - Doesn't fire in wrapped terminals (shell integration doesn't inject through script(1))
459
+ - Doesn't fire for TUI sessions
460
+ - Ring buffer holds last 500 events — old events are dropped
461
+
462
+ For reliable observation, use `readLog` on wrapped terminals instead.
463
+
464
+ ### The Monitor Pattern
465
+
466
+ The preferred observation pattern in v0.8+ is the **bus-stream** approach — subscribe to the claws/2 event bus directly using `stream-events.js`. This is SIGPIPE-safe and sub-100ms latency, unlike `tail -F | grep` which gets killed by VS Code's process supervisor within ~30 s of inactivity.
467
+
468
+ Every `claws_worker` spawn response includes a ready-to-use `monitor_arm_command`. Copy it into a `Monitor(...)` call:
469
+
470
+ ```
471
+ Monitor(
472
+ command="node /path/to/.claws-bin/scripts/stream-events.js --wait <correlation_id>",
473
+ description="claws monitor | term=<id>",
474
+ timeout_ms=600000,
475
+ persistent=false
476
+ )
477
+ ```
478
+
479
+ `stream-events.js --wait <correlation_id>` filters the bus stream to one worker and self-exits on `system.worker.completed`. Use the exact `monitor_arm_command` string from the spawn response — it has the right paths and correlation ID pre-filled.
480
+
481
+ **Legacy `tail -F` pattern** (still works, but avoid for long-running observation):
482
+
483
+ ```bash
484
+ tail -F .claws/terminals/claws-5.log \
485
+ | perl -pe 'BEGIN{$|=1} s/\e\[[0-9;?]*[a-zA-Z]//g' \
486
+ | grep --line-buffered -E 'Error|DONE|FAIL|exit'
487
+ ```
488
+
489
+ ---
490
+
491
+ ## Chapter 7 — AI Pair Programming
492
+
493
+ This is what Claws was built for. One AI session controls multiple terminal sessions — spawning workers, sending mission prompts, monitoring progress, reacting to errors.
494
+
495
+ ### The Basic Pattern
496
+
497
+ ```python
498
+ from claws import ClawsClient
499
+ import time
500
+
501
+ client = ClawsClient(".claws/claws.sock")
502
+
503
+ # 1. Create a wrapped terminal
504
+ worker = client.create("ai-worker", wrapped=True)
505
+ time.sleep(1.5)
506
+
507
+ # 2. Launch Claude Code inside it
508
+ client.send(worker.id, "claude --dangerously-skip-permissions")
509
+ time.sleep(5)
510
+
511
+ # 3. Send a mission prompt
512
+ mission = (
513
+ "fix the failing test in src/utils.test.ts. "
514
+ "read the error first, then fix the implementation. "
515
+ "commit when green. print MISSION_COMPLETE when done."
516
+ )
517
+ client.send(worker.id, mission)
518
+ time.sleep(0.3)
519
+ # Submit with raw CR (Claude Code needs explicit Enter)
520
+ client.send(worker.id, "\r", newline=False)
521
+
522
+ # 4. Monitor progress
523
+ while True:
524
+ log = client.read_log(worker.id, lines=20)
525
+ if "MISSION_COMPLETE" in log:
526
+ break
527
+ if "Error" in log:
528
+ print("Worker hit an error — check the log")
529
+ time.sleep(10)
530
+
531
+ # 5. Read final state
532
+ full_log = client.read_log(worker.id, lines=200)
533
+ print(full_log)
534
+
535
+ # 6. Clean up
536
+ client.close(worker.id)
537
+ ```
538
+
539
+ ### Writing Good Mission Prompts
540
+
541
+ A mission prompt should have:
542
+
543
+ 1. **Context** — what the worker needs to know
544
+ 2. **Objective** — one clear sentence
545
+ 3. **Steps** — numbered if order matters
546
+ 4. **Constraints** — explicit prohibitions
547
+ 5. **Completion marker** — `MISSION_COMPLETE` for machine parsing
548
+ 6. **Imperative close** — "go."
549
+
550
+ ```
551
+ fix the type error in pipeline/committee.py line 234.
552
+ read the error, trace the root cause, apply a minimal fix.
553
+ do not refactor surrounding code. do not commit.
554
+ print MISSION_COMPLETE when the fix is verified. go.
555
+ ```
556
+
557
+ ### Sending Follow-ups
558
+
559
+ After reading the worker's state, you can send a follow-up prompt:
560
+
561
+ ```python
562
+ # Read what the worker did
563
+ log = client.read_log(worker.id, lines=30)
564
+
565
+ # If it's stuck, redirect
566
+ if "I need clarification" in log:
567
+ client.send(worker.id, "use option B. the database is PostgreSQL 15.")
568
+ client.send(worker.id, "\r", newline=False)
569
+ ```
570
+
571
+ This is true pair programming — read, think, respond.
572
+
573
+ ---
574
+
575
+ ## Chapter 8 — Parallel Worker Fleets
576
+
577
+ ### Spawning Multiple Workers
578
+
579
+ ```python
580
+ tasks = {
581
+ "lint": "npm run lint",
582
+ "test": "npm test",
583
+ "typecheck": "npx tsc --noEmit",
584
+ }
585
+
586
+ workers = {}
587
+ for name, cmd in tasks.items():
588
+ term = client.create(f"worker-{name}", wrapped=True)
589
+ workers[name] = term
590
+ time.sleep(0.5) # stagger to avoid shell init race
591
+
592
+ # Fire all commands
593
+ for name, cmd in tasks.items():
594
+ client.send(workers[name].id, cmd)
595
+
596
+ # Wait and collect
597
+ import time
598
+ time.sleep(15)
599
+ for name, term in workers.items():
600
+ log = client.read_log(term.id, lines=10)
601
+ passed = "PASS" in log or "0 errors" in log
602
+ status = "PASS" if passed else "FAIL"
603
+ print(f"{status} {name}")
604
+ client.close(term.id)
605
+ ```
606
+
607
+ ### AI Agent Fleet
608
+
609
+ Spawn multiple Claude Code sessions with different missions:
610
+
611
+ ```python
612
+ missions = [
613
+ ("audit-a", "analyze pipeline latency from artifact mtimes. write to /tmp/latency.md"),
614
+ ("audit-b", "analyze token consumption from budget_ledger.jsonl. write to /tmp/tokens.md"),
615
+ ("audit-c", "analyze runbook dependencies and parallelism. write to /tmp/critpath.md"),
616
+ ]
617
+
618
+ workers = {}
619
+ for name, mission in missions:
620
+ term = client.create(name, wrapped=True)
621
+ time.sleep(1.5)
622
+ client.send(term.id, "claude --dangerously-skip-permissions")
623
+ time.sleep(5)
624
+ client.send(term.id, mission + " print MISSION_COMPLETE when done. go.")
625
+ time.sleep(0.3)
626
+ client.send(term.id, "\r", newline=False)
627
+ workers[name] = term
628
+
629
+ # Monitor all workers
630
+ while workers:
631
+ for name, term in list(workers.items()):
632
+ log = client.read_log(term.id, lines=5)
633
+ if "MISSION_COMPLETE" in log:
634
+ print(f"{name} — DONE")
635
+ client.close(term.id)
636
+ del workers[name]
637
+ time.sleep(15)
638
+
639
+ print("All workers complete.")
640
+ ```
641
+
642
+ ### Auto-Cleanup
643
+
644
+ Every terminal you create must be closed. Implement a cleanup handler:
645
+
646
+ ```python
647
+ import atexit
648
+
649
+ created_terminals = []
650
+
651
+ def create_worker(name, **kwargs):
652
+ term = client.create(name, **kwargs)
653
+ created_terminals.append(term.id)
654
+ return term
655
+
656
+ @atexit.register
657
+ def cleanup():
658
+ for tid in created_terminals:
659
+ try:
660
+ client.close(tid)
661
+ except:
662
+ pass
663
+ ```
664
+
665
+ ---
666
+
667
+ ## Chapter 9 — Advanced Patterns
668
+
669
+ ### Pattern: Orchestrator with Monitor
670
+
671
+ Use `tail -F` as a real-time event source instead of polling:
672
+
673
+ ```bash
674
+ # Terminal 1: monitor
675
+ tail -F .claws/terminals/claws-5.log \
676
+ | perl -pe 'BEGIN{$|=1} s/\e\[[0-9;?]*[a-zA-Z]//g; s/\e\][^\a]*\a//g; s/[\x00-\x08\x0b-\x1a\x1c-\x1f\x7f]//g' \
677
+ | grep --line-buffered -E '(Read|Write|Edit|Bash)\([^)]{3,}|MISSION_COMPLETE|Error|Traceback'
678
+ ```
679
+
680
+ This gives you a filtered stream of tool calls and errors from the worker, arriving in real-time.
681
+
682
+ ### Pattern: Conditional Branching
683
+
684
+ Read the worker's state and make decisions:
685
+
686
+ ```python
687
+ log = client.read_log(worker.id, lines=20)
688
+
689
+ if "test failed" in log.lower():
690
+ client.send(worker.id, "revert the last change and try approach B instead")
691
+ elif "permission denied" in log.lower():
692
+ client.send(worker.id, "use sudo for that command")
693
+ elif "MISSION_COMPLETE" in log:
694
+ print("Success!")
695
+ client.close(worker.id)
696
+ else:
697
+ print("Still working...")
698
+ ```
699
+
700
+ ### Pattern: Pipeline Stages
701
+
702
+ Chain workers — output of one feeds the next:
703
+
704
+ ```python
705
+ # Stage 1: analyze
706
+ analyzer = client.create("stage-1-analyze", wrapped=True)
707
+ client.send(analyzer.id, "python3 analyze.py > /tmp/analysis.json")
708
+ time.sleep(10)
709
+ client.close(analyzer.id)
710
+
711
+ # Stage 2: transform (reads stage 1 output)
712
+ transformer = client.create("stage-2-transform", wrapped=True)
713
+ client.send(transformer.id, "python3 transform.py /tmp/analysis.json > /tmp/result.json")
714
+ time.sleep(10)
715
+ client.close(transformer.id)
716
+ ```
717
+
718
+ ### Pattern: Watchdog
719
+
720
+ Monitor a long-running process and restart if it crashes:
721
+
722
+ ```python
723
+ import time
724
+
725
+ while True:
726
+ term = client.create("server", wrapped=True)
727
+ client.send(term.id, "npm start")
728
+
729
+ while True:
730
+ time.sleep(30)
731
+ log = client.read_log(term.id, lines=5)
732
+ if "EADDRINUSE" in log or "FATAL" in log or "crashed" in log.lower():
733
+ print("Server crashed — restarting...")
734
+ client.close(term.id)
735
+ time.sleep(2)
736
+ break
737
+ ```
738
+
739
+ ### Pattern: Multi-Language Raw Socket
740
+
741
+ You don't need Python. Any language works:
742
+
743
+ **bash:**
744
+ ```bash
745
+ echo '{"id":1,"cmd":"list"}' | nc -U .claws/claws.sock
746
+ ```
747
+
748
+ **Node.js:**
749
+ ```javascript
750
+ const net = require('net');
751
+ const sock = net.createConnection('.claws/claws.sock');
752
+ sock.write('{"id":1,"cmd":"list"}\n');
753
+ sock.on('data', d => console.log(JSON.parse(d.toString())));
754
+ ```
755
+
756
+ **Go:**
757
+ ```go
758
+ conn, _ := net.Dial("unix", ".claws/claws.sock")
759
+ conn.Write([]byte(`{"id":1,"cmd":"list"}` + "\n"))
760
+ buf := make([]byte, 65536)
761
+ n, _ := conn.Read(buf)
762
+ fmt.Println(string(buf[:n]))
763
+ ```
764
+
765
+ ---
766
+
767
+ ## Chapter 10 — Cross-Device Control
768
+
769
+ ### Today: SSH Tunnel
770
+
771
+ You can control a remote VS Code instance right now using SSH port forwarding:
772
+
773
+ ```bash
774
+ # On your local machine — forward the remote socket
775
+ ssh -L /tmp/remote-claws.sock:/remote/workspace/.claws/claws.sock user@remote-host
776
+
777
+ # Connect to the forwarded socket
778
+ from claws import ClawsClient
779
+ client = ClawsClient("/tmp/remote-claws.sock")
780
+ terminals = client.list() # shows remote VS Code terminals
781
+ ```
782
+
783
+ ### Planned: WebSocket Transport
784
+
785
+ v0.3 will add WebSocket alongside the Unix socket:
786
+
787
+ 1. Enable in VS Code settings: `"claws.enableWebSocket": true`
788
+ 2. Claws starts a WebSocket server on port 9876
789
+ 3. Connect from anywhere: `ws://remote-host:9876`
790
+ 4. Token auth required (token shown in Output panel)
791
+ 5. TLS support for encrypted connections
792
+
793
+ ### Planned: Team Configuration
794
+
795
+ Named devices with per-terminal access control:
796
+
797
+ ```json
798
+ {
799
+ "team": {
800
+ "dev-laptop": { "role": "controller", "access": "read-write" },
801
+ "build-server": { "role": "worker", "access": "read-write" },
802
+ "dashboard": { "role": "observer", "access": "read-only" }
803
+ }
804
+ }
805
+ ```
806
+
807
+ ---
808
+
809
+ ## Chapter 11 — Troubleshooting
810
+
811
+ ### "No socket found"
812
+
813
+ The extension isn't running. Check:
814
+ 1. Is VS Code open?
815
+ 2. Is the Claws extension installed? (`Cmd+Shift+X` → search "Claws")
816
+ 3. Did you reload? (`Cmd+Shift+P` → "Developer: Reload Window")
817
+ 4. Check the Output panel → "Claws" for errors
818
+
819
+ ### "Terminal not wrapped"
820
+
821
+ You called `readLog` on a regular terminal. Only terminals created with `wrapped: true` have pty logs. Create a new one:
822
+
823
+ ```python
824
+ term = client.create("name", wrapped=True)
825
+ ```
826
+
827
+ ### Wrapped terminal shows visual glitches
828
+
829
+ You're probably running a TUI (Claude Code, vim) and the wrapper script has the `-F` flag enabled. Remove it — default `script` buffering is correct for TUI sessions. Check `scripts/terminal-wrapper.sh`.
830
+
831
+ ### Multi-line send fragments into separate commands
832
+
833
+ This happens when bracketed paste isn't working. Claws auto-wraps multi-line text in `\x1b[200~...\x1b[201~`. If your shell doesn't support bracketed paste, each `\n` becomes a separate Enter. Fix: upgrade your shell or send the text as a file: `cat /tmp/prompt.txt`.
834
+
835
+ ### exec times out but the command is running
836
+
837
+ `exec` polls for a `.done` marker file. If the command runs but doesn't produce the marker (e.g., it runs in a subshell that doesn't inherit the wrapper), the marker never appears. Check `/tmp/claws-exec/` for orphaned `.out` files.
838
+
839
+ ### Socket permission denied
840
+
841
+ The socket is created with `chmod 600`. Only the user who started VS Code can connect. If you're running your script as a different user, that's the problem.
842
+
843
+ ---
844
+
845
+ ## Chapter 12 — Architecture Internals
846
+
847
+ ### Extension Lifecycle
848
+
849
+ 1. VS Code loads the extension on `onStartupFinished`
850
+ 2. `activate()` runs:
851
+ - Creates the output channel
852
+ - Attaches shell integration listeners
853
+ - Starts the socket server
854
+ - Registers the terminal profile provider
855
+ - Registers commands
856
+ 3. On each request: parse JSON → dispatch to handler → write response
857
+ 4. `deactivate()` closes the server and cleans up the socket file
858
+
859
+ ### Socket Server
860
+
861
+ - Standard Node.js `net.createServer`
862
+ - Each connection gets its own buffer for newline-delimited framing
863
+ - Requests are handled asynchronously — multiple concurrent requests work
864
+ - Socket file created with `chmod 600` for security
865
+
866
+ ### Terminal ID Assignment
867
+
868
+ - `WeakMap<Terminal, string>` maps VS Code Terminal objects to stable string IDs
869
+ - IDs are monotonically increasing integers as strings ("1", "2", "3", ...)
870
+ - The WeakMap ensures IDs are garbage-collected when terminals are disposed
871
+ - For wrapped terminals created via the profile provider, the ID is pre-reserved before the Terminal object exists
872
+
873
+ ### Wrapped Terminal Mechanics
874
+
875
+ 1. `createTerminal({ shellPath: "scripts/terminal-wrapper.sh", env: { CLAWS_TERM_LOG: path } })`
876
+ 2. The wrapper script runs: `exec script -q "$CLAWS_TERM_LOG" /bin/zsh -il`
877
+ 3. `script(1)` creates a pseudo-terminal pair and records all output to the log file
878
+ 4. The user's shell runs inside this pseudo-terminal — completely transparent
879
+ 5. `readLog` opens the log file, reads a byte range, strips ANSI via regex, returns clean text
880
+
881
+ ### ANSI Stripping
882
+
883
+ Two regex patterns applied sequentially:
884
+ - CSI sequences: `[\x1b\x9b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-PRZcf-ntqry=><]`
885
+ - Control characters: `[\x00-\x08\x0b-\x1a\x1c-\x1f\x7f]`
886
+
887
+ This removes colors, cursor positioning, screen clearing, and control chars. Newlines (`\n`) and tabs (`\t`) are preserved.
888
+
889
+ ### Configuration Resolution
890
+
891
+ Settings are read via `vscode.workspace.getConfiguration('claws')` on every request. No caching — changes take effect immediately without reload. Defaults are hardcoded constants that match `package.json` defaults.