@calltelemetry/openclaw-linear 0.5.2 → 0.6.1

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 (37) hide show
  1. package/README.md +359 -195
  2. package/index.ts +10 -10
  3. package/openclaw.plugin.json +4 -1
  4. package/package.json +9 -2
  5. package/src/agent/agent.test.ts +127 -0
  6. package/src/{agent.ts → agent/agent.ts} +84 -7
  7. package/src/agent/watchdog.test.ts +266 -0
  8. package/src/agent/watchdog.ts +176 -0
  9. package/src/{cli.ts → infra/cli.ts} +32 -5
  10. package/src/{codex-worktree.ts → infra/codex-worktree.ts} +1 -1
  11. package/src/infra/doctor.test.ts +399 -0
  12. package/src/infra/doctor.ts +781 -0
  13. package/src/infra/notify.test.ts +169 -0
  14. package/src/{notify.ts → infra/notify.ts} +6 -1
  15. package/src/pipeline/active-session.test.ts +154 -0
  16. package/src/pipeline/artifacts.test.ts +383 -0
  17. package/src/{artifacts.ts → pipeline/artifacts.ts} +9 -1
  18. package/src/{dispatch-service.ts → pipeline/dispatch-service.ts} +1 -1
  19. package/src/pipeline/dispatch-state.test.ts +382 -0
  20. package/src/pipeline/pipeline.test.ts +226 -0
  21. package/src/{pipeline.ts → pipeline/pipeline.ts} +61 -7
  22. package/src/{tier-assess.ts → pipeline/tier-assess.ts} +1 -1
  23. package/src/{webhook.test.ts → pipeline/webhook.test.ts} +1 -1
  24. package/src/{webhook.ts → pipeline/webhook.ts} +8 -8
  25. package/src/{claude-tool.ts → tools/claude-tool.ts} +31 -5
  26. package/src/{cli-shared.ts → tools/cli-shared.ts} +5 -4
  27. package/src/{code-tool.ts → tools/code-tool.ts} +2 -2
  28. package/src/{codex-tool.ts → tools/codex-tool.ts} +31 -5
  29. package/src/{gemini-tool.ts → tools/gemini-tool.ts} +31 -5
  30. package/src/{orchestration-tools.ts → tools/orchestration-tools.ts} +1 -1
  31. package/src/client.ts +0 -94
  32. /package/src/{auth.ts → api/auth.ts} +0 -0
  33. /package/src/{linear-api.ts → api/linear-api.ts} +0 -0
  34. /package/src/{oauth-callback.ts → api/oauth-callback.ts} +0 -0
  35. /package/src/{active-session.ts → pipeline/active-session.ts} +0 -0
  36. /package/src/{dispatch-state.ts → pipeline/dispatch-state.ts} +0 -0
  37. /package/src/{tools.ts → tools/tools.ts} +0 -0
package/README.md CHANGED
@@ -1,153 +1,212 @@
1
1
  # @calltelemetry/openclaw-linear
2
2
 
3
- An OpenClaw plugin that connects your Linear workspace to AI agents. Issues get triaged automatically, agents respond to @mentions, and a worker-audit pipeline runs when you assign work to the agent.
3
+ [![OpenClaw](https://img.shields.io/badge/OpenClaw-v2026.2+-blue)](https://github.com/calltelemetry/openclaw)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
5
+
6
+ An OpenClaw plugin that connects Linear to AI agents. Issues get triaged automatically, agents respond to `@mentions`, and a worker-audit pipeline runs when you assign work -- with an inactivity watchdog that kills and respawns stuck sessions.
7
+
8
+ ---
9
+
10
+ ## Table of Contents
11
+
12
+ - [Features](#features)
13
+ - [How It Works](#how-it-works)
14
+ - [Architecture](#architecture)
15
+ - [Project Layout](#project-layout)
16
+ - [Getting Started](#getting-started)
17
+ - [Usage](#usage)
18
+ - [Configuration](#configuration)
19
+ - [Prompt Customization](#prompt-customization)
20
+ - [Notifications](#notifications)
21
+ - [Coding Tool](#coding-tool-code_run)
22
+ - [Inactivity Watchdog](#inactivity-watchdog)
23
+ - [CLI Reference](#cli-reference)
24
+ - [Troubleshooting](#troubleshooting)
25
+ - [License](#license)
26
+
27
+ ---
4
28
 
5
29
  ## Features
6
30
 
7
- - **Auto-triage** -- New issues get story point estimates, labels, and priority automatically
8
- - **@mention routing** -- `@qa`, `@infra`, `@docs` in comments route to specialized agents
9
- - **Worker-audit pipeline** -- Assign an issue and a worker implements it, then an independent auditor verifies the work against the issue's definition of done
10
- - **Hard-enforced audit** -- The audit triggers automatically in plugin code, not as an LLM decision. Workers cannot self-certify completion.
11
- - **Branded replies** -- Each agent posts with its own name and avatar in Linear
12
- - **Real-time progress** -- Agent activity (thinking, acting, responding) shows in Linear's UI
13
- - **Unified `code_run` tool** -- One tool, three coding CLI backends (Codex, Claude Code, Gemini CLI), configurable per agent
14
- - **Issue management via `linearis`** -- Agents use the `linearis` CLI to update status, close issues, add comments, and more
15
- - **Customizable prompts** -- Worker, audit, and rework prompts live in `prompts.yaml`, editable without rebuilding
16
- - **Discord notifications** -- Optional dispatch lifecycle notifications to a Discord channel
31
+ | Feature | Description |
32
+ |---------|-------------|
33
+ | **Auto-triage** | New issues get story point estimates, labels, and priority automatically |
34
+ | **@mention routing** | `@qa`, `@infra`, `@docs` in comments route to specialized agents |
35
+ | **Worker-audit pipeline** | Assign an issue and a worker implements it, then an independent auditor verifies |
36
+ | **Hard-enforced audit** | Audit triggers in plugin code, not as an LLM decision. Workers cannot self-certify. |
37
+ | **Inactivity watchdog** | Kills agent sessions with no I/O, retries once, escalates on double failure |
38
+ | **Branded replies** | Each agent posts with its own name and avatar in Linear |
39
+ | **Real-time progress** | Agent activity (thinking, acting, responding) streams to Linear's UI |
40
+ | **Unified `code_run`** | One tool, three backends (Codex, Claude Code, Gemini), configurable per agent |
41
+ | **Issue management** | Agents use `linearis` CLI to update status, close issues, add comments |
42
+ | **Customizable prompts** | `prompts.yaml` -- edit worker, audit, and rework prompts without rebuilding |
43
+ | **Discord notifications** | Dispatch lifecycle events posted to a Discord channel |
44
+ | **Artifact logging** | Every dispatch writes structured logs to `.claw/` in the worktree |
45
+
46
+ ---
47
+
48
+ ## How It Works
49
+
50
+ ```mermaid
51
+ sequenceDiagram
52
+ participant You
53
+ participant Linear
54
+ participant Plugin
55
+ participant Agents
56
+
57
+ You->>Linear: Create issue
58
+ Linear->>Plugin: Webhook (Issue.create)
59
+ Plugin->>Agents: Triage agent
60
+ Agents-->>Plugin: Estimate + labels
61
+ Plugin-->>Linear: Update issue
62
+ Plugin-->>Linear: Post assessment
63
+
64
+ You->>Linear: Assign to agent
65
+ Linear->>Plugin: Webhook (Issue.update)
66
+ Plugin->>Agents: Worker agent
67
+ Agents-->>Linear: Streaming status
68
+ Plugin->>Agents: Audit agent (automatic)
69
+ Agents-->>Plugin: JSON verdict
70
+ Plugin-->>Linear: Result comment
71
+
72
+ You->>Linear: Comment "@qa review"
73
+ Linear->>Plugin: Webhook (Comment)
74
+ Plugin->>Agents: QA agent
75
+ Agents-->>Plugin: Response
76
+ Plugin-->>Linear: Branded comment
77
+ ```
78
+
79
+ ---
17
80
 
18
81
  ## Architecture
19
82
 
20
83
  ### Dispatch Pipeline (v2)
21
84
 
22
- When an issue is assigned to the agent, the plugin runs a multi-stage pipeline with hard-enforced audit:
85
+ When an issue is assigned, the plugin runs a multi-stage pipeline:
23
86
 
24
- ```
25
- Issue Assigned
26
- |
27
- v
28
- +-----------------+
29
- | DISPATCH | Tier assessment, worktree creation,
30
- | | dispatch state registration
31
- +-----------------+
32
- |
33
- v
34
- +-----------------+
35
- | WORKER | Plans approach, implements solution,
36
- | (sub-agent) | posts summary comment on the issue.
37
- | | CANNOT mark issue as Done.
38
- +-----------------+
39
- |
40
- | (plugin code -- automatic, not LLM-mediated)
41
- v
42
- +-----------------+
43
- | AUDIT | Independent auditor reads issue body
44
- | (sub-agent) | (source of truth), verifies criteria,
45
- | | runs tests, returns JSON verdict.
46
- +-----------------+
47
- |
48
- v
49
- +-----------------+
50
- | VERDICT | Plugin code processes the verdict:
51
- | (plugin code) | PASS --> done + notify
52
- | | FAIL <= max --> rework (attempt++)
53
- | | FAIL > max --> stuck + escalate
54
- +-----------------+
87
+ ```mermaid
88
+ flowchart TD
89
+ A[Issue Assigned] --> B["**DISPATCH**<br/>Tier assessment, worktree creation,<br/>state registration"]
90
+ B --> C["**WORKER** *(sub-agent)*<br/>Plans + implements solution.<br/>Posts summary comment.<br/>CANNOT mark issue as Done."]
91
+ C -->|"plugin code — automatic,<br/>not LLM-mediated"| D["**AUDIT** *(sub-agent)*<br/>Independent auditor reads issue body,<br/>verifies criteria, runs tests,<br/>returns JSON verdict."]
92
+ D --> E["**VERDICT** *(plugin code)*"]
93
+ E -->|PASS| F["Done + notify"]
94
+ E -->|"FAIL ≤ max"| G["Rework (attempt++)"]
95
+ G --> C
96
+ E -->|"FAIL > max"| H["Stuck + escalate"]
55
97
  ```
56
98
 
57
- **What's hard-enforced vs. LLM-mediated:**
99
+ ### Hard-Enforced vs. LLM-Mediated
58
100
 
59
101
  | Layer | Mechanism | Can be skipped? |
60
102
  |-------|-----------|-----------------|
61
103
  | Worker spawn | Plugin code (`runAgent`) | No |
62
104
  | Audit trigger | Plugin code (fires after worker completes) | No |
63
105
  | Verdict processing | Plugin code (pass/fail/escalate) | No |
64
- | Worker implementation | LLM-mediated (the agent decides how to code) | N/A |
65
- | Audit evaluation | LLM-mediated (the agent decides if criteria are met) | N/A |
106
+ | Inactivity watchdog | Plugin code (timer-based kill + retry) | No |
107
+ | Worker implementation | LLM-mediated (agent decides how to code) | N/A |
108
+ | Audit evaluation | LLM-mediated (agent decides if criteria are met) | N/A |
66
109
 
67
110
  ### State Machine
68
111
 
69
- ```
70
- DISPATCHED --> WORKING --> AUDITING --> DONE
71
- ^ |
72
- | FAIL ---+ (attempt++ if <= max)
73
- +------------+ (re-enter WORKING)
74
- |
75
- (attempt > max) --> STUCK
112
+ ```mermaid
113
+ stateDiagram-v2
114
+ [*] --> DISPATCHED
115
+ DISPATCHED --> WORKING
116
+ WORKING --> AUDITING
117
+ AUDITING --> DONE
118
+ AUDITING --> WORKING : FAIL (attempt++)
119
+ WORKING --> STUCK : watchdog kill 2x
120
+ AUDITING --> STUCK : attempt > max
76
121
  ```
77
122
 
78
- All state transitions use compare-and-swap (CAS) to prevent races from duplicate webhooks or concurrent events. `dispatch-state.json` is the canonical source of truth; Linear labels are derived side effects.
123
+ All transitions use compare-and-swap (CAS) to prevent races. `dispatch-state.json` is the canonical source of truth.
79
124
 
80
- ### Webhook Flow
125
+ ### Webhook Event Router
81
126
 
82
- ```
83
- Linear OpenClaw Gateway AI Agents
84
- | | |
85
- | Webhook (issue created) | |
86
- | -----------------------> | |
87
- | | Dispatch triage agent |
88
- | | ----------------------> |
89
- | | |
90
- | | Estimate + labels |
91
- | | <---------------------- |
92
- | Update issue | |
93
- | <----------------------- | |
94
- | Post assessment comment | |
95
- | <----------------------- | |
127
+ ```mermaid
128
+ flowchart TD
129
+ A["POST /linear/webhook"] --> B{"Event Type"}
130
+ B --> C["AgentSessionEvent.created → Dispatch pipeline"]
131
+ B --> D["AgentSessionEvent.prompted → Resume session"]
132
+ B --> E["Comment.create → @mention routing"]
133
+ B --> F["Issue.create → Auto-triage"]
134
+ B --> G["Issue.update → Dispatch if assigned"]
135
+ B --> H["AppUserNotification → Direct response"]
96
136
  ```
97
137
 
98
- ```
99
- Linear OpenClaw Gateway AI Agents
100
- | | |
101
- | "@qa check this" | |
102
- | -----------------------> | |
103
- | | Route to QA agent |
104
- | | ----------------------> |
105
- | | |
106
- | | Response |
107
- | | <---------------------- |
108
- | Comment from "QA" | |
109
- | <----------------------- | |
110
- ```
138
+ All handlers respond `200 OK` within 5 seconds (Linear requirement), then process asynchronously.
111
139
 
112
140
  ### Two Webhook Systems
113
141
 
114
142
  Linear delivers events through two separate webhook paths:
115
143
 
116
- 1. **Workspace webhook** (Settings > API > Webhooks) -- handles Comment, Issue, and User events
117
- 2. **OAuth app webhook** (Settings > API > Applications > your app) -- handles `AgentSessionEvent` (created/prompted)
144
+ 1. **Workspace webhook** (Settings > API > Webhooks) -- Comment, Issue, User events
145
+ 2. **OAuth app webhook** (Settings > API > Applications) -- `AgentSessionEvent` (created/prompted)
118
146
 
119
- Both must point to the same URL: `https://<your-domain>/linear/webhook`
147
+ Both must point to: `https://<your-domain>/linear/webhook`
120
148
 
121
- ### Source Layout
149
+ ### Deduplication
122
150
 
123
- ```
124
- index.ts Plugin entry point, agent_end hook, notifier setup
125
- prompts.yaml Externalized worker/audit/rework prompt templates
126
- src/
127
- webhook.ts Webhook handler -- routes events to agents, dispatches pipeline
128
- pipeline.ts v2 pipeline: spawnWorker, triggerAudit, processVerdict
129
- dispatch-state.ts File-backed state with CAS transitions, session map, idempotency
130
- dispatch-service.ts Background service -- stale detection, recovery, cleanup
131
- notify.ts Notification provider (Discord + noop fallback)
132
- agent.ts Agent execution wrapper (embedded runner + subprocess fallback)
133
- active-session.ts In-process session registry (issueId -> session)
134
- tier-assess.ts Issue complexity assessment (junior/medior/senior)
135
-
136
- code-tool.ts Unified code_run tool -- dispatches to configured backend
137
- cli-shared.ts Shared helpers for CLI tools (buildLinearApi, resolveSession)
138
- codex-tool.ts Codex CLI runner (JSONL stream -> Linear activities)
139
- claude-tool.ts Claude Code CLI runner (JSONL stream -> Linear activities)
140
- gemini-tool.ts Gemini CLI runner (JSONL stream -> Linear activities)
141
- coding-tools.json Backend config (default tool, per-agent overrides, aliases)
142
-
143
- tools.ts Tool registration (code_run + orchestration)
144
- orchestration-tools.ts spawn_agent / ask_agent for multi-agent delegation
145
- linear-api.ts Linear GraphQL API client, token resolution, activity streaming
146
- auth.ts OAuth token management and profile storage
147
- oauth-callback.ts OAuth callback handler
148
- cli.ts CLI subcommands (auth, status, worktrees, prompts)
149
- codex-worktree.ts Git worktree management for isolated runs
150
- ```
151
+ A 60-second sliding window prevents double-handling:
152
+
153
+ | Key Pattern | Prevents |
154
+ |---|---|
155
+ | `session:{id}` | Same session processed by both Issue.update and AgentSessionEvent |
156
+ | `comment:{id}` | Same comment webhook delivered twice |
157
+ | `assigned:{issueId}:{viewerId}` | Rapid re-assignment events |
158
+ | `issue-create:{id}` | Duplicate Issue.create webhooks |
159
+
160
+ ---
161
+
162
+ ## Project Layout
163
+
164
+ ```
165
+ openclaw-linear/
166
+ |-- index.ts Plugin entry point, route/hook/service registration
167
+ |-- openclaw.plugin.json Plugin metadata and config schema
168
+ |-- prompts.yaml Externalized worker/audit/rework prompt templates
169
+ |-- coding-tools.json Backend config (default tool, per-agent overrides)
170
+ |-- package.json
171
+ |-- README.md
172
+ |-- docs/
173
+ | |-- architecture.md Internal architecture reference
174
+ | +-- troubleshooting.md Diagnostic commands and common issues
175
+ +-- src/
176
+ |-- pipeline/ Core dispatch lifecycle
177
+ | |-- webhook.ts Event router -- 6 webhook handlers, dispatch logic
178
+ | |-- pipeline.ts v2 pipeline: spawnWorker, triggerAudit, processVerdict
179
+ | |-- dispatch-state.ts File-backed state, CAS transitions, session mapping
180
+ | |-- dispatch-service.ts Background monitor: stale detection, recovery, cleanup
181
+ | |-- active-session.ts In-memory session registry (issueId -> session)
182
+ | |-- tier-assess.ts Issue complexity assessment (junior/medior/senior)
183
+ | +-- artifacts.ts .claw/ directory: manifest, logs, verdicts, summaries
184
+ |
185
+ |-- agent/ Agent execution & monitoring
186
+ | |-- agent.ts Embedded runner + subprocess fallback, retry on watchdog kill
187
+ | +-- watchdog.ts InactivityWatchdog class + per-agent config resolver
188
+ |
189
+ |-- tools/ Tool registration & CLI backends
190
+ | |-- tools.ts Tool registration (code_run + orchestration)
191
+ | |-- code-tool.ts Unified code_run dispatcher
192
+ | |-- cli-shared.ts Shared helpers (buildLinearApi, resolveSession, defaults)
193
+ | |-- claude-tool.ts Claude Code CLI runner (JSONL -> Linear activities)
194
+ | |-- codex-tool.ts Codex CLI runner (JSONL -> Linear activities)
195
+ | |-- gemini-tool.ts Gemini CLI runner (JSONL -> Linear activities)
196
+ | +-- orchestration-tools.ts spawn_agent / ask_agent for multi-agent delegation
197
+ |
198
+ |-- api/ Linear API & auth
199
+ | |-- linear-api.ts GraphQL client, token resolution, auto-refresh
200
+ | |-- auth.ts OAuth provider registration
201
+ | +-- oauth-callback.ts HTTP handler for OAuth redirect
202
+ |
203
+ +-- infra/ Infrastructure utilities
204
+ |-- cli.ts CLI subcommands (auth, status, worktrees, prompts)
205
+ |-- codex-worktree.ts Git worktree create/remove/status/PR helpers
206
+ +-- notify.ts Discord notifier (+ noop fallback)
207
+ ```
208
+
209
+ ---
151
210
 
152
211
  ## Getting Started
153
212
 
@@ -177,7 +236,7 @@ Save the **Client ID** and **Client Secret**.
177
236
 
178
237
  ### 3. Set Credentials
179
238
 
180
- Add to your gateway's environment (systemd service or shell):
239
+ Add to your gateway environment or plugin config:
181
240
 
182
241
  ```bash
183
242
  export LINEAR_CLIENT_ID="your_client_id"
@@ -196,13 +255,13 @@ Then reload: `systemctl --user daemon-reload && systemctl --user restart opencla
196
255
 
197
256
  ### 4. Expose the Gateway
198
257
 
199
- Linear needs to reach your gateway over HTTPS to deliver webhooks. A [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) is the recommended approach -- no open ports, no TLS certificates to manage.
258
+ Linear needs HTTPS access to deliver webhooks. [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) is recommended.
200
259
 
201
260
  ```bash
202
- # Install cloudflared (RHEL/Rocky/Alma)
203
- sudo dnf install -y cloudflared
261
+ # Install cloudflared
262
+ sudo dnf install -y cloudflared # RHEL/Rocky/Alma
204
263
 
205
- # Authenticate and create tunnel
264
+ # Create and configure tunnel
206
265
  cloudflared tunnel login
207
266
  cloudflared tunnel create openclaw
208
267
  cloudflared tunnel route dns openclaw linear.yourdomain.com
@@ -242,21 +301,16 @@ curl -s https://linear.yourdomain.com/linear/webhook \
242
301
  openclaw openclaw-linear auth
243
302
  ```
244
303
 
245
- This opens your browser to authorize the agent. After authorization, restart the gateway:
304
+ This opens your browser to authorize the agent. Then restart and verify:
246
305
 
247
306
  ```bash
248
307
  systemctl --user restart openclaw-gateway
249
- ```
250
-
251
- Verify it's working:
252
-
253
- ```bash
254
308
  openclaw openclaw-linear status
255
309
  ```
256
310
 
257
311
  ### 6. Configure Agents
258
312
 
259
- Create `~/.openclaw/agent-profiles.json` to define your agent team:
313
+ Create `~/.openclaw/agent-profiles.json`:
260
314
 
261
315
  ```json
262
316
  {
@@ -266,20 +320,28 @@ Create `~/.openclaw/agent-profiles.json` to define your agent team:
266
320
  "mission": "Full-stack engineer. Plans, implements, and ships code.",
267
321
  "isDefault": true,
268
322
  "mentionAliases": ["coder"],
269
- "avatarUrl": "https://example.com/coder.png"
323
+ "avatarUrl": "https://example.com/coder.png",
324
+ "watchdog": {
325
+ "inactivitySec": 180,
326
+ "maxTotalSec": 7200,
327
+ "toolTimeoutSec": 900
328
+ }
270
329
  },
271
330
  "qa": {
272
331
  "label": "QA",
273
332
  "mission": "Test engineer. Quality guardian, test strategy.",
274
- "mentionAliases": ["qa", "tester"]
333
+ "mentionAliases": ["qa", "tester"],
334
+ "watchdog": {
335
+ "inactivitySec": 120,
336
+ "maxTotalSec": 3600,
337
+ "toolTimeoutSec": 600
338
+ }
275
339
  }
276
340
  }
277
341
  }
278
342
  ```
279
343
 
280
- Each agent name must match an agent definition in your `~/.openclaw/openclaw.json`.
281
-
282
- One agent must be marked `isDefault: true` -- this is the agent that handles issue assignments and the dispatch pipeline.
344
+ Each agent name must match an agent in `~/.openclaw/openclaw.json`. One agent must have `isDefault: true` -- this agent handles issue assignments and the dispatch pipeline.
283
345
 
284
346
  ### 7. Configure Coding Tools
285
347
 
@@ -287,7 +349,7 @@ Create `coding-tools.json` in the plugin root:
287
349
 
288
350
  ```json
289
351
  {
290
- "codingTool": "codex",
352
+ "codingTool": "claude",
291
353
  "agentCodingTools": {},
292
354
  "backends": {
293
355
  "claude": { "aliases": ["claude", "claude code", "anthropic"] },
@@ -311,7 +373,7 @@ echo "lin_api_YOUR_KEY" > ~/.linear_api_token
311
373
  systemctl --user restart openclaw-gateway
312
374
  ```
313
375
 
314
- Check the logs for a clean startup:
376
+ Check logs for a clean startup:
315
377
 
316
378
  ```
317
379
  [plugins] Linear agent extension registered (agent: default, token: profile,
@@ -327,6 +389,8 @@ curl -s -X POST https://your-domain.com/linear/webhook \
327
389
  # Should return: "ok"
328
390
  ```
329
391
 
392
+ ---
393
+
330
394
  ## Usage
331
395
 
332
396
  Once set up, the plugin responds to Linear events automatically:
@@ -334,7 +398,7 @@ Once set up, the plugin responds to Linear events automatically:
334
398
  | What you do in Linear | What happens |
335
399
  |---|---|
336
400
  | Create a new issue | Agent triages it (estimate, labels, priority) and posts an assessment |
337
- | Assign an issue to the agent | Worker-audit pipeline runs: implement, then independent audit |
401
+ | Assign an issue to the agent | Worker-audit pipeline runs with watchdog protection |
338
402
  | Trigger an agent session | Agent responds directly in the session |
339
403
  | Comment `@qa check the tests` | QA agent responds with its expertise |
340
404
  | Ask "close this issue" | Agent runs `linearis issues update API-123 --status Done` |
@@ -344,17 +408,68 @@ Once set up, the plugin responds to Linear events automatically:
344
408
 
345
409
  When an issue is assigned:
346
410
 
347
- 1. **Tier assessment** -- The plugin evaluates issue complexity (junior/medior/senior) and selects an appropriate model
348
- 2. **Worktree creation** -- A git worktree is created for isolated work
349
- 3. **Worker runs** -- The worker agent plans and implements the solution, posts a summary comment
350
- 4. **Audit runs** -- An independent audit agent reads the issue body (source of truth), verifies acceptance criteria, runs tests, and returns a JSON verdict
351
- 5. **Verdict** -- If the audit passes, the issue is marked done. If it fails, the worker is re-spawned with the audit gaps (up to `maxReworkAttempts` times). If it fails too many times, the issue is marked stuck and an escalation notification is sent.
411
+ 1. **Tier assessment** -- Evaluates complexity (junior/medior/senior), selects model tier
412
+ 2. **Worktree creation** -- Isolated git worktree for the implementation
413
+ 3. **Worker runs** -- Worker agent plans and implements, posts summary comment
414
+ 4. **Audit runs** -- Independent auditor verifies against issue body, returns JSON verdict
415
+ 5. **Verdict** -- Pass: issue done. Fail: worker re-spawns with gaps (up to `maxReworkAttempts`). Too many failures: stuck + escalation notification.
416
+ 6. **Watchdog** -- If the worker goes silent (no I/O), the watchdog kills it and retries once. Double failure escalates to stuck.
417
+
418
+ Workers **cannot** mark issues as done -- that's handled entirely by plugin verdict processing code.
419
+
420
+ ---
421
+
422
+ ## Configuration
423
+
424
+ ### Plugin Config
425
+
426
+ Set in `openclaw.json` under the plugin entry:
427
+
428
+ | Key | Type | Default | Description |
429
+ |---|---|---|---|
430
+ | `defaultAgentId` | string | `"default"` | Agent ID for pipeline workers and audit |
431
+ | `enableAudit` | boolean | `true` | Run auditor stage after implementation |
432
+ | `enableOrchestration` | boolean | `true` | Allow `spawn_agent`/`ask_agent` tools |
433
+ | `codexBaseRepo` | string | `"/home/claw/ai-workspace"` | Git repo for worktrees |
434
+ | `codexModel` | string | -- | Default Codex model |
435
+ | `codexTimeoutMs` | number | `600000` | Legacy timeout for coding CLIs (ms) |
436
+ | `worktreeBaseDir` | string | `"~/.openclaw/worktrees"` | Base directory for worktrees |
437
+ | `dispatchStatePath` | string | `"~/.openclaw/linear-dispatch-state.json"` | Dispatch state file |
438
+ | `flowDiscordChannel` | string | -- | Discord channel ID for notifications |
439
+ | `promptsPath` | string | -- | Override path for `prompts.yaml` |
440
+ | `maxReworkAttempts` | number | `2` | Max audit failures before escalation |
441
+ | `inactivitySec` | number | `120` | Kill sessions with no I/O for this long |
442
+ | `maxTotalSec` | number | `7200` | Max total agent session runtime |
443
+ | `toolTimeoutSec` | number | `600` | Max runtime for a single `code_run` invocation |
352
444
 
353
- Workers **cannot** mark issues as done or modify issue status -- that's handled entirely by the plugin's verdict processing code.
445
+ ### Environment Variables
446
+
447
+ | Variable | Required | Description |
448
+ |---|---|---|
449
+ | `LINEAR_CLIENT_ID` | Yes | OAuth app client ID |
450
+ | `LINEAR_CLIENT_SECRET` | Yes | OAuth app client secret |
451
+ | `LINEAR_API_KEY` | No | Personal API key (fallback if no OAuth) |
452
+ | `LINEAR_REDIRECT_URI` | No | Override the OAuth callback URL |
453
+ | `OPENCLAW_GATEWAY_PORT` | No | Gateway port (default: 18789) |
454
+
455
+ ### Agent Profile Fields
456
+
457
+ | Field | Required | Description |
458
+ |---|---|---|
459
+ | `label` | Yes | Display name on Linear comments |
460
+ | `mission` | Yes | Role description (injected as context) |
461
+ | `isDefault` | One agent | Handles triage and the dispatch pipeline |
462
+ | `mentionAliases` | Yes | `@mention` triggers (e.g., `["qa", "tester"]`) |
463
+ | `avatarUrl` | No | Avatar URL for branded comments |
464
+ | `watchdog.inactivitySec` | No | Inactivity kill threshold (default: 120) |
465
+ | `watchdog.maxTotalSec` | No | Max total session runtime (default: 7200) |
466
+ | `watchdog.toolTimeoutSec` | No | Max single `code_run` runtime (default: 600) |
467
+
468
+ ---
354
469
 
355
470
  ## Prompt Customization
356
471
 
357
- Worker, audit, and rework prompts are externalized in `prompts.yaml`. Edit them to customize agent behavior without rebuilding the plugin.
472
+ Worker, audit, and rework prompts live in `prompts.yaml`. Edit to customize without rebuilding.
358
473
 
359
474
  ### Managing Prompts
360
475
 
@@ -374,12 +489,10 @@ openclaw openclaw-linear prompts validate # Validate structure and template va
374
489
  | `{{worktreePath}}` | Path to the git worktree |
375
490
  | `{{tier}}` | Assessed complexity tier |
376
491
  | `{{attempt}}` | Current attempt number (0-based) |
377
- | `{{gaps}}` | Audit gaps from previous failed attempt (rework only) |
492
+ | `{{gaps}}` | Audit gaps from previous attempt (rework only) |
378
493
 
379
494
  ### Override Path
380
495
 
381
- Set `promptsPath` in plugin config to load prompts from a custom location:
382
-
383
496
  ```json
384
497
  {
385
498
  "plugins": {
@@ -394,11 +507,11 @@ Set `promptsPath` in plugin config to load prompts from a custom location:
394
507
  }
395
508
  ```
396
509
 
397
- ## Notifications
510
+ ---
398
511
 
399
- The plugin can post dispatch lifecycle events to a Discord channel. Configure `flowDiscordChannel` in plugin config with the channel ID.
512
+ ## Notifications
400
513
 
401
- Events posted:
514
+ Configure `flowDiscordChannel` in plugin config with a Discord channel ID. Events:
402
515
 
403
516
  | Event | Message |
404
517
  |---|---|
@@ -406,21 +519,26 @@ Events posted:
406
519
  | Worker started | `**API-123** worker started (attempt 0)` |
407
520
  | Audit in progress | `**API-123** audit in progress` |
408
521
  | Audit passed | `**API-123** passed audit. PR ready.` |
409
- | Audit failed | `**API-123** failed audit (attempt 1). Gaps: missing test coverage` |
522
+ | Audit failed | `**API-123** failed audit (attempt 1). Gaps: ...` |
410
523
  | Escalation | `**API-123** needs human review -- audit failed 3x` |
524
+ | Watchdog kill | `**API-123** killed by watchdog (no I/O for 120s). Retrying.` |
525
+
526
+ ---
411
527
 
412
528
  ## Coding Tool (`code_run`)
413
529
 
414
- The plugin provides a single `code_run` tool that dispatches to one of three coding CLI backends. Agents call `code_run` without needing to know which backend is active.
530
+ One tool dispatches to three CLI backends. Agents call `code_run` without knowing which backend is active.
415
531
 
416
532
  ### Supported Backends
417
533
 
418
534
  | Backend | CLI | Stream Format | Key Flags |
419
535
  |---|---|---|---|
420
- | **Codex** (OpenAI) | `codex` | JSONL | `--full-auto`, `-q` |
421
- | **Claude Code** (Anthropic) | `claude` | JSONL (`stream-json`) | `--print`, `--dangerously-skip-permissions`, `--verbose` |
536
+ | **Claude Code** (Anthropic) | `claude` | JSONL (`stream-json`) | `--print`, `--dangerously-skip-permissions` |
537
+ | **Codex** (OpenAI) | `codex` | JSONL | `--full-auto`, `--ephemeral` |
422
538
  | **Gemini CLI** (Google) | `gemini` | JSONL (`stream-json`) | `--yolo`, `-o stream-json` |
423
539
 
540
+ All three backends have inactivity watchdog protection. Each line of JSONL output ticks the watchdog timer. If a CLI goes silent beyond the configured threshold, the process is killed with SIGTERM (+ SIGKILL after 5s).
541
+
424
542
  ### Backend Resolution Priority
425
543
 
426
544
  1. **Explicit `backend` parameter** -- Agent passes `backend: "gemini"` (or any alias)
@@ -428,61 +546,100 @@ The plugin provides a single `code_run` tool that dispatches to one of three cod
428
546
  3. **Global default** -- `codingTool` in `coding-tools.json`
429
547
  4. **Hardcoded fallback** -- `"claude"`
430
548
 
431
- ## Linear Issue Management (`linearis` Skill)
549
+ ---
432
550
 
433
- Issue management is handled by the **`linearis`** CLI, installed as an OpenClaw skill. Agents use `linearis` via exec.
551
+ ## Inactivity Watchdog
434
552
 
435
- ```bash
436
- linearis issues list -l 20 # List recent issues
437
- linearis issues search "auth bug" # Full-text search
438
- linearis issues read API-123 # Get issue details
439
- linearis issues update API-123 --status "Done"
440
- linearis issues update API-123 --labels "Bug" --label-by adding
441
- linearis comments create API-123 --body "Fixed in PR #456"
442
- linearis usage # Full command reference
553
+ Agent sessions can go silent when LLM providers rate-limit, APIs hang, or CLI tools lock up. The watchdog detects silence and kills stuck sessions.
554
+
555
+ ### How It Works
556
+
557
+ ```mermaid
558
+ flowchart TD
559
+ A[Agent starts] --> B["Watchdog timer starts<br/>(inactivitySec countdown)"]
560
+ B --> C{"I/O event?"}
561
+ C -->|"JSONL line, stderr,<br/>stream callback"| D[Timer resets]
562
+ D --> C
563
+ C -->|"No I/O for inactivitySec"| E[KILL]
564
+ E --> F[Retry once]
565
+ F -->|Success| G[Continue pipeline]
566
+ F -->|Killed again| H["STUCK (escalation)"]
567
+ B --> I{"Total runtime<br/>> maxTotalSec?"}
568
+ I -->|Yes| J["KILL (no retry)"]
443
569
  ```
444
570
 
445
- ## Configuration Reference
571
+ ### Three Timeout Dimensions
446
572
 
447
- ### Plugin Config
573
+ | Timeout | Scope | Default | Description |
574
+ |---------|-------|---------|-------------|
575
+ | `inactivitySec` | Per I/O gap | 120s (2 min) | Kill if no stdout/stderr/callback for this long |
576
+ | `maxTotalSec` | Per agent session | 7200s (2 hrs) | Hard ceiling on total session runtime |
577
+ | `toolTimeoutSec` | Per `code_run` call | 600s (10 min) | Max runtime for a single CLI invocation |
448
578
 
449
- Set in `openclaw.json` under the plugin entry:
579
+ ### Config Resolution Order
450
580
 
451
- | Key | Type | Default | Description |
452
- |---|---|---|---|
453
- | `defaultAgentId` | string | `"default"` | Agent ID for pipeline workers and audit |
454
- | `enableAudit` | boolean | `true` | Run the auditor stage after implementation |
455
- | `enableOrchestration` | boolean | `true` | Allow agents to use `spawn_agent`/`ask_agent` |
456
- | `codexBaseRepo` | string | `"/home/claw/ai-workspace"` | Git repo path for worktrees |
457
- | `codexModel` | string | -- | Default Codex model |
458
- | `codexTimeoutMs` | number | `600000` | Default timeout for coding CLIs (ms) |
459
- | `worktreeBaseDir` | string | `"~/.openclaw/worktrees"` | Base directory for persistent git worktrees |
460
- | `dispatchStatePath` | string | `"~/.openclaw/linear-dispatch-state.json"` | Path to dispatch state file |
461
- | `flowDiscordChannel` | string | -- | Discord channel ID for lifecycle notifications |
462
- | `promptsPath` | string | -- | Override path for `prompts.yaml` |
463
- | `maxReworkAttempts` | number | `2` | Max audit failures before escalation |
581
+ 1. **Agent profile** -- `~/.openclaw/agent-profiles.json` `agents.{id}.watchdog`
582
+ 2. **Plugin config** -- `openclaw.json` `inactivitySec` / `maxTotalSec` / `toolTimeoutSec`
583
+ 3. **Hardcoded defaults** -- 120s / 7200s / 600s
464
584
 
465
- ### Environment Variables
585
+ ### Per-Agent Configuration
466
586
 
467
- | Variable | Required | Description |
468
- |---|---|---|
469
- | `LINEAR_CLIENT_ID` | Yes | OAuth app client ID |
470
- | `LINEAR_CLIENT_SECRET` | Yes | OAuth app client secret |
471
- | `LINEAR_API_KEY` | No | Personal API key (fallback if no OAuth) |
472
- | `LINEAR_REDIRECT_URI` | No | Override the OAuth callback URL |
473
- | `OPENCLAW_GATEWAY_PORT` | No | Gateway port (default: 18789) |
587
+ ```json
588
+ {
589
+ "agents": {
590
+ "coder": {
591
+ "watchdog": {
592
+ "inactivitySec": 180,
593
+ "maxTotalSec": 7200,
594
+ "toolTimeoutSec": 900
595
+ }
596
+ },
597
+ "reviewer": {
598
+ "watchdog": {
599
+ "inactivitySec": 60,
600
+ "maxTotalSec": 600,
601
+ "toolTimeoutSec": 300
602
+ }
603
+ }
604
+ }
605
+ }
606
+ ```
474
607
 
475
- ### Agent Profile Fields
608
+ ### Artifact Logging
476
609
 
477
- | Field | Required | Description |
478
- |---|---|---|
479
- | `label` | Yes | Display name shown on comments in Linear |
480
- | `mission` | Yes | Role description (injected as context) |
481
- | `isDefault` | One agent | Handles issue triage and the dispatch pipeline |
482
- | `mentionAliases` | Yes | `@mention` triggers (e.g., `["qa", "tester"]`) |
483
- | `avatarUrl` | No | Avatar for branded comments |
610
+ Every dispatch writes structured artifacts to `.claw/` in the worktree:
611
+
612
+ ```
613
+ .claw/
614
+ manifest.json Issue metadata + lifecycle timestamps
615
+ plan.md Implementation plan
616
+ worker-{N}.md Worker output per attempt (truncated to 8KB)
617
+ audit-{N}.json Audit verdict per attempt
618
+ log.jsonl Append-only structured interaction log
619
+ summary.md Agent-curated final summary
620
+ ```
484
621
 
485
- ### CLI
622
+ Watchdog kills are logged to `log.jsonl` with phase `"watchdog"`:
623
+
624
+ ```json
625
+ {
626
+ "ts": "2026-02-18T12:00:00Z",
627
+ "phase": "watchdog",
628
+ "attempt": 0,
629
+ "agent": "coder",
630
+ "success": false,
631
+ "watchdog": {
632
+ "reason": "inactivity",
633
+ "silenceSec": 120,
634
+ "thresholdSec": 120,
635
+ "retried": true
636
+ }
637
+ }
638
+ ```
639
+
640
+ ---
641
+
642
+ ## CLI Reference
486
643
 
487
644
  ```bash
488
645
  openclaw openclaw-linear auth # Run OAuth authorization
@@ -494,6 +651,8 @@ openclaw openclaw-linear prompts path # Print resolved prompts file path
494
651
  openclaw openclaw-linear prompts validate # Validate prompt structure
495
652
  ```
496
653
 
654
+ ---
655
+
497
656
  ## Troubleshooting
498
657
 
499
658
  Quick checks:
@@ -510,6 +669,8 @@ openclaw openclaw-linear prompts validate # Are prompts valid?
510
669
 
511
670
  | Problem | Cause | Fix |
512
671
  |---|---|---|
672
+ | Agent goes silent, no response | LLM provider timeout or rate limit | Watchdog auto-kills after `inactivitySec` and retries. Check logs for `Watchdog KILL`. |
673
+ | Dispatch stuck after watchdog | Both retry attempts failed | Check `.claw/log.jsonl` for watchdog entries. Re-assign issue to retry. |
513
674
  | Agent says "closing" but doesn't | No issue management tool | Install `linearis`: `npx clawhub install linearis` |
514
675
  | `code_run` uses wrong backend | Config mismatch | Check `coding-tools.json` |
515
676
  | Claude Code "nested session" error | `CLAUDECODE` env var set | Plugin handles this automatically |
@@ -517,7 +678,10 @@ openclaw openclaw-linear prompts validate # Are prompts valid?
517
678
  | Webhook events not arriving | Wrong URL | Both webhooks must point to `/linear/webhook` |
518
679
  | OAuth token expired | Tokens expire ~24h | Auto-refreshes; restart gateway if stuck |
519
680
  | Audit always fails | Bad prompt template | Run `openclaw openclaw-linear prompts validate` |
520
- | Dispatch stuck | Worker timed out or crashed | Check `dispatch-state.json`, re-assign issue |
681
+
682
+ See [docs/troubleshooting.md](docs/troubleshooting.md) for detailed diagnostic commands.
683
+
684
+ ---
521
685
 
522
686
  ## License
523
687