@calltelemetry/openclaw-linear 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +263 -249
- package/index.ts +104 -1
- package/openclaw.plugin.json +4 -1
- package/package.json +5 -1
- package/prompts.yaml +61 -0
- package/src/active-session.ts +1 -1
- package/src/cli.ts +103 -0
- package/src/dispatch-service.ts +50 -2
- package/src/dispatch-state.ts +240 -8
- package/src/notify.ts +91 -0
- package/src/pipeline.ts +561 -406
- package/src/tier-assess.ts +1 -1
- package/src/webhook.ts +39 -30
package/README.md
CHANGED
|
@@ -1,211 +1,171 @@
|
|
|
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
|
|
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.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- **Auto-triage**
|
|
8
|
-
- **@mention routing**
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
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
|
|
14
17
|
|
|
15
18
|
## Architecture
|
|
16
19
|
|
|
20
|
+
### Dispatch Pipeline (v2)
|
|
21
|
+
|
|
22
|
+
When an issue is assigned to the agent, the plugin runs a multi-stage pipeline with hard-enforced audit:
|
|
23
|
+
|
|
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
|
+
+-----------------+
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**What's hard-enforced vs. LLM-mediated:**
|
|
58
|
+
|
|
59
|
+
| Layer | Mechanism | Can be skipped? |
|
|
60
|
+
|-------|-----------|-----------------|
|
|
61
|
+
| Worker spawn | Plugin code (`runAgent`) | No |
|
|
62
|
+
| Audit trigger | Plugin code (fires after worker completes) | No |
|
|
63
|
+
| 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 |
|
|
66
|
+
|
|
67
|
+
### State Machine
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
DISPATCHED --> WORKING --> AUDITING --> DONE
|
|
71
|
+
^ |
|
|
72
|
+
| FAIL ---+ (attempt++ if <= max)
|
|
73
|
+
+------------+ (re-enter WORKING)
|
|
74
|
+
|
|
|
75
|
+
(attempt > max) --> STUCK
|
|
76
|
+
```
|
|
77
|
+
|
|
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.
|
|
79
|
+
|
|
17
80
|
### Webhook Flow
|
|
18
81
|
|
|
19
82
|
```
|
|
20
83
|
Linear OpenClaw Gateway AI Agents
|
|
21
84
|
| | |
|
|
22
85
|
| Webhook (issue created) | |
|
|
23
|
-
|
|
|
86
|
+
| -----------------------> | |
|
|
24
87
|
| | Dispatch triage agent |
|
|
25
|
-
| |
|
|
88
|
+
| | ----------------------> |
|
|
26
89
|
| | |
|
|
27
90
|
| | Estimate + labels |
|
|
28
|
-
| |
|
|
91
|
+
| | <---------------------- |
|
|
29
92
|
| Update issue | |
|
|
30
|
-
|
|
|
93
|
+
| <----------------------- | |
|
|
31
94
|
| Post assessment comment | |
|
|
32
|
-
|
|
|
95
|
+
| <----------------------- | |
|
|
33
96
|
```
|
|
34
97
|
|
|
35
98
|
```
|
|
36
99
|
Linear OpenClaw Gateway AI Agents
|
|
37
100
|
| | |
|
|
38
101
|
| "@qa check this" | |
|
|
39
|
-
|
|
|
102
|
+
| -----------------------> | |
|
|
40
103
|
| | Route to QA agent |
|
|
41
|
-
| |
|
|
104
|
+
| | ----------------------> |
|
|
42
105
|
| | |
|
|
43
106
|
| | Response |
|
|
44
|
-
| |
|
|
107
|
+
| | <---------------------- |
|
|
45
108
|
| Comment from "QA" | |
|
|
46
|
-
|
|
|
109
|
+
| <----------------------- | |
|
|
47
110
|
```
|
|
48
111
|
|
|
49
112
|
### Two Webhook Systems
|
|
50
113
|
|
|
51
114
|
Linear delivers events through two separate webhook paths:
|
|
52
115
|
|
|
53
|
-
1. **Workspace webhook** (Settings > API > Webhooks)
|
|
54
|
-
2. **OAuth app webhook** (Settings > API > Applications > your app)
|
|
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)
|
|
55
118
|
|
|
56
119
|
Both must point to the same URL: `https://<your-domain>/linear/webhook`
|
|
57
120
|
|
|
58
121
|
### Source Layout
|
|
59
122
|
|
|
60
123
|
```
|
|
61
|
-
index.ts Plugin entry point,
|
|
124
|
+
index.ts Plugin entry point, agent_end hook, notifier setup
|
|
125
|
+
prompts.yaml Externalized worker/audit/rework prompt templates
|
|
62
126
|
src/
|
|
63
|
-
webhook.ts Webhook handler
|
|
64
|
-
pipeline.ts
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
|
69
137
|
cli-shared.ts Shared helpers for CLI tools (buildLinearApi, resolveSession)
|
|
70
|
-
codex-tool.ts Codex CLI runner (JSONL stream
|
|
71
|
-
claude-tool.ts Claude Code CLI runner (JSONL stream
|
|
72
|
-
gemini-tool.ts Gemini CLI runner (JSONL stream
|
|
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)
|
|
73
141
|
coding-tools.json Backend config (default tool, per-agent overrides, aliases)
|
|
74
142
|
|
|
75
143
|
tools.ts Tool registration (code_run + orchestration)
|
|
76
144
|
orchestration-tools.ts spawn_agent / ask_agent for multi-agent delegation
|
|
77
145
|
linear-api.ts Linear GraphQL API client, token resolution, activity streaming
|
|
78
|
-
client.ts Lightweight Linear GraphQL client (legacy, unused by tools)
|
|
79
146
|
auth.ts OAuth token management and profile storage
|
|
80
147
|
oauth-callback.ts OAuth callback handler
|
|
81
|
-
cli.ts CLI subcommands (auth, status)
|
|
82
|
-
codex-worktree.ts Git worktree management for isolated
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## Coding Tool (`code_run`)
|
|
86
|
-
|
|
87
|
-
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 — the dispatcher handles routing.
|
|
88
|
-
|
|
89
|
-
### Supported Backends
|
|
90
|
-
|
|
91
|
-
| Backend | CLI | Stream Format | Key Flags |
|
|
92
|
-
|---|---|---|---|
|
|
93
|
-
| **Codex** (OpenAI) | `codex` | JSONL | `--full-auto`, `-q` |
|
|
94
|
-
| **Claude Code** (Anthropic) | `claude` | JSONL (`stream-json`) | `--print`, `--dangerously-skip-permissions`, `--verbose` |
|
|
95
|
-
| **Gemini CLI** (Google) | `gemini` | JSONL (`stream-json`) | `--yolo`, `-o stream-json` |
|
|
96
|
-
|
|
97
|
-
All three stream JSONL events that get mapped to Linear agent activities in real-time (thoughts, actions, tool results).
|
|
98
|
-
|
|
99
|
-
### Backend Resolution Priority
|
|
100
|
-
|
|
101
|
-
When `code_run` is called:
|
|
102
|
-
|
|
103
|
-
1. **Explicit `backend` parameter** — Agent passes `backend: "gemini"` (or any alias)
|
|
104
|
-
2. **Per-agent override** — `agentCodingTools` in `coding-tools.json`
|
|
105
|
-
3. **Global default** — `codingTool` in `coding-tools.json`
|
|
106
|
-
4. **Hardcoded fallback** — `"claude"`
|
|
107
|
-
|
|
108
|
-
### Configuration (`coding-tools.json`)
|
|
109
|
-
|
|
110
|
-
```json
|
|
111
|
-
{
|
|
112
|
-
"codingTool": "codex",
|
|
113
|
-
"agentCodingTools": {
|
|
114
|
-
"kaylee": "claude",
|
|
115
|
-
"inara": "gemini"
|
|
116
|
-
},
|
|
117
|
-
"backends": {
|
|
118
|
-
"claude": {
|
|
119
|
-
"aliases": ["claude", "claude code", "anthropic"]
|
|
120
|
-
},
|
|
121
|
-
"codex": {
|
|
122
|
-
"aliases": ["codex", "openai"]
|
|
123
|
-
},
|
|
124
|
-
"gemini": {
|
|
125
|
-
"aliases": ["gemini", "google"]
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
148
|
+
cli.ts CLI subcommands (auth, status, worktrees, prompts)
|
|
149
|
+
codex-worktree.ts Git worktree management for isolated runs
|
|
129
150
|
```
|
|
130
151
|
|
|
131
|
-
|
|
132
|
-
- **`agentCodingTools`** — Per-agent overrides (keyed by agent ID)
|
|
133
|
-
- **`backends.*.aliases`** — Alias strings so the agent (or user) can say "use google" and it resolves to `gemini`
|
|
152
|
+
## Getting Started
|
|
134
153
|
|
|
135
|
-
###
|
|
136
|
-
|
|
137
|
-
**Claude Code:**
|
|
138
|
-
- Must unset `CLAUDECODE` env var to avoid "nested session" error
|
|
139
|
-
- Requires `--verbose` alongside `stream-json` for full event output
|
|
140
|
-
- Content blocks are arrays: `message.content[].type` can be `text` or `tool_use`
|
|
141
|
-
|
|
142
|
-
**Gemini CLI:**
|
|
143
|
-
- Working directory set via `spawn()` `cwd` option (no `-C` flag)
|
|
144
|
-
- Model override via `-m <model>` flag
|
|
145
|
-
- Stderr may include "YOLO mode" warnings — filtered from output
|
|
146
|
-
|
|
147
|
-
**Codex:**
|
|
148
|
-
- Uses git worktrees for isolated runs (see `codex-worktree.ts`)
|
|
149
|
-
- Model/timeout configurable via plugin config (`codexModel`, `codexTimeoutMs`)
|
|
150
|
-
|
|
151
|
-
## Linear Issue Management (`linearis` Skill)
|
|
152
|
-
|
|
153
|
-
Issue management (update status, close, assign, comment, labels, etc.) is handled by the **`linearis`** CLI, installed as an OpenClaw skill. This replaces custom GraphQL tools — agents use `linearis` via exec.
|
|
154
|
-
|
|
155
|
-
### Install
|
|
156
|
-
|
|
157
|
-
```bash
|
|
158
|
-
npx clawhub install linearis
|
|
159
|
-
npm install -g linearis
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
### Auth
|
|
163
|
-
|
|
164
|
-
```bash
|
|
165
|
-
echo "lin_api_..." > ~/.linear_api_token
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
Or set `LINEAR_API_TOKEN` env var.
|
|
169
|
-
|
|
170
|
-
### Key Commands
|
|
171
|
-
|
|
172
|
-
```bash
|
|
173
|
-
linearis issues list -l 20 # List recent issues
|
|
174
|
-
linearis issues list --team UAT # Filter by team
|
|
175
|
-
linearis issues search "auth bug" # Full-text search
|
|
176
|
-
linearis issues read API-123 # Get issue details
|
|
177
|
-
linearis issues update API-123 --status "Done" # Close issue
|
|
178
|
-
linearis issues update API-123 --status "In Progress"
|
|
179
|
-
linearis issues update API-123 --assignee user123
|
|
180
|
-
linearis issues update API-123 --labels "Bug" --label-by adding
|
|
181
|
-
linearis issues create --title "Fix it" --team UAT --priority 2
|
|
182
|
-
linearis comments create API-123 --body "Fixed in PR #456"
|
|
183
|
-
linearis teams list
|
|
184
|
-
linearis users list --active
|
|
185
|
-
linearis projects list
|
|
186
|
-
linearis documents list
|
|
187
|
-
linearis usage # Full command reference
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
All output is JSON, suitable for piping to `jq`.
|
|
191
|
-
|
|
192
|
-
## Prerequisites
|
|
154
|
+
### Prerequisites
|
|
193
155
|
|
|
194
156
|
- **OpenClaw** gateway running (v2026.2+)
|
|
195
157
|
- **Linear** workspace with API access
|
|
196
158
|
- **Public URL** for webhook delivery (Cloudflare Tunnel recommended)
|
|
197
|
-
- **Coding CLIs** (at least one): `codex`, `claude`, `gemini`
|
|
198
|
-
- **linearis** CLI
|
|
159
|
+
- **Coding CLIs** (at least one): `codex`, `claude`, `gemini` -- installed in PATH
|
|
160
|
+
- **linearis** CLI -- for issue management
|
|
199
161
|
|
|
200
|
-
|
|
162
|
+
### 1. Install the Plugin
|
|
201
163
|
|
|
202
164
|
```bash
|
|
203
165
|
openclaw plugins install @calltelemetry/openclaw-linear
|
|
204
166
|
```
|
|
205
167
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
### 1. Create a Linear OAuth App
|
|
168
|
+
### 2. Create a Linear OAuth App
|
|
209
169
|
|
|
210
170
|
Go to **Linear Settings > API > Applications** and create a new application:
|
|
211
171
|
|
|
@@ -215,7 +175,7 @@ Go to **Linear Settings > API > Applications** and create a new application:
|
|
|
215
175
|
|
|
216
176
|
Save the **Client ID** and **Client Secret**.
|
|
217
177
|
|
|
218
|
-
###
|
|
178
|
+
### 3. Set Credentials
|
|
219
179
|
|
|
220
180
|
Add to your gateway's environment (systemd service or shell):
|
|
221
181
|
|
|
@@ -234,49 +194,20 @@ Environment=LINEAR_CLIENT_SECRET=your_client_secret
|
|
|
234
194
|
|
|
235
195
|
Then reload: `systemctl --user daemon-reload && systemctl --user restart openclaw-gateway`
|
|
236
196
|
|
|
237
|
-
###
|
|
197
|
+
### 4. Expose the Gateway
|
|
238
198
|
|
|
239
|
-
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
|
|
240
|
-
|
|
241
|
-
#### a. Install `cloudflared`
|
|
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.
|
|
242
200
|
|
|
243
201
|
```bash
|
|
244
|
-
# RHEL
|
|
202
|
+
# Install cloudflared (RHEL/Rocky/Alma)
|
|
245
203
|
sudo dnf install -y cloudflared
|
|
246
204
|
|
|
247
|
-
#
|
|
248
|
-
sudo apt install -y cloudflared
|
|
249
|
-
|
|
250
|
-
# macOS
|
|
251
|
-
brew install cloudflare/cloudflare/cloudflared
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
#### b. Authenticate with Cloudflare
|
|
255
|
-
|
|
256
|
-
```bash
|
|
205
|
+
# Authenticate and create tunnel
|
|
257
206
|
cloudflared tunnel login
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
This opens your browser. Log in, select the domain you want to use, and click **Authorize**.
|
|
261
|
-
|
|
262
|
-
#### c. Create a tunnel
|
|
263
|
-
|
|
264
|
-
```bash
|
|
265
207
|
cloudflared tunnel create openclaw
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
Note the **Tunnel ID** (a UUID) from the output.
|
|
269
|
-
|
|
270
|
-
#### d. Point a subdomain at the tunnel
|
|
271
|
-
|
|
272
|
-
```bash
|
|
273
208
|
cloudflared tunnel route dns openclaw linear.yourdomain.com
|
|
274
209
|
```
|
|
275
210
|
|
|
276
|
-
This creates a DNS record so `linear.yourdomain.com` routes through the tunnel.
|
|
277
|
-
|
|
278
|
-
#### e. Configure the tunnel
|
|
279
|
-
|
|
280
211
|
Create `~/.cloudflared/config.yml`:
|
|
281
212
|
|
|
282
213
|
```yaml
|
|
@@ -289,21 +220,14 @@ ingress:
|
|
|
289
220
|
- service: http_status:404
|
|
290
221
|
```
|
|
291
222
|
|
|
292
|
-
|
|
223
|
+
Start the tunnel:
|
|
293
224
|
|
|
294
225
|
```bash
|
|
295
|
-
# Install as a system service (starts on boot)
|
|
296
226
|
sudo cloudflared service install
|
|
297
227
|
sudo systemctl enable --now cloudflared
|
|
298
228
|
```
|
|
299
229
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
```bash
|
|
303
|
-
cloudflared tunnel run openclaw
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
#### g. Verify the tunnel
|
|
230
|
+
Verify:
|
|
307
231
|
|
|
308
232
|
```bash
|
|
309
233
|
curl -s https://linear.yourdomain.com/linear/webhook \
|
|
@@ -312,21 +236,13 @@ curl -s https://linear.yourdomain.com/linear/webhook \
|
|
|
312
236
|
# Should return: "ok"
|
|
313
237
|
```
|
|
314
238
|
|
|
315
|
-
###
|
|
239
|
+
### 5. Authorize with Linear
|
|
316
240
|
|
|
317
241
|
```bash
|
|
318
242
|
openclaw openclaw-linear auth
|
|
319
243
|
```
|
|
320
244
|
|
|
321
|
-
This opens your browser to authorize the agent.
|
|
322
|
-
|
|
323
|
-
| Scope | What it enables |
|
|
324
|
-
|---|---|
|
|
325
|
-
| `read` / `write` | Read and update issues, post comments |
|
|
326
|
-
| `app:assignable` | Agent appears in Linear's assignment menus |
|
|
327
|
-
| `app:mentionable` | Users can @mention the agent in comments |
|
|
328
|
-
|
|
329
|
-
After authorization, restart the gateway:
|
|
245
|
+
This opens your browser to authorize the agent. After authorization, restart the gateway:
|
|
330
246
|
|
|
331
247
|
```bash
|
|
332
248
|
systemctl --user restart openclaw-gateway
|
|
@@ -338,31 +254,24 @@ Verify it's working:
|
|
|
338
254
|
openclaw openclaw-linear status
|
|
339
255
|
```
|
|
340
256
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
### 5. Configure Agents
|
|
257
|
+
### 6. Configure Agents
|
|
344
258
|
|
|
345
259
|
Create `~/.openclaw/agent-profiles.json` to define your agent team:
|
|
346
260
|
|
|
347
261
|
```json
|
|
348
262
|
{
|
|
349
263
|
"agents": {
|
|
350
|
-
"
|
|
351
|
-
"label": "
|
|
352
|
-
"mission": "
|
|
264
|
+
"coder": {
|
|
265
|
+
"label": "Coder",
|
|
266
|
+
"mission": "Full-stack engineer. Plans, implements, and ships code.",
|
|
353
267
|
"isDefault": true,
|
|
354
|
-
"mentionAliases": ["
|
|
355
|
-
"avatarUrl": "https://example.com/
|
|
268
|
+
"mentionAliases": ["coder"],
|
|
269
|
+
"avatarUrl": "https://example.com/coder.png"
|
|
356
270
|
},
|
|
357
271
|
"qa": {
|
|
358
272
|
"label": "QA",
|
|
359
273
|
"mission": "Test engineer. Quality guardian, test strategy.",
|
|
360
274
|
"mentionAliases": ["qa", "tester"]
|
|
361
|
-
},
|
|
362
|
-
"infra": {
|
|
363
|
-
"label": "Infra",
|
|
364
|
-
"mission": "Backend engineer. Performance, reliability, observability.",
|
|
365
|
-
"mentionAliases": ["infra", "backend"]
|
|
366
275
|
}
|
|
367
276
|
}
|
|
368
277
|
}
|
|
@@ -370,9 +279,9 @@ Create `~/.openclaw/agent-profiles.json` to define your agent team:
|
|
|
370
279
|
|
|
371
280
|
Each agent name must match an agent definition in your `~/.openclaw/openclaw.json`.
|
|
372
281
|
|
|
373
|
-
One agent must be marked `isDefault: true`
|
|
282
|
+
One agent must be marked `isDefault: true` -- this is the agent that handles issue assignments and the dispatch pipeline.
|
|
374
283
|
|
|
375
|
-
###
|
|
284
|
+
### 7. Configure Coding Tools
|
|
376
285
|
|
|
377
286
|
Create `coding-tools.json` in the plugin root:
|
|
378
287
|
|
|
@@ -388,7 +297,7 @@ Create `coding-tools.json` in the plugin root:
|
|
|
388
297
|
}
|
|
389
298
|
```
|
|
390
299
|
|
|
391
|
-
###
|
|
300
|
+
### 8. Install linearis
|
|
392
301
|
|
|
393
302
|
```bash
|
|
394
303
|
npm install -g linearis
|
|
@@ -396,7 +305,7 @@ npx clawhub install linearis
|
|
|
396
305
|
echo "lin_api_YOUR_KEY" > ~/.linear_api_token
|
|
397
306
|
```
|
|
398
307
|
|
|
399
|
-
###
|
|
308
|
+
### 9. Verify
|
|
400
309
|
|
|
401
310
|
```bash
|
|
402
311
|
systemctl --user restart openclaw-gateway
|
|
@@ -425,62 +334,164 @@ Once set up, the plugin responds to Linear events automatically:
|
|
|
425
334
|
| What you do in Linear | What happens |
|
|
426
335
|
|---|---|
|
|
427
336
|
| Create a new issue | Agent triages it (estimate, labels, priority) and posts an assessment |
|
|
428
|
-
| Assign an issue to the agent |
|
|
429
|
-
| Trigger an agent session |
|
|
337
|
+
| Assign an issue to the agent | Worker-audit pipeline runs: implement, then independent audit |
|
|
338
|
+
| Trigger an agent session | Agent responds directly in the session |
|
|
430
339
|
| Comment `@qa check the tests` | QA agent responds with its expertise |
|
|
431
|
-
| Comment `@infra why is this slow` | Infra agent investigates and replies |
|
|
432
340
|
| Ask "close this issue" | Agent runs `linearis issues update API-123 --status Done` |
|
|
433
341
|
| Ask "use gemini to review" | Agent calls `code_run` with `backend: "gemini"` |
|
|
434
342
|
|
|
435
|
-
|
|
343
|
+
### Pipeline Behavior
|
|
436
344
|
|
|
437
|
-
|
|
345
|
+
When an issue is assigned:
|
|
438
346
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
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.
|
|
352
|
+
|
|
353
|
+
Workers **cannot** mark issues as done or modify issue status -- that's handled entirely by the plugin's verdict processing code.
|
|
354
|
+
|
|
355
|
+
## Prompt Customization
|
|
356
|
+
|
|
357
|
+
Worker, audit, and rework prompts are externalized in `prompts.yaml`. Edit them to customize agent behavior without rebuilding the plugin.
|
|
358
|
+
|
|
359
|
+
### Managing Prompts
|
|
360
|
+
|
|
361
|
+
```bash
|
|
362
|
+
openclaw openclaw-linear prompts show # Print current prompts.yaml
|
|
363
|
+
openclaw openclaw-linear prompts path # Print resolved file path
|
|
364
|
+
openclaw openclaw-linear prompts validate # Validate structure and template variables
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### Template Variables
|
|
368
|
+
|
|
369
|
+
| Variable | Description |
|
|
370
|
+
|---|---|
|
|
371
|
+
| `{{identifier}}` | Issue identifier (e.g., `API-123`) |
|
|
372
|
+
| `{{title}}` | Issue title |
|
|
373
|
+
| `{{description}}` | Full issue body |
|
|
374
|
+
| `{{worktreePath}}` | Path to the git worktree |
|
|
375
|
+
| `{{tier}}` | Assessed complexity tier |
|
|
376
|
+
| `{{attempt}}` | Current attempt number (0-based) |
|
|
377
|
+
| `{{gaps}}` | Audit gaps from previous failed attempt (rework only) |
|
|
378
|
+
|
|
379
|
+
### Override Path
|
|
380
|
+
|
|
381
|
+
Set `promptsPath` in plugin config to load prompts from a custom location:
|
|
382
|
+
|
|
383
|
+
```json
|
|
384
|
+
{
|
|
385
|
+
"plugins": {
|
|
386
|
+
"entries": {
|
|
387
|
+
"openclaw-linear": {
|
|
388
|
+
"config": {
|
|
389
|
+
"promptsPath": "/path/to/my/prompts.yaml"
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
## Notifications
|
|
398
|
+
|
|
399
|
+
The plugin can post dispatch lifecycle events to a Discord channel. Configure `flowDiscordChannel` in plugin config with the channel ID.
|
|
400
|
+
|
|
401
|
+
Events posted:
|
|
402
|
+
|
|
403
|
+
| Event | Message |
|
|
404
|
+
|---|---|
|
|
405
|
+
| Dispatch | `**API-123** dispatched -- Fix auth bug` |
|
|
406
|
+
| Worker started | `**API-123** worker started (attempt 0)` |
|
|
407
|
+
| Audit in progress | `**API-123** audit in progress` |
|
|
408
|
+
| Audit passed | `**API-123** passed audit. PR ready.` |
|
|
409
|
+
| Audit failed | `**API-123** failed audit (attempt 1). Gaps: missing test coverage` |
|
|
410
|
+
| Escalation | `**API-123** needs human review -- audit failed 3x` |
|
|
411
|
+
|
|
412
|
+
## Coding Tool (`code_run`)
|
|
413
|
+
|
|
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.
|
|
415
|
+
|
|
416
|
+
### Supported Backends
|
|
417
|
+
|
|
418
|
+
| Backend | CLI | Stream Format | Key Flags |
|
|
419
|
+
|---|---|---|---|
|
|
420
|
+
| **Codex** (OpenAI) | `codex` | JSONL | `--full-auto`, `-q` |
|
|
421
|
+
| **Claude Code** (Anthropic) | `claude` | JSONL (`stream-json`) | `--print`, `--dangerously-skip-permissions`, `--verbose` |
|
|
422
|
+
| **Gemini CLI** (Google) | `gemini` | JSONL (`stream-json`) | `--yolo`, `-o stream-json` |
|
|
423
|
+
|
|
424
|
+
### Backend Resolution Priority
|
|
425
|
+
|
|
426
|
+
1. **Explicit `backend` parameter** -- Agent passes `backend: "gemini"` (or any alias)
|
|
427
|
+
2. **Per-agent override** -- `agentCodingTools` in `coding-tools.json`
|
|
428
|
+
3. **Global default** -- `codingTool` in `coding-tools.json`
|
|
429
|
+
4. **Hardcoded fallback** -- `"claude"`
|
|
430
|
+
|
|
431
|
+
## Linear Issue Management (`linearis` Skill)
|
|
432
|
+
|
|
433
|
+
Issue management is handled by the **`linearis`** CLI, installed as an OpenClaw skill. Agents use `linearis` via exec.
|
|
434
|
+
|
|
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
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
## Configuration Reference
|
|
446
446
|
|
|
447
447
|
### Plugin Config
|
|
448
448
|
|
|
449
|
-
|
|
449
|
+
Set in `openclaw.json` under the plugin entry:
|
|
450
450
|
|
|
451
451
|
| Key | Type | Default | Description |
|
|
452
452
|
|---|---|---|---|
|
|
453
|
-
| `defaultAgentId` | string |
|
|
453
|
+
| `defaultAgentId` | string | `"default"` | Agent ID for pipeline workers and audit |
|
|
454
454
|
| `enableAudit` | boolean | `true` | Run the auditor stage after implementation |
|
|
455
455
|
| `enableOrchestration` | boolean | `true` | Allow agents to use `spawn_agent`/`ask_agent` |
|
|
456
|
-
| `codexBaseRepo` | string |
|
|
457
|
-
| `codexModel` | string |
|
|
458
|
-
| `codexTimeoutMs` | number | `600000` | Default timeout for coding CLIs |
|
|
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 |
|
|
459
464
|
|
|
460
|
-
###
|
|
465
|
+
### Environment Variables
|
|
461
466
|
|
|
462
|
-
|
|
|
463
|
-
|
|
464
|
-
| `
|
|
465
|
-
| `
|
|
466
|
-
| `
|
|
467
|
-
| `
|
|
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) |
|
|
468
474
|
|
|
469
475
|
### Agent Profile Fields
|
|
470
476
|
|
|
471
477
|
| Field | Required | Description |
|
|
472
478
|
|---|---|---|
|
|
473
479
|
| `label` | Yes | Display name shown on comments in Linear |
|
|
474
|
-
| `mission` | Yes | Role description (injected as context
|
|
475
|
-
| `isDefault` | One agent | Handles issue triage and the pipeline |
|
|
480
|
+
| `mission` | Yes | Role description (injected as context) |
|
|
481
|
+
| `isDefault` | One agent | Handles issue triage and the dispatch pipeline |
|
|
476
482
|
| `mentionAliases` | Yes | `@mention` triggers (e.g., `["qa", "tester"]`) |
|
|
477
483
|
| `avatarUrl` | No | Avatar for branded comments |
|
|
478
484
|
|
|
479
485
|
### CLI
|
|
480
486
|
|
|
481
487
|
```bash
|
|
482
|
-
openclaw openclaw-linear auth
|
|
483
|
-
openclaw openclaw-linear status
|
|
488
|
+
openclaw openclaw-linear auth # Run OAuth authorization
|
|
489
|
+
openclaw openclaw-linear status # Check connection and token status
|
|
490
|
+
openclaw openclaw-linear worktrees # List active worktrees
|
|
491
|
+
openclaw openclaw-linear worktrees --prune <path> # Remove a worktree
|
|
492
|
+
openclaw openclaw-linear prompts show # Print current prompts
|
|
493
|
+
openclaw openclaw-linear prompts path # Print resolved prompts file path
|
|
494
|
+
openclaw openclaw-linear prompts validate # Validate prompt structure
|
|
484
495
|
```
|
|
485
496
|
|
|
486
497
|
## Troubleshooting
|
|
@@ -492,18 +503,21 @@ systemctl --user status openclaw-gateway # Is the gateway running?
|
|
|
492
503
|
openclaw openclaw-linear status # Is the token valid?
|
|
493
504
|
journalctl --user -u openclaw-gateway -f # Watch live logs
|
|
494
505
|
linearis issues list -l 1 # Is linearis authenticated?
|
|
506
|
+
openclaw openclaw-linear prompts validate # Are prompts valid?
|
|
495
507
|
```
|
|
496
508
|
|
|
497
509
|
### Common Issues
|
|
498
510
|
|
|
499
511
|
| Problem | Cause | Fix |
|
|
500
512
|
|---|---|---|
|
|
501
|
-
| Agent says "closing" but doesn't | No issue management tool
|
|
502
|
-
| `code_run` uses wrong backend |
|
|
503
|
-
| Claude Code "nested session" error | `CLAUDECODE` env var set | Plugin handles this automatically
|
|
504
|
-
| Gateway rejects plugin config keys | Strict validator
|
|
505
|
-
| Webhook events not arriving | Wrong
|
|
506
|
-
| OAuth token expired | Tokens expire ~24h | Auto-refreshes
|
|
513
|
+
| Agent says "closing" but doesn't | No issue management tool | Install `linearis`: `npx clawhub install linearis` |
|
|
514
|
+
| `code_run` uses wrong backend | Config mismatch | Check `coding-tools.json` |
|
|
515
|
+
| Claude Code "nested session" error | `CLAUDECODE` env var set | Plugin handles this automatically |
|
|
516
|
+
| Gateway rejects plugin config keys | Strict validator | Custom config goes in `coding-tools.json` |
|
|
517
|
+
| Webhook events not arriving | Wrong URL | Both webhooks must point to `/linear/webhook` |
|
|
518
|
+
| OAuth token expired | Tokens expire ~24h | Auto-refreshes; restart gateway if stuck |
|
|
519
|
+
| 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 |
|
|
507
521
|
|
|
508
522
|
## License
|
|
509
523
|
|