@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.
- package/README.md +359 -195
- package/index.ts +10 -10
- package/openclaw.plugin.json +4 -1
- package/package.json +9 -2
- package/src/agent/agent.test.ts +127 -0
- package/src/{agent.ts → agent/agent.ts} +84 -7
- package/src/agent/watchdog.test.ts +266 -0
- package/src/agent/watchdog.ts +176 -0
- package/src/{cli.ts → infra/cli.ts} +32 -5
- package/src/{codex-worktree.ts → infra/codex-worktree.ts} +1 -1
- package/src/infra/doctor.test.ts +399 -0
- package/src/infra/doctor.ts +781 -0
- package/src/infra/notify.test.ts +169 -0
- package/src/{notify.ts → infra/notify.ts} +6 -1
- package/src/pipeline/active-session.test.ts +154 -0
- package/src/pipeline/artifacts.test.ts +383 -0
- package/src/{artifacts.ts → pipeline/artifacts.ts} +9 -1
- package/src/{dispatch-service.ts → pipeline/dispatch-service.ts} +1 -1
- package/src/pipeline/dispatch-state.test.ts +382 -0
- package/src/pipeline/pipeline.test.ts +226 -0
- package/src/{pipeline.ts → pipeline/pipeline.ts} +61 -7
- package/src/{tier-assess.ts → pipeline/tier-assess.ts} +1 -1
- package/src/{webhook.test.ts → pipeline/webhook.test.ts} +1 -1
- package/src/{webhook.ts → pipeline/webhook.ts} +8 -8
- package/src/{claude-tool.ts → tools/claude-tool.ts} +31 -5
- package/src/{cli-shared.ts → tools/cli-shared.ts} +5 -4
- package/src/{code-tool.ts → tools/code-tool.ts} +2 -2
- package/src/{codex-tool.ts → tools/codex-tool.ts} +31 -5
- package/src/{gemini-tool.ts → tools/gemini-tool.ts} +31 -5
- package/src/{orchestration-tools.ts → tools/orchestration-tools.ts} +1 -1
- package/src/client.ts +0 -94
- /package/src/{auth.ts → api/auth.ts} +0 -0
- /package/src/{linear-api.ts → api/linear-api.ts} +0 -0
- /package/src/{oauth-callback.ts → api/oauth-callback.ts} +0 -0
- /package/src/{active-session.ts → pipeline/active-session.ts} +0 -0
- /package/src/{dispatch-state.ts → pipeline/dispatch-state.ts} +0 -0
- /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
|
-
|
|
3
|
+
[](https://github.com/calltelemetry/openclaw)
|
|
4
|
+
[](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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
|
85
|
+
When an issue is assigned, the plugin runs a multi-stage pipeline:
|
|
23
86
|
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
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
|
-
|
|
|
65
|
-
|
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
|
123
|
+
All transitions use compare-and-swap (CAS) to prevent races. `dispatch-state.json` is the canonical source of truth.
|
|
79
124
|
|
|
80
|
-
### Webhook
|
|
125
|
+
### Webhook Event Router
|
|
81
126
|
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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) --
|
|
117
|
-
2. **OAuth app webhook** (Settings > API > Applications
|
|
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
|
|
147
|
+
Both must point to: `https://<your-domain>/linear/webhook`
|
|
120
148
|
|
|
121
|
-
###
|
|
149
|
+
### Deduplication
|
|
122
150
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
|
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
|
|
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
|
|
203
|
-
sudo dnf install -y cloudflared
|
|
261
|
+
# Install cloudflared
|
|
262
|
+
sudo dnf install -y cloudflared # RHEL/Rocky/Alma
|
|
204
263
|
|
|
205
|
-
#
|
|
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.
|
|
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
|
|
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
|
|
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": "
|
|
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
|
|
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
|
|
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** --
|
|
348
|
-
2. **Worktree creation** --
|
|
349
|
-
3. **Worker runs** --
|
|
350
|
-
4. **Audit runs** --
|
|
351
|
-
5. **Verdict** --
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
510
|
+
---
|
|
398
511
|
|
|
399
|
-
|
|
512
|
+
## Notifications
|
|
400
513
|
|
|
401
|
-
Events
|
|
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:
|
|
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
|
-
|
|
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
|
-
| **
|
|
421
|
-
| **
|
|
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
|
-
|
|
549
|
+
---
|
|
432
550
|
|
|
433
|
-
|
|
551
|
+
## Inactivity Watchdog
|
|
434
552
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
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
|
-
|
|
571
|
+
### Three Timeout Dimensions
|
|
446
572
|
|
|
447
|
-
|
|
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
|
-
|
|
579
|
+
### Config Resolution Order
|
|
450
580
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
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
|
-
###
|
|
585
|
+
### Per-Agent Configuration
|
|
466
586
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
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
|
-
###
|
|
608
|
+
### Artifact Logging
|
|
476
609
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
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
|
-
|
|
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
|
-
|
|
681
|
+
|
|
682
|
+
See [docs/troubleshooting.md](docs/troubleshooting.md) for detailed diagnostic commands.
|
|
683
|
+
|
|
684
|
+
---
|
|
521
685
|
|
|
522
686
|
## License
|
|
523
687
|
|