@scrylog/cli 0.1.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 (129) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +836 -0
  3. package/package.json +75 -0
  4. package/src/api/docs/sessions.keys.ts +6 -0
  5. package/src/api/docs/sessions.ts +81 -0
  6. package/src/api/docs/system.keys.ts +5 -0
  7. package/src/api/docs/system.ts +66 -0
  8. package/src/api/docs/usage.keys.ts +3 -0
  9. package/src/api/docs/usage.ts +24 -0
  10. package/src/api/docs/webhooks.keys.ts +5 -0
  11. package/src/api/docs/webhooks.ts +78 -0
  12. package/src/api/index.ts +18 -0
  13. package/src/api/lib/auth.ts +43 -0
  14. package/src/api/lib/errors.ts +28 -0
  15. package/src/api/lib/route.ts +18 -0
  16. package/src/api/models/claude.ts +4 -0
  17. package/src/api/models/codex.ts +4 -0
  18. package/src/api/models/opencode.ts +11 -0
  19. package/src/api/routes/sessions.ts +47 -0
  20. package/src/api/routes/system.ts +103 -0
  21. package/src/api/routes/usage.ts +15 -0
  22. package/src/api/routes/webhooks/claude.ts +161 -0
  23. package/src/api/routes/webhooks/codex.ts +175 -0
  24. package/src/api/routes/webhooks/opencode.ts +107 -0
  25. package/src/api/routes.ts +93 -0
  26. package/src/api/schemas/common.ts +21 -0
  27. package/src/api/schemas/sessions.ts +72 -0
  28. package/src/api/schemas/usage.ts +50 -0
  29. package/src/api/schemas/webhooks/claude.ts +32 -0
  30. package/src/api/schemas/webhooks/codex.ts +34 -0
  31. package/src/api/schemas/webhooks/opencode.ts +29 -0
  32. package/src/api/services/claude-session.ts +9 -0
  33. package/src/api/services/codex-session.ts +8 -0
  34. package/src/api/services/opencode-session.ts +73 -0
  35. package/src/classifier.ts +206 -0
  36. package/src/cli/commands.ts +498 -0
  37. package/src/cli/prompt.ts +44 -0
  38. package/src/daemon/cli.ts +27 -0
  39. package/src/daemon/collectors/claude/README.md +108 -0
  40. package/src/daemon/collectors/claude/collector.ts +413 -0
  41. package/src/daemon/collectors/claude/discovery.ts +148 -0
  42. package/src/daemon/collectors/claude/hooks.ts +181 -0
  43. package/src/daemon/collectors/claude/index.ts +8 -0
  44. package/src/daemon/collectors/claude/jsonl.ts +85 -0
  45. package/src/daemon/collectors/claude/transcript.ts +246 -0
  46. package/src/daemon/collectors/codex/README.md +147 -0
  47. package/src/daemon/collectors/codex/collector.ts +661 -0
  48. package/src/daemon/collectors/codex/discovery.ts +104 -0
  49. package/src/daemon/collectors/codex/hooks.ts +179 -0
  50. package/src/daemon/collectors/codex/index.ts +7 -0
  51. package/src/daemon/collectors/codex/jsonl.ts +108 -0
  52. package/src/daemon/collectors/codex/transcript.ts +299 -0
  53. package/src/daemon/collectors/git.ts +295 -0
  54. package/src/daemon/collectors/opencode/README.md +106 -0
  55. package/src/daemon/collectors/opencode/collector.ts +543 -0
  56. package/src/daemon/collectors/opencode/discovery.ts +257 -0
  57. package/src/daemon/collectors/opencode/index.ts +5 -0
  58. package/src/daemon/collectors/opencode/session-builder.ts +59 -0
  59. package/src/daemon/collectors/opencode-db.ts +282 -0
  60. package/src/daemon/collectors/process.ts +201 -0
  61. package/src/daemon/collectors/tmux/README.md +128 -0
  62. package/src/daemon/collectors/tmux/collector.ts +472 -0
  63. package/src/daemon/collectors/tmux/enrichment.ts +241 -0
  64. package/src/daemon/collectors/tmux/index.ts +4 -0
  65. package/src/daemon/collectors/tmux/parse.ts +128 -0
  66. package/src/daemon/collectors/usage.ts +193 -0
  67. package/src/daemon/index.ts +207 -0
  68. package/src/daemon/scheduler.ts +86 -0
  69. package/src/daemon/store.ts +535 -0
  70. package/src/detect.ts +143 -0
  71. package/src/hooks/claude.ts +596 -0
  72. package/src/hooks/codex.ts +517 -0
  73. package/src/legacy/classifier.ts +215 -0
  74. package/src/legacy/detect.ts +143 -0
  75. package/src/mcp/client-server.ts +21 -0
  76. package/src/mcp/http-handler.ts +126 -0
  77. package/src/mcp/index.ts +61 -0
  78. package/src/mcp/resources/config-current.ts +19 -0
  79. package/src/mcp/resources/index.ts +11 -0
  80. package/src/mcp/resources/sessions-active.ts +19 -0
  81. package/src/mcp/resources/sessions-all.ts +19 -0
  82. package/src/mcp/schemas/sessions.ts +3 -0
  83. package/src/mcp/server.ts +17 -0
  84. package/src/mcp/services/api-adapter.ts +48 -0
  85. package/src/mcp/services/data-source.ts +22 -0
  86. package/src/mcp/services/store-adapter.ts +40 -0
  87. package/src/mcp/tools/get-active-sessions.ts +16 -0
  88. package/src/mcp/tools/get-session-children.ts +24 -0
  89. package/src/mcp/tools/get-session-messages.ts +24 -0
  90. package/src/mcp/tools/get-session.ts +23 -0
  91. package/src/mcp/tools/index.ts +15 -0
  92. package/src/mcp/tools/list-sessions.ts +16 -0
  93. package/src/neo-blessed.d.ts +4 -0
  94. package/src/oc/index.ts +302 -0
  95. package/src/service/manager.ts +242 -0
  96. package/src/shared/config.ts +478 -0
  97. package/src/shared/ipc.ts +80 -0
  98. package/src/shared/logger.ts +248 -0
  99. package/src/shared/paths.ts +73 -0
  100. package/src/shared/platform.ts +110 -0
  101. package/src/shared/session-view.ts +241 -0
  102. package/src/shared/types.ts +299 -0
  103. package/src/shared/utils.ts +339 -0
  104. package/src/tui/app.ts +920 -0
  105. package/src/tui/client.ts +149 -0
  106. package/src/tui/index.ts +181 -0
  107. package/src/types.ts +113 -0
  108. package/src/usage/README.md +323 -0
  109. package/src/usage/api.ts +99 -0
  110. package/src/usage/client.ts +3 -0
  111. package/src/usage/clients/anthropic-oauth-usage.ts +178 -0
  112. package/src/usage/clients/anthropic-web-usage.ts +245 -0
  113. package/src/usage/clients/claude-cli-probe.ts +187 -0
  114. package/src/usage/clients/codex-oauth-usage.ts +113 -0
  115. package/src/usage/clients/opencode-go-usage.ts +441 -0
  116. package/src/usage/index.ts +19 -0
  117. package/src/usage/mappers.ts +273 -0
  118. package/src/usage/planner.ts +54 -0
  119. package/src/usage/providers/claude.ts +113 -0
  120. package/src/usage/providers/codex.ts +34 -0
  121. package/src/usage/providers/opencode-go.ts +37 -0
  122. package/src/usage/resolver.ts +4 -0
  123. package/src/usage/resolvers/browser-cookies.ts +198 -0
  124. package/src/usage/resolvers/claude-auth.ts +99 -0
  125. package/src/usage/resolvers/claude-cli.ts +24 -0
  126. package/src/usage/resolvers/claude-web.ts +16 -0
  127. package/src/usage/resolvers/codex-auth.ts +117 -0
  128. package/src/usage/resolvers/opencode-go-web.ts +14 -0
  129. package/src/usage/types.ts +190 -0
package/README.md ADDED
@@ -0,0 +1,836 @@
1
+ # scrylog
2
+
3
+ `scrylog` is a Bun-based terminal dashboard and daemon for monitoring AI coding sessions in `tmux` and as standalone processes.
4
+
5
+ It ships four commands:
6
+
7
+ | Command | Purpose |
8
+ | --- | --- |
9
+ | `scrylog` | TUI dashboard and operator CLI |
10
+ | `scrylogd` | Foreground daemon process |
11
+ | `scrylog-mcp` | stdio MCP server that proxies daemon data |
12
+ | `oc` | OpenCode launcher and attach helper |
13
+
14
+ ## Features
15
+
16
+ - `tmux` monitoring for OpenCode, Codex, Copilot, and shell panes
17
+ - OpenCode integration in `hooks` or `sse` mode
18
+ - Claude transcript collection
19
+ - Codex transcript collection and hook-based state tracking
20
+ - Local daemon with Unix socket IPC on macOS and Linux, TCP fallback on Windows
21
+ - Optional TCP REST API exposure (enabled by default on Windows)
22
+ - Optional MCP HTTP exposure with bearer token support
23
+ - User-service installation on macOS and Linux
24
+ - Interactive setup wizard and diagnostics
25
+
26
+ ## Requirements
27
+
28
+ - [Bun](https://bun.sh) `>= 1.3.0`
29
+ - `tmux` if you want `tmux` monitoring
30
+ - OpenCode if you want OpenCode monitoring
31
+ - `ps` on Unix or `wmic` on Windows for process auto-discovery
32
+
33
+ ## Platform Support
34
+
35
+ | Tier | Platform | Status | Notes |
36
+ | --- | --- | --- | --- |
37
+ | Tier 1 | macOS | Tested daily | Full feature set including Keychain OAuth and Safari cookies |
38
+ | Tier 2 | Linux / WSL 2 | Compatible | Claude OAuth via `~/.claude/.credentials.json`, Chrome/Chromium cookies, systemd service when available |
39
+ | Tier 3 | Windows (native) | Experimental / not recommended | TCP IPC, `wmic` process scan, degraded service status. Chrome cookie decryption not available (DPAPI not implemented). Primary use is ad-hoc debugging, not daily monitoring. |
40
+
41
+ ## WSL 2 Notes
42
+
43
+ - The daemon runs as a Linux process and uses the same paths as native Linux.
44
+ - Service installation requires systemd. If `systemctl --user` is not available, `scrylog daemon status` reports `platform: wsl` (WSL) or `platform: linux-no-systemd` (native Linux) with guidance.
45
+ - `tmux` monitoring works inside WSL but cannot see Windows-native processes.
46
+ - Browser cookie extraction works for Chrome/Chromium running inside WSL, not for the Windows host browser.
47
+
48
+ ## Linux Notes
49
+
50
+ - Linux without systemd (containers, minimal distros) reports `platform: linux-no-systemd` — the daemon runs but service management commands throw descriptive errors.
51
+ - OpenCode port discovery falls back to `/proc/<pid>/net/tcp` when `lsof` is unavailable.
52
+
53
+ ## Install
54
+
55
+ ### Main package
56
+
57
+ ```bash
58
+ bun install -g @scrylog/cli
59
+ ```
60
+
61
+ This installs the user-facing commands `scrylog`, `scrylogd`, `scrylog-mcp`, `scrylog-claude-hook`, `scrylog-codex-hook`, and `oc`.
62
+
63
+ ### OpenCode plugin for hooks mode
64
+
65
+ Install this only if you want `opencode.mode: "hooks"`:
66
+
67
+ ```bash
68
+ bun install -g @scrylog/opencode-plugin
69
+ ```
70
+
71
+ ### From source
72
+
73
+ ```bash
74
+ git clone https://github.com/scrylog/scrylog.git
75
+ cd scrylog
76
+ bun install
77
+ ```
78
+
79
+ ## Quick Start
80
+
81
+ ### Simplest setup
82
+
83
+ Run the setup wizard:
84
+
85
+ ```bash
86
+ scrylog setup
87
+ ```
88
+
89
+ The wizard can:
90
+
91
+ - create the config file
92
+ - optionally configure OpenCode
93
+ - enable or disable the TCP API
94
+ - enable or disable CORS for browser access
95
+ - enable or disable MCP HTTP
96
+ - generate an MCP bearer token
97
+ - install the daemon as a user service
98
+
99
+ Validated wizard paths:
100
+
101
+ - skip OpenCode entirely and keep defaults
102
+ - configure OpenCode `hooks` mode
103
+ - configure OpenCode `sse` mode with explicit instance URLs
104
+
105
+ ### Launch the dashboard
106
+
107
+ ```bash
108
+ scrylog
109
+ ```
110
+
111
+ If the daemon is not running, `scrylog` prints an error with the commands to start it.
112
+
113
+ ### Recommended local setup
114
+
115
+ For most users on macOS or Linux:
116
+
117
+ 1. Install `@scrylog/cli`.
118
+ 2. Run `scrylog setup`.
119
+ 3. Keep the TCP API disabled unless you explicitly want HTTP access from outside local IPC.
120
+ 4. Keep MCP HTTP disabled unless you explicitly need remote MCP over HTTP.
121
+ 5. Install the daemon as a user service from the wizard.
122
+ 6. Launch the dashboard with `scrylog`.
123
+
124
+ ## Operator CLI
125
+
126
+ `scrylog` is both the TUI entrypoint and the operator CLI.
127
+
128
+ ### TUI
129
+
130
+ ```bash
131
+ scrylog
132
+ scrylog --config ~/.config/scrylog/config.json
133
+ ```
134
+
135
+ Keyboard shortcuts:
136
+
137
+ | Key | Action |
138
+ | --- | --- |
139
+ | `↑` / `k` | Move selection up |
140
+ | `↓` / `j` | Move selection down |
141
+ | `Enter` | Open session detail |
142
+ | `t` | Attach to selected `tmux` session |
143
+ | `/` | Search |
144
+ | `f` | Cycle filters |
145
+ | `a` | Show actionable sessions only |
146
+ | `r` | Refresh now |
147
+ | `Esc` | Close detail |
148
+ | `q` / `Ctrl+C` | Quit |
149
+
150
+ ### Setup
151
+
152
+ ```bash
153
+ scrylog setup
154
+ ```
155
+
156
+ ### Daemon service management
157
+
158
+ ```bash
159
+ scrylog daemon install
160
+ scrylog daemon uninstall
161
+ scrylog daemon start
162
+ scrylog daemon stop
163
+ scrylog daemon restart
164
+ scrylog daemon status
165
+ ```
166
+
167
+ Supported service managers:
168
+
169
+ - macOS: `launchd` user agent
170
+ - Linux: `systemd --user`
171
+ - WSL without systemd: reported as `platform: wsl` with guidance
172
+ - Windows: reported as `platform: unsupported` — run `scrylogd` manually or use Task Scheduler
173
+
174
+ Typical service workflow:
175
+
176
+ ```bash
177
+ scrylog daemon install
178
+ scrylog daemon start
179
+ scrylog daemon status
180
+ ```
181
+
182
+ To stop automatic startup later:
183
+
184
+ ```bash
185
+ scrylog daemon stop
186
+ scrylog daemon uninstall
187
+ ```
188
+
189
+ ### Config commands
190
+
191
+ ```bash
192
+ scrylog config path
193
+ scrylog config show
194
+ ```
195
+
196
+ ### Token commands
197
+
198
+ ```bash
199
+ scrylog token generate
200
+ scrylog token rotate
201
+ scrylog token clear
202
+ ```
203
+
204
+ ### Diagnostics and logs
205
+
206
+ ```bash
207
+ scrylog doctor
208
+ scrylog logs
209
+ ```
210
+
211
+ ## Foreground Daemon
212
+
213
+ Use `scrylogd` when you want to run the daemon manually in the foreground:
214
+
215
+ ```bash
216
+ scrylogd
217
+ scrylogd --config ~/.config/scrylog/config.json
218
+ scrylogd --log-level debug
219
+ scrylogd --log-format json
220
+ scrylogd --no-log-file
221
+ ```
222
+
223
+ Use the foreground daemon mainly for:
224
+
225
+ - debugging startup issues
226
+ - verifying listener behavior manually
227
+ - local development
228
+
229
+ Logging options:
230
+
231
+ | Flag | Purpose |
232
+ | --- | --- |
233
+ | `--log-level debug|info|warn|error` | Override the configured minimum log level |
234
+ | `--log-format pretty|json` | Override stderr output format for this process |
235
+ | `--no-log-file` | Disable daemon JSONL file logging for this process |
236
+
237
+ For normal daily use on macOS and Linux, prefer `scrylog daemon install` so the daemon starts automatically with your user session.
238
+
239
+ ## Configuration
240
+
241
+ Config is loaded from the first path that exists:
242
+
243
+ 1. `--config <path>`
244
+ 2. `SCRYLOG_CONFIG`
245
+ 3. `~/.config/scrylog/config.json`
246
+ 4. `~/.scrylog.json`
247
+ 5. built-in defaults
248
+
249
+ Example config:
250
+
251
+ ```jsonc
252
+ {
253
+ "daemon": {
254
+ "pollIntervalMs": 10000,
255
+ "socketPath": null,
256
+ "commandTimeoutMs": 5000,
257
+ "networkTimeoutMs": 10000,
258
+ "logLevel": "info",
259
+ "logFormat": "auto",
260
+ "logFileEnabled": true,
261
+ "logFilePath": "~/.scrylog/logs/scrylogd.log",
262
+ "logFileMaxBytes": 5242880,
263
+ "logFileMaxFiles": 3
264
+ },
265
+ "api": {
266
+ "tcpEnabled": false,
267
+ "host": "127.0.0.1",
268
+ "port": 7788
269
+ },
270
+ "cors": {
271
+ "enabled": false,
272
+ "origins": [],
273
+ "methods": ["GET", "POST", "OPTIONS"],
274
+ "allowedHeaders": ["Content-Type", "Authorization"],
275
+ "exposedHeaders": [],
276
+ "credentials": false,
277
+ "maxAge": 600
278
+ },
279
+ "opencode": {
280
+ "mode": "hooks",
281
+ "instances": [],
282
+ "autoDiscover": true
283
+ },
284
+ "claude": {
285
+ "claudeDir": "/Users/you/.claude",
286
+ "hooksEnabled": false,
287
+ "hooksDir": "/tmp/scrylog-claude-hooks"
288
+ },
289
+ "codex": {
290
+ "codexDir": "/Users/you/.codex",
291
+ "hooksEnabled": false,
292
+ "hooksDir": "/tmp/scrylog-codex-hooks"
293
+ },
294
+ "tmux": {
295
+ "previewLines": 50,
296
+ "detailLines": 200
297
+ },
298
+ "tui": {
299
+ "refreshMs": 5000,
300
+ "showStandalone": true,
301
+ "usePushUpdates": true,
302
+ "standaloneMaxAgeHours": 6
303
+ },
304
+ "mcp": {
305
+ "stdioEnabled": true,
306
+ "httpEnabled": false,
307
+ "host": "127.0.0.1",
308
+ "port": 7789,
309
+ "bearerToken": null
310
+ },
311
+ "usage": {
312
+ "enabled": true,
313
+ "pollIntervalMs": 300000,
314
+ "providers": ["claude", "opencode-go", "codex"]
315
+ },
316
+ "retention": {
317
+ "maxSessions": 500,
318
+ "standaloneMaxAgeHours": 168,
319
+ "localCommandTtlHours": 72,
320
+ "cacheMaxEntries": 1000,
321
+ "transcriptMaxBytes": 10485760
322
+ }
323
+ }
324
+ ```
325
+
326
+ Notes:
327
+
328
+ - On macOS and Linux, local clients use the Unix socket even when `api.tcpEnabled` is `false`.
329
+ - `api.tcpEnabled` controls TCP exposure of the REST API, not local daemon IPC.
330
+ - `mcp.httpEnabled` controls the HTTP MCP listener.
331
+ - `scrylog-mcp` uses local daemon access and is separate from MCP HTTP.
332
+ - `cors.enabled` controls whether the API and MCP HTTP handlers include CORS headers. Enable it when consuming the API from a browser (e.g. a web dashboard).
333
+ - `cors.origins` accepts an array of allowed origins. Use `["*"]` to allow any origin.
334
+ - `daemon.logFormat: "auto"` uses pretty stderr output in a terminal and JSONL when stderr is not a TTY.
335
+ - `daemon.socketPath` overrides the local Unix socket on macOS/Linux. Leave it unset for the per-user default `/tmp/scrylog-<uid>.sock`.
336
+ - `daemon.commandTimeoutMs` bounds daemon-owned commands such as `ps`, `tmux`, `git`, `lsof`, and `pgrep`.
337
+ - `daemon.networkTimeoutMs` bounds daemon-owned usage/integration network requests.
338
+ - `usage.enabled: false` disables periodic Claude/OpenCode usage probes without disabling session monitoring.
339
+ - `retention` limits in-memory state. Active `working` and `waiting-input` sessions are preserved even when old.
340
+ - The daemon log file is always JSONL and rotates by size: `scrylogd.log`, `scrylogd.1.log`, `scrylogd.2.log` by default.
341
+ - The current CLI preserves an existing legacy config path when updating config, so older `~/.scrylog.json` users are not forced onto a new file immediately.
342
+
343
+ ### Long-Running Operation
344
+
345
+ `scrylogd` is a monitor for active and recent sessions, not a permanent historical archive. Defaults are tuned for unattended daemon usage:
346
+
347
+ | Setting | Default | Effect |
348
+ | --- | ---: | --- |
349
+ | `retention.maxSessions` | `500` | Prunes oldest inactive sessions above this count |
350
+ | `retention.standaloneMaxAgeHours` | `168` | Prunes inactive standalone sessions older than 7 days |
351
+ | `retention.cacheMaxEntries` | `1000` | Bounds internal path/project caches |
352
+ | `retention.transcriptMaxBytes` | `10485760` | Parses only a bounded tail for very large Claude transcripts |
353
+ | `daemon.commandTimeoutMs` | `5000` | Prevents external commands from blocking indefinitely |
354
+
355
+ Expected daemon RSS depends on active sessions and transcript size:
356
+
357
+ | Scenario | Expected RSS |
358
+ | --- | ---: |
359
+ | No active sessions | 35-70 MB |
360
+ | Normal local usage | 50-120 MB |
361
+ | Heavy tmux/Claude/OpenCode usage | 100-250 MB |
362
+
363
+ If you want longer history, increase `retention.maxSessions` or `retention.standaloneMaxAgeHours`. Setting age to `0` disables age-based pruning, but count-based pruning can still apply.
364
+
365
+ Run diagnostics after changing operational settings:
366
+
367
+ ```bash
368
+ scrylog doctor
369
+ ```
370
+
371
+ Doctor reports the effective socket path, log path, retention limits, timeout values, and whether usage collection is enabled.
372
+
373
+ ### Daemon Logs
374
+
375
+ `scrylogd` writes structured logs to stderr and, by default, to:
376
+
377
+ ```text
378
+ ~/.scrylog/logs/scrylogd.log
379
+ ```
380
+
381
+ The file format is JSONL for bug reports and tooling. Terminal stderr output defaults to pretty formatting when interactive.
382
+
383
+ Default file rotation keeps three files total:
384
+
385
+ | File | Purpose |
386
+ | --- | --- |
387
+ | `scrylogd.log` | Active log file |
388
+ | `scrylogd.1.log` | Previous active file |
389
+ | `scrylogd.2.log` | Oldest retained file |
390
+
391
+ Example JSONL entry:
392
+
393
+ ```json
394
+ {"ts":"2026-05-05T18:42:31.123Z","level":"info","source":"daemon","event":"daemon.started","msg":"Started"}
395
+ ```
396
+
397
+ Logs sanitize home-directory paths, bearer tokens, authorization values, and URL query strings before writing.
398
+
399
+ The daemon's own file logs are capped by `daemon.logFileMaxBytes * daemon.logFileMaxFiles` (15 MB by default). Stderr logs written by `systemd --user` or `launchd` are retained according to the operating system's service logging policy.
400
+
401
+ ### Exposure Recommendations
402
+
403
+ Recommended defaults for a local machine:
404
+
405
+ ```json
406
+ {
407
+ "api": {
408
+ "tcpEnabled": false
409
+ },
410
+ "cors": {
411
+ "enabled": false
412
+ },
413
+ "mcp": {
414
+ "httpEnabled": false
415
+ }
416
+ }
417
+ ```
418
+
419
+ Enable `api.tcpEnabled` only when you want TCP access to the REST API.
420
+
421
+ Enable `cors.enabled` when a browser-based client needs to consume the API directly.
422
+
423
+ Enable `mcp.httpEnabled` only when you want MCP over HTTP. If you enable it, also set or generate `mcp.bearerToken`.
424
+
425
+ ## OpenCode Integration
426
+
427
+ OpenCode setup is optional. If you skip it in `scrylog setup`, defaults remain unchanged until you configure it later.
428
+
429
+ `scrylog` supports two mutually exclusive OpenCode modes.
430
+
431
+ ### `hooks` mode
432
+
433
+ Recommended mode when you run OpenCode inside `tmux`.
434
+
435
+ Use it when you want:
436
+
437
+ - immediate session updates from OpenCode events
438
+ - permission prompt visibility
439
+ - the best available pane correlation in `tmux`
440
+
441
+ Requirements:
442
+
443
+ - `scrylog`
444
+ - `@scrylog/opencode-plugin`
445
+ - OpenCode config with the plugin enabled
446
+
447
+ Setup:
448
+
449
+ 1. Install the plugin.
450
+
451
+ ```bash
452
+ bun install -g @scrylog/opencode-plugin
453
+ ```
454
+
455
+ 2. Set `opencode.mode` to `hooks`.
456
+
457
+ 3. Add the plugin to `~/.config/opencode/opencode.json`:
458
+
459
+ ```json
460
+ {
461
+ "plugin": ["@scrylog/opencode-plugin"]
462
+ }
463
+ ```
464
+
465
+ 4. Start `scrylogd` or install the service.
466
+
467
+ Recommended command flow:
468
+
469
+ ```bash
470
+ scrylog setup
471
+ scrylog daemon install
472
+ scrylog daemon status
473
+ ```
474
+
475
+ What it allows:
476
+
477
+ - webhook-driven OpenCode updates
478
+ - better `tmux` correlation when the plugin writes `@opencode-session`
479
+ - child session visibility when OpenCode emits parent IDs
480
+
481
+ What it does not allow:
482
+
483
+ - heuristic `opencode attach` correlation inside `tmux`
484
+ - complete exact-session tracking without an upstream OpenCode signal
485
+
486
+ ### `sse` mode
487
+
488
+ Use this when OpenCode exposes an HTTP endpoint, such as:
489
+
490
+ - `opencode --port 4096`
491
+ - `opencode serve`
492
+ - `oc`
493
+
494
+ Setup:
495
+
496
+ 1. Set `opencode.mode` to `sse`.
497
+ 2. Optionally configure `opencode.instances`.
498
+ 3. Leave `opencode.autoDiscover` enabled if you want local process discovery.
499
+ 4. Start OpenCode with `opencode --port 4096`, `opencode serve`, or `oc`.
500
+
501
+ What it allows:
502
+
503
+ - standalone OpenCode monitoring through the SDK
504
+ - explicit instance URLs
505
+ - `oc` launch and attach workflows
506
+
507
+ What it does not allow:
508
+
509
+ - OpenCode `tmux` rows
510
+ - plugin-driven updates
511
+
512
+ Important behavior:
513
+
514
+ - in `sse` mode, OpenCode is shown as standalone only
515
+ - the daemon ignores webhook payloads from the plugin in `sse` mode
516
+
517
+ ## `oc`
518
+
519
+ `oc` is the OpenCode helper included in `scrylog`. It is mainly intended for `sse` mode.
520
+
521
+ ```bash
522
+ oc
523
+ oc --continue
524
+ OPENCODE_LOCAL_PORT=4097 oc
525
+ OPENCODE_HOST=mac-mini.my-tailnet.ts.net OPENCODE_LOCAL_PORT=4096 oc
526
+ ```
527
+
528
+ How it works:
529
+
530
+ 1. scans running processes for OpenCode instances exposing a port
531
+ 2. probes each candidate with `GET /global/health`
532
+ 3. does one of the following:
533
+ - no live instance: launches `opencode --port 4096`
534
+ - one live instance: runs `opencode attach <url>`
535
+ - multiple live instances: prompts you to choose one
536
+
537
+ Environment variables:
538
+
539
+ | Variable | Default | Purpose |
540
+ | --- | --- | --- |
541
+ | `OPENCODE_LOCAL_PORT` | `4096` | Force a specific port |
542
+ | `OPENCODE_HOST` | `127.0.0.1` | Force a specific host |
543
+
544
+ ## HTTP API
545
+
546
+ The daemon always exposes local IPC on Unix socket on macOS and Linux. The TCP HTTP API is optional.
547
+
548
+ Enable it with:
549
+
550
+ ```json
551
+ {
552
+ "api": {
553
+ "tcpEnabled": true,
554
+ "host": "127.0.0.1",
555
+ "port": 7788
556
+ }
557
+ }
558
+ ```
559
+
560
+ Endpoints:
561
+
562
+ | Method | Path | Returns |
563
+ | --- | --- | --- |
564
+ | `GET` | `/api/health` | daemon health, timestamps, collector status |
565
+ | `GET` | `/api/status` | visible counts, collector status, generated timestamp |
566
+ | `GET` | `/api/sessions` | visible session tree plus counts |
567
+ | `GET` | `/api/sessions/:id` | full session detail |
568
+ | `GET` | `/api/sessions/:id/children` | visible child sessions |
569
+ | `GET` | `/api/sessions/:id/messages` | recent messages when available |
570
+ | `GET` | `/api/config` | active config with sensitive fields redacted |
571
+ | `GET` | `/api/events` | SSE stream of store events |
572
+ | `POST` | `/api/webhook/opencode` | OpenCode plugin webhook |
573
+
574
+ All error responses follow a consistent format:
575
+
576
+ ```json
577
+ { "error": "Session 'abc' not found", "code": "NOT_FOUND" }
578
+ ```
579
+
580
+ Known codes: `NOT_FOUND`, `UNAUTHORIZED`, `VALIDATION_ERROR`, `INTERNAL_ERROR`.
581
+
582
+ Example:
583
+
584
+ ```bash
585
+ curl http://127.0.0.1:7788/api/health
586
+ curl http://127.0.0.1:7788/api/sessions
587
+ ```
588
+
589
+ ## MCP
590
+
591
+ ### stdio MCP
592
+
593
+ Use `scrylog-mcp` for local MCP clients:
594
+
595
+ ```bash
596
+ scrylog-mcp
597
+ ```
598
+
599
+ Example MCP client config:
600
+
601
+ ```json
602
+ {
603
+ "mcpServers": {
604
+ "scrylog": {
605
+ "command": "scrylog-mcp"
606
+ }
607
+ }
608
+ }
609
+ ```
610
+
611
+ Available tools:
612
+
613
+ - `list_sessions`
614
+ - `get_active_sessions`
615
+ - `get_session`
616
+ - `get_session_messages`
617
+ - `get_session_children`
618
+
619
+ Available resources:
620
+
621
+ - `sessions://all`
622
+ - `sessions://active`
623
+ - `config://current`
624
+
625
+ ### MCP HTTP
626
+
627
+ MCP HTTP is disabled by default.
628
+
629
+ Enable it with:
630
+
631
+ ```json
632
+ {
633
+ "mcp": {
634
+ "httpEnabled": true,
635
+ "host": "127.0.0.1",
636
+ "port": 7789,
637
+ "bearerToken": "your-secret-token"
638
+ }
639
+ }
640
+ ```
641
+
642
+ If `bearerToken` is set, clients must send:
643
+
644
+ - `Authorization: Bearer <token>`
645
+
646
+ For streamable HTTP clients, include:
647
+
648
+ - `Accept: application/json, text/event-stream`
649
+
650
+ The server uses stateful MCP HTTP sessions:
651
+
652
+ 1. send `initialize`
653
+ 2. read the `mcp-session-id` response header
654
+ 3. send `notifications/initialized` with the same `mcp-session-id`
655
+ 4. send later MCP requests with the same `mcp-session-id`
656
+
657
+ ### MCP HTTP Security
658
+
659
+ Generate a token from the operator CLI:
660
+
661
+ ```bash
662
+ scrylog token generate
663
+ ```
664
+
665
+ Rotate it later with:
666
+
667
+ ```bash
668
+ scrylog token rotate
669
+ ```
670
+
671
+ Clear it with:
672
+
673
+ ```bash
674
+ scrylog token clear
675
+ ```
676
+
677
+ ## Service Installation
678
+
679
+ You can keep the daemon running automatically with the operator CLI:
680
+
681
+ ```bash
682
+ scrylog daemon install
683
+ scrylog daemon start
684
+ scrylog daemon status
685
+ ```
686
+
687
+ macOS uses a LaunchAgent under `~/Library/LaunchAgents/`.
688
+
689
+ Linux uses `systemd --user` under `~/.config/systemd/user/`.
690
+
691
+ The service lifecycle was validated with:
692
+
693
+ - install
694
+ - start
695
+ - restart
696
+ - stop
697
+ - uninstall
698
+
699
+ If you want to inspect the current service state or listener reachability, run:
700
+
701
+ ```bash
702
+ scrylog daemon status
703
+ scrylog doctor
704
+ ```
705
+
706
+ ## Troubleshooting
707
+
708
+ ### `scrylog` cannot connect to the daemon
709
+
710
+ Start it manually:
711
+
712
+ ```bash
713
+ scrylogd --log-level debug
714
+ ```
715
+
716
+ Or inspect the service:
717
+
718
+ ```bash
719
+ scrylog daemon status
720
+ scrylog logs
721
+ ```
722
+
723
+ If you normally use the user service, also try:
724
+
725
+ ```bash
726
+ scrylog daemon restart
727
+ ```
728
+
729
+ ### OpenCode is missing in hooks mode
730
+
731
+ Check:
732
+
733
+ 1. `opencode.mode` is `hooks`
734
+ 2. `@scrylog/opencode-plugin` is installed
735
+ 3. OpenCode config includes `"plugin": ["@scrylog/opencode-plugin"]`
736
+ 4. the daemon is running
737
+
738
+ ### OpenCode is missing in sse mode
739
+
740
+ Check:
741
+
742
+ 1. `opencode.mode` is `sse`
743
+ 2. OpenCode is exposing a reachable HTTP endpoint
744
+ 3. `opencode.instances` is correct or `autoDiscover` is enabled
745
+ 4. `GET /global/health` succeeds on the OpenCode endpoint
746
+
747
+ ### MCP HTTP returns `401 Unauthorized`
748
+
749
+ Send the configured bearer token.
750
+
751
+ ### MCP HTTP returns `No valid session ID provided`
752
+
753
+ Start with `initialize`, then reuse the returned `mcp-session-id`.
754
+
755
+ ### I want a guided setup again
756
+
757
+ Run:
758
+
759
+ ```bash
760
+ scrylog setup
761
+ ```
762
+
763
+ ## Validated User Flows
764
+
765
+ These user-facing flows were exercised after implementation:
766
+
767
+ - operator CLI help and subcommands
768
+ - daemon foreground startup
769
+ - daemon user-service install, start, restart, stop, uninstall on macOS
770
+ - `scrylog` TUI launch and quit
771
+ - setup wizard skip, `hooks`, and `sse` flows
772
+ - MCP token generate, rotate, and clear
773
+ - TCP API enable and disable behavior
774
+ - MCP HTTP enable, disable, and bearer-token enforcement
775
+ - `scrylog-mcp` stdio startup and tool discovery
776
+
777
+ ## Development And Release
778
+
779
+ ### Development Hooks
780
+
781
+ When developing from this checkout, use local hook paths instead of the published package. This is only for local development and manual testing; normal users should follow the published package setup above.
782
+
783
+ Claude Code hook commands should point to this checkout:
784
+
785
+ ```text
786
+ bun run /Volumes/Files/Workspace/Projects/other/scrylog/src/hooks/claude.ts
787
+ ```
788
+
789
+ Use that command for every Claude hook event that `scrylog` tracks.
790
+
791
+ Codex hook commands should point to this checkout:
792
+
793
+ ```text
794
+ bun run /Volumes/Files/Workspace/Projects/other/scrylog/src/hooks/codex.ts
795
+ ```
796
+
797
+ Use that command for every Codex hook event that `scrylog` tracks.
798
+
799
+ For OpenCode local plugin testing, create or update:
800
+
801
+ ```text
802
+ ~/.config/opencode/plugins/scrylog.ts
803
+ ```
804
+
805
+ with:
806
+
807
+ ```ts
808
+ export { server } from "file:///Volumes/Files/Workspace/Projects/other/scrylog/packages/opencode-plugin/src/index.ts"
809
+ ```
810
+
811
+ For package usage, prefer the published plugin configuration:
812
+
813
+ ```json
814
+ {
815
+ "plugin": ["@scrylog/opencode-plugin"]
816
+ }
817
+ ```
818
+
819
+ Validation:
820
+
821
+ ```bash
822
+ bun run check-types
823
+ bun run test
824
+ ```
825
+
826
+ Publish-readiness checks:
827
+
828
+ ```bash
829
+ bun run release:check
830
+ ```
831
+
832
+ Public packages are versioned with Changesets and validated through Turborepo. The release workflow creates a version PR on `main`; merging that PR publishes `@scrylog/cli` and `@scrylog/opencode-plugin` to npm.
833
+
834
+ ## OpenSpec
835
+
836
+ Design and behavior artifacts live in `openspec/`.