@calltelemetry/openclaw-linear 0.6.1 → 0.7.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 (38) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +115 -17
  3. package/index.ts +57 -22
  4. package/openclaw.plugin.json +37 -4
  5. package/package.json +2 -1
  6. package/prompts.yaml +47 -0
  7. package/src/api/linear-api.test.ts +494 -0
  8. package/src/api/linear-api.ts +193 -19
  9. package/src/gateway/dispatch-methods.ts +243 -0
  10. package/src/infra/cli.ts +284 -29
  11. package/src/infra/codex-worktree.ts +83 -0
  12. package/src/infra/commands.ts +156 -0
  13. package/src/infra/doctor.test.ts +4 -4
  14. package/src/infra/doctor.ts +7 -29
  15. package/src/infra/file-lock.test.ts +61 -0
  16. package/src/infra/file-lock.ts +49 -0
  17. package/src/infra/multi-repo.ts +85 -0
  18. package/src/infra/notify.test.ts +357 -108
  19. package/src/infra/notify.ts +222 -43
  20. package/src/infra/observability.ts +48 -0
  21. package/src/infra/resilience.test.ts +94 -0
  22. package/src/infra/resilience.ts +101 -0
  23. package/src/pipeline/artifacts.ts +38 -2
  24. package/src/pipeline/dag-dispatch.test.ts +553 -0
  25. package/src/pipeline/dag-dispatch.ts +390 -0
  26. package/src/pipeline/dispatch-service.ts +48 -1
  27. package/src/pipeline/dispatch-state.ts +2 -42
  28. package/src/pipeline/pipeline.ts +91 -17
  29. package/src/pipeline/planner.test.ts +334 -0
  30. package/src/pipeline/planner.ts +287 -0
  31. package/src/pipeline/planning-state.test.ts +236 -0
  32. package/src/pipeline/planning-state.ts +178 -0
  33. package/src/pipeline/tier-assess.test.ts +175 -0
  34. package/src/pipeline/webhook.ts +90 -17
  35. package/src/tools/dispatch-history-tool.ts +201 -0
  36. package/src/tools/orchestration-tools.test.ts +158 -0
  37. package/src/tools/planner-tools.test.ts +535 -0
  38. package/src/tools/planner-tools.ts +450 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-2026 CallTelemetry, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -39,8 +39,9 @@ An OpenClaw plugin that connects Linear to AI agents. Issues get triaged automat
39
39
  | **Real-time progress** | Agent activity (thinking, acting, responding) streams to Linear's UI |
40
40
  | **Unified `code_run`** | One tool, three backends (Codex, Claude Code, Gemini), configurable per agent |
41
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 |
42
+ | **Project planner** | Interactive interview builds out Linear issue hierarchies with dependency DAGs |
43
+ | **Customizable prompts** | `prompts.yaml` -- edit worker, audit, planner, and rework prompts without rebuilding |
44
+ | **Multi-channel notifications** | Dispatch events fan out to Discord, Slack, Telegram, Signal, or any OpenClaw channel |
44
45
  | **Artifact logging** | Every dispatch writes structured logs to `.claw/` in the worktree |
45
46
 
46
47
  ---
@@ -74,6 +75,12 @@ sequenceDiagram
74
75
  Plugin->>Agents: QA agent
75
76
  Agents-->>Plugin: Response
76
77
  Plugin-->>Linear: Branded comment
78
+
79
+ You->>Linear: Comment "@ctclaw plan this project"
80
+ Linear->>Plugin: Webhook (Comment)
81
+ Plugin->>Agents: Planner agent
82
+ Agents-->>Linear: Creates epics + issues + dependency DAG
83
+ Agents-->>Linear: Interview question
77
84
  ```
78
85
 
79
86
  ---
@@ -122,6 +129,23 @@ stateDiagram-v2
122
129
 
123
130
  All transitions use compare-and-swap (CAS) to prevent races. `dispatch-state.json` is the canonical source of truth.
124
131
 
132
+ ### Project Planner Pipeline
133
+
134
+ When `@ctclaw plan this project` is commented on a root issue, the plugin enters planning mode:
135
+
136
+ ```mermaid
137
+ flowchart TD
138
+ A["Comment: 'plan this project'"] --> B["INITIATE<br/>Register session, post welcome"]
139
+ B --> C["INTERVIEW<br/>Agent asks questions,<br/>creates issues + DAG"]
140
+ C -->|user responds| C
141
+ C -->|"'finalize plan'"| D["AUDIT<br/>DAG validation, completeness checks"]
142
+ D -->|Pass| E["APPROVED<br/>Project ready for dispatch"]
143
+ D -->|Fail| C
144
+ C -->|"'abandon'"| F["ABANDONED"]
145
+ ```
146
+
147
+ During planning mode, the planner creates epics, sub-issues, and dependency relationships (`blocks`/`blocked_by`) via 5 dedicated tools. Issue dispatch is blocked for projects in planning mode.
148
+
125
149
  ### Webhook Event Router
126
150
 
127
151
  ```mermaid
@@ -129,7 +153,7 @@ flowchart TD
129
153
  A["POST /linear/webhook"] --> B{"Event Type"}
130
154
  B --> C["AgentSessionEvent.created → Dispatch pipeline"]
131
155
  B --> D["AgentSessionEvent.prompted → Resume session"]
132
- B --> E["Comment.create → @mention routing"]
156
+ B --> E["Comment.create → @mention routing<br/>or planning mode"]
133
157
  B --> F["Issue.create → Auto-triage"]
134
158
  B --> G["Issue.update → Dispatch if assigned"]
135
159
  B --> H["AppUserNotification → Direct response"]
@@ -180,7 +204,9 @@ openclaw-linear/
180
204
  | |-- dispatch-service.ts Background monitor: stale detection, recovery, cleanup
181
205
  | |-- active-session.ts In-memory session registry (issueId -> session)
182
206
  | |-- tier-assess.ts Issue complexity assessment (junior/medior/senior)
183
- | +-- artifacts.ts .claw/ directory: manifest, logs, verdicts, summaries
207
+ | |-- artifacts.ts .claw/ directory: manifest, logs, verdicts, summaries
208
+ | |-- planner.ts Project planner orchestration (interview, audit)
209
+ | +-- planning-state.ts File-backed planning state (mirrors dispatch-state)
184
210
  |
185
211
  |-- agent/ Agent execution & monitoring
186
212
  | |-- agent.ts Embedded runner + subprocess fallback, retry on watchdog kill
@@ -193,7 +219,8 @@ openclaw-linear/
193
219
  | |-- claude-tool.ts Claude Code CLI runner (JSONL -> Linear activities)
194
220
  | |-- codex-tool.ts Codex CLI runner (JSONL -> Linear activities)
195
221
  | |-- gemini-tool.ts Gemini CLI runner (JSONL -> Linear activities)
196
- | +-- orchestration-tools.ts spawn_agent / ask_agent for multi-agent delegation
222
+ | |-- orchestration-tools.ts spawn_agent / ask_agent for multi-agent delegation
223
+ | +-- planner-tools.ts 5 planning tools (create/link/update issues, audit DAG)
197
224
  |
198
225
  |-- api/ Linear API & auth
199
226
  | |-- linear-api.ts GraphQL client, token resolution, auto-refresh
@@ -203,7 +230,7 @@ openclaw-linear/
203
230
  +-- infra/ Infrastructure utilities
204
231
  |-- cli.ts CLI subcommands (auth, status, worktrees, prompts)
205
232
  |-- codex-worktree.ts Git worktree create/remove/status/PR helpers
206
- +-- notify.ts Discord notifier (+ noop fallback)
233
+ +-- notify.ts Multi-channel notifier (Discord, Slack, Telegram, Signal)
207
234
  ```
208
235
 
209
236
  ---
@@ -401,6 +428,9 @@ Once set up, the plugin responds to Linear events automatically:
401
428
  | Assign an issue to the agent | Worker-audit pipeline runs with watchdog protection |
402
429
  | Trigger an agent session | Agent responds directly in the session |
403
430
  | Comment `@qa check the tests` | QA agent responds with its expertise |
431
+ | Comment `@ctclaw plan this project` | Planner agent enters interview mode, builds issue DAG |
432
+ | Reply during planning mode | Planner creates/updates issues and asks next question |
433
+ | Comment "finalize plan" | DAG audit runs: cycles, orphans, missing estimates/priorities |
404
434
  | Ask "close this issue" | Agent runs `linearis issues update API-123 --status Done` |
405
435
  | Ask "use gemini to review" | Agent calls `code_run` with `backend: "gemini"` |
406
436
 
@@ -435,7 +465,7 @@ Set in `openclaw.json` under the plugin entry:
435
465
  | `codexTimeoutMs` | number | `600000` | Legacy timeout for coding CLIs (ms) |
436
466
  | `worktreeBaseDir` | string | `"~/.openclaw/worktrees"` | Base directory for worktrees |
437
467
  | `dispatchStatePath` | string | `"~/.openclaw/linear-dispatch-state.json"` | Dispatch state file |
438
- | `flowDiscordChannel` | string | -- | Discord channel ID for notifications |
468
+ | `notifications` | object | -- | [Notification targets and event toggles](#notifications) |
439
469
  | `promptsPath` | string | -- | Override path for `prompts.yaml` |
440
470
  | `maxReworkAttempts` | number | `2` | Max audit failures before escalation |
441
471
  | `inactivitySec` | number | `120` | Kill sessions with no I/O for this long |
@@ -511,17 +541,78 @@ openclaw openclaw-linear prompts validate # Validate structure and template va
511
541
 
512
542
  ## Notifications
513
543
 
514
- Configure `flowDiscordChannel` in plugin config with a Discord channel ID. Events:
544
+ Dispatch lifecycle events fan out to any combination of OpenClaw channels -- Discord, Slack, Telegram, Signal, or any channel the runtime supports.
515
545
 
516
- | Event | Message |
517
- |---|---|
518
- | Dispatch | `**API-123** dispatched -- Fix auth bug` |
519
- | Worker started | `**API-123** worker started (attempt 0)` |
520
- | Audit in progress | `**API-123** audit in progress` |
521
- | Audit passed | `**API-123** passed audit. PR ready.` |
522
- | Audit failed | `**API-123** failed audit (attempt 1). Gaps: ...` |
523
- | Escalation | `**API-123** needs human review -- audit failed 3x` |
524
- | Watchdog kill | `**API-123** killed by watchdog (no I/O for 120s). Retrying.` |
546
+ ### Configuration
547
+
548
+ Add a `notifications` object to your plugin config:
549
+
550
+ ```json
551
+ {
552
+ "plugins": {
553
+ "entries": {
554
+ "openclaw-linear": {
555
+ "config": {
556
+ "notifications": {
557
+ "targets": [
558
+ { "channel": "discord", "target": "1471743433566715974" },
559
+ { "channel": "slack", "target": "C0123456789", "accountId": "my-acct" },
560
+ { "channel": "telegram", "target": "-1003884997363" }
561
+ ],
562
+ "events": {
563
+ "auditing": false
564
+ }
565
+ }
566
+ }
567
+ }
568
+ }
569
+ }
570
+ }
571
+ ```
572
+
573
+ **`targets`** -- Array of notification destinations. Each target specifies:
574
+
575
+ | Field | Required | Description |
576
+ |---|---|---|
577
+ | `channel` | Yes | OpenClaw channel name: `discord`, `slack`, `telegram`, `signal`, etc. |
578
+ | `target` | Yes | Channel/group/user ID to send to |
579
+ | `accountId` | No | Account ID for multi-account setups (Slack) |
580
+
581
+ **`events`** -- Per-event-type toggles. All events are enabled by default. Set to `false` to suppress.
582
+
583
+ ### Events
584
+
585
+ | Event | Kind | Example Message |
586
+ |---|---|---|
587
+ | Dispatch | `dispatch` | `API-123 dispatched -- Fix auth bug` |
588
+ | Worker started | `working` | `API-123 worker started (attempt 0)` |
589
+ | Audit in progress | `auditing` | `API-123 audit in progress` |
590
+ | Audit passed | `audit_pass` | `API-123 passed audit. PR ready.` |
591
+ | Audit failed | `audit_fail` | `API-123 failed audit (attempt 1). Gaps: no tests, missing validation` |
592
+ | Escalation | `escalation` | `API-123 needs human review -- audit failed 3x` |
593
+ | Stale detection | `stuck` | `API-123 stuck -- stale 2h` |
594
+ | Watchdog kill | `watchdog_kill` | `API-123 killed by watchdog (no I/O for 120s). Retrying (attempt 0).` |
595
+
596
+ ### Delivery
597
+
598
+ Messages route through OpenClaw's native runtime channel API:
599
+
600
+ - **Discord** -- `runtime.channel.discord.sendMessageDiscord()`
601
+ - **Slack** -- `runtime.channel.slack.sendMessageSlack()` (passes `accountId` for multi-workspace)
602
+ - **Telegram** -- `runtime.channel.telegram.sendMessageTelegram()` (silent mode)
603
+ - **Signal** -- `runtime.channel.signal.sendMessageSignal()`
604
+ - **Other** -- Falls back to `openclaw message send` CLI
605
+
606
+ Failures are isolated per target -- one channel going down doesn't block the others.
607
+
608
+ ### Notify CLI
609
+
610
+ ```bash
611
+ openclaw openclaw-linear notify status # Show configured targets and suppressed events
612
+ openclaw openclaw-linear notify test # Send test notification to all targets
613
+ openclaw openclaw-linear notify test --channel discord # Test only discord targets
614
+ openclaw openclaw-linear notify setup # Interactive target setup
615
+ ```
525
616
 
526
617
  ---
527
618
 
@@ -649,6 +740,13 @@ openclaw openclaw-linear worktrees --prune <path> # Remove a worktree
649
740
  openclaw openclaw-linear prompts show # Print current prompts
650
741
  openclaw openclaw-linear prompts path # Print resolved prompts file path
651
742
  openclaw openclaw-linear prompts validate # Validate prompt structure
743
+ openclaw openclaw-linear notify status # Show notification targets and event toggles
744
+ openclaw openclaw-linear notify test # Send test notification to all targets
745
+ openclaw openclaw-linear notify test --channel slack # Test specific channel only
746
+ openclaw openclaw-linear notify setup # Interactive notification target setup
747
+ openclaw openclaw-linear doctor # Run comprehensive health checks
748
+ openclaw openclaw-linear doctor --fix # Auto-fix safe issues
749
+ openclaw openclaw-linear doctor --json # Output results as JSON
652
750
  ```
653
751
 
654
752
  ---
package/index.ts CHANGED
@@ -7,9 +7,15 @@ import { handleLinearWebhook } from "./src/pipeline/webhook.js";
7
7
  import { handleOAuthCallback } from "./src/api/oauth-callback.js";
8
8
  import { LinearAgentApi, resolveLinearToken } from "./src/api/linear-api.js";
9
9
  import { createDispatchService } from "./src/pipeline/dispatch-service.js";
10
+ import { registerDispatchMethods } from "./src/gateway/dispatch-methods.js";
10
11
  import { readDispatchState, lookupSessionMapping, getActiveDispatch } from "./src/pipeline/dispatch-state.js";
11
12
  import { triggerAudit, processVerdict, type HookContext } from "./src/pipeline/pipeline.js";
12
- import { createDiscordNotifier, createNoopNotifier, type NotifyFn } from "./src/infra/notify.js";
13
+ import { createNotifierFromConfig, type NotifyFn } from "./src/infra/notify.js";
14
+ import { readPlanningState, setPlanningCache } from "./src/pipeline/planning-state.js";
15
+ import { createPlannerTools } from "./src/tools/planner-tools.js";
16
+ import { registerDispatchCommands } from "./src/infra/commands.js";
17
+ import { createDispatchHistoryTool } from "./src/tools/dispatch-history-tool.js";
18
+ import { readDispatchState as readStateForHook, listActiveDispatches as listActiveForHook } from "./src/pipeline/dispatch-state.js";
13
19
 
14
20
  export default function register(api: OpenClawPluginApi) {
15
21
  const pluginConfig = (api as any).pluginConfig as Record<string, unknown> | undefined;
@@ -36,6 +42,15 @@ export default function register(api: OpenClawPluginApi) {
36
42
  return createLinearTools(api, ctx);
37
43
  });
38
44
 
45
+ // Register planner tools (context injected at runtime via setActivePlannerContext)
46
+ api.registerTool(() => createPlannerTools());
47
+
48
+ // Register dispatch_history tool for agent context
49
+ api.registerTool(() => createDispatchHistoryTool(api, pluginConfig));
50
+
51
+ // Register zero-LLM slash commands for dispatch ops
52
+ registerDispatchCommands(api);
53
+
39
54
  // Register Linear webhook handler on a dedicated route
40
55
  api.registerHttpRoute({
41
56
  path: "/linear/webhook",
@@ -63,31 +78,25 @@ export default function register(api: OpenClawPluginApi) {
63
78
  // Register dispatch monitor service (stale detection, session hydration, cleanup)
64
79
  api.registerService(createDispatchService(api));
65
80
 
81
+ // Register dispatch gateway RPC methods (list, get, retry, escalate, cancel, stats)
82
+ registerDispatchMethods(api);
83
+
84
+ // Hydrate planning state on startup
85
+ readPlanningState(pluginConfig?.planningStatePath as string | undefined).then((state) => {
86
+ for (const session of Object.values(state.sessions)) {
87
+ if (session.status === "interviewing" || session.status === "plan_review") {
88
+ setPlanningCache(session);
89
+ api.logger.info(`Planning: restored session for ${session.projectName} (${session.rootIdentifier})`);
90
+ }
91
+ }
92
+ }).catch((err) => api.logger.warn(`Planning state hydration failed: ${err}`));
93
+
66
94
  // ---------------------------------------------------------------------------
67
95
  // Dispatch pipeline v2: notifier + agent_end lifecycle hook
68
96
  // ---------------------------------------------------------------------------
69
97
 
70
- // Instantiate notifier (Discord if configured, otherwise noop)
71
- const discordBotToken = (() => {
72
- try {
73
- const config = JSON.parse(
74
- require("node:fs").readFileSync(
75
- require("node:path").join(process.env.HOME ?? "/home/claw", ".openclaw", "openclaw.json"),
76
- "utf8",
77
- ),
78
- );
79
- return config?.channels?.discord?.token as string | undefined;
80
- } catch { return undefined; }
81
- })();
82
- const flowDiscordChannel = pluginConfig?.flowDiscordChannel as string | undefined;
83
-
84
- const notify: NotifyFn = (discordBotToken && flowDiscordChannel)
85
- ? createDiscordNotifier(discordBotToken, flowDiscordChannel)
86
- : createNoopNotifier();
87
-
88
- if (flowDiscordChannel && discordBotToken) {
89
- api.logger.info(`Linear dispatch: Discord notifications enabled (channel: ${flowDiscordChannel})`);
90
- }
98
+ // Instantiate notifier (Discord, Slack, or both — config-driven)
99
+ const notify: NotifyFn = createNotifierFromConfig(pluginConfig, api.runtime);
91
100
 
92
101
  // Register agent_end hook — safety net for sessions_spawn sub-agents.
93
102
  // In the current implementation, the worker→audit→verdict flow runs inline
@@ -163,6 +172,32 @@ export default function register(api: OpenClawPluginApi) {
163
172
  }
164
173
  });
165
174
 
175
+ // Inject recent dispatch history as context for worker/audit agents
176
+ api.on("before_agent_start", async (event: any, ctx: any) => {
177
+ try {
178
+ const sessionKey = ctx?.sessionKey ?? "";
179
+ if (!sessionKey.startsWith("linear-worker-") && !sessionKey.startsWith("linear-audit-")) return;
180
+
181
+ const statePath = pluginConfig?.dispatchStatePath as string | undefined;
182
+ const state = await readStateForHook(statePath);
183
+ const active = listActiveForHook(state);
184
+
185
+ // Include up to 3 recent active dispatches as context
186
+ const recent = active.slice(0, 3);
187
+ if (recent.length === 0) return;
188
+
189
+ const lines = recent.map(d =>
190
+ `- **${d.issueIdentifier}** (${d.tier}): ${d.status}, attempt ${d.attempt}`
191
+ );
192
+
193
+ return {
194
+ prependContext: `<dispatch-history>\nActive dispatches:\n${lines.join("\n")}\n</dispatch-history>\n\n`,
195
+ };
196
+ } catch {
197
+ // Never block agent start for telemetry
198
+ }
199
+ });
200
+
166
201
  // Narration Guard: catch short "Let me explore..." responses that narrate intent
167
202
  // without actually calling tools, and append a warning for the user.
168
203
  const NARRATION_PATTERNS = [
@@ -2,7 +2,7 @@
2
2
  "id": "openclaw-linear",
3
3
  "name": "Linear Agent",
4
4
  "description": "Linear integration with OAuth support, agent pipeline, and webhook-driven AI agent lifecycle",
5
- "version": "0.2.0",
5
+ "version": "0.7.0",
6
6
  "configSchema": {
7
7
  "type": "object",
8
8
  "additionalProperties": false,
@@ -15,12 +15,45 @@
15
15
  "defaultAgentId": { "type": "string", "description": "OpenClaw agent ID to use for pipeline stages" },
16
16
  "enableAudit": { "type": "boolean", "description": "Run auditor stage after implementation", "default": true },
17
17
  "codexBaseRepo": { "type": "string", "description": "Path to git repo for Codex worktrees", "default": "/home/claw/ai-workspace" },
18
- "codexModel": { "type": "string", "description": "Default Codex model (optional — uses Codex default if omitted)" },
19
- "codexTimeoutMs": { "type": "number", "description": "Default Codex timeout in milliseconds", "default": 600000 },
20
18
  "enableOrchestration": { "type": "boolean", "description": "Allow agents to spawn sub-agents via spawn_agent/ask_agent tools", "default": true },
21
19
  "worktreeBaseDir": { "type": "string", "description": "Base directory for persistent git worktrees (default: ~/.openclaw/worktrees)" },
20
+ "repos": { "type": "object", "description": "Multi-repo map (name → path, e.g. {\"api\": \"/home/claw/api\", \"frontend\": \"/home/claw/frontend\"})", "additionalProperties": { "type": "string" } },
22
21
  "dispatchStatePath": { "type": "string", "description": "Path to dispatch state JSON file (default: ~/.openclaw/linear-dispatch-state.json)" },
23
- "flowDiscordChannel": { "type": "string", "description": "Discord channel ID for dispatch lifecycle notifications (omit to disable)" },
22
+ "planningStatePath": { "type": "string", "description": "Path to planning state JSON file (default: ~/.openclaw/linear-planning-state.json)" },
23
+ "notifications": {
24
+ "type": "object",
25
+ "description": "Dispatch lifecycle notification config — fan-out to any combination of channels",
26
+ "properties": {
27
+ "targets": {
28
+ "type": "array",
29
+ "description": "Notification targets — each routes to an OpenClaw channel",
30
+ "items": {
31
+ "type": "object",
32
+ "required": ["channel", "target"],
33
+ "properties": {
34
+ "channel": { "type": "string", "description": "OpenClaw channel name: discord, slack, telegram, signal, etc." },
35
+ "target": { "type": "string", "description": "Channel/group/user ID to send to" },
36
+ "accountId": { "type": "string", "description": "Account ID for multi-account channel setups (optional)" }
37
+ }
38
+ }
39
+ },
40
+ "events": {
41
+ "type": "object",
42
+ "description": "Per-event-type toggles (all default true, set false to suppress)",
43
+ "properties": {
44
+ "dispatch": { "type": "boolean" },
45
+ "working": { "type": "boolean" },
46
+ "auditing": { "type": "boolean" },
47
+ "audit_pass": { "type": "boolean" },
48
+ "audit_fail": { "type": "boolean" },
49
+ "escalation": { "type": "boolean" },
50
+ "stuck": { "type": "boolean" },
51
+ "watchdog_kill": { "type": "boolean" }
52
+ }
53
+ },
54
+ "richFormat": { "type": "boolean", "description": "Send rich embeds (Discord) and HTML (Telegram) instead of plain text", "default": false }
55
+ }
56
+ },
24
57
  "promptsPath": { "type": "string", "description": "Override path for prompts.yaml (default: ships with plugin)" },
25
58
  "maxReworkAttempts": { "type": "number", "description": "Max audit failures before escalation", "default": 2 },
26
59
  "inactivitySec": { "type": "number", "description": "Kill sessions with no I/O for this many seconds (default: 120)", "default": 120 },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calltelemetry/openclaw-linear",
3
- "version": "0.6.1",
3
+ "version": "0.7.1",
4
4
  "description": "Linear Agent plugin for OpenClaw — webhook-driven AI pipeline with OAuth, multi-agent routing, and issue triage",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -45,6 +45,7 @@
45
45
  ]
46
46
  },
47
47
  "dependencies": {
48
+ "cockatiel": "^3.2.1",
48
49
  "yaml": "^2.8.2"
49
50
  }
50
51
  }
package/prompts.yaml CHANGED
@@ -77,3 +77,50 @@ rework:
77
77
 
78
78
  Address these specific issues in your rework. Focus on the gaps listed above.
79
79
  Remember: you do NOT have linearis access. Just fix the code and return a text summary.
80
+
81
+ planner:
82
+ system: |
83
+ You are a product planning specialist working with Linear. Your job is to interview
84
+ the user about features they want to build, then decompose them into a well-structured
85
+ project with epics, issues, and sub-issues connected by a dependency graph.
86
+
87
+ STRUCTURE RULES:
88
+ - Epics are high-level feature areas. Mark them with isEpic=true.
89
+ - Issues under epics are concrete deliverables with acceptance criteria.
90
+ - Sub-issues are atomic work units that together complete a parent issue.
91
+ - Use "blocks" relationships to express ordering: if A must finish before B starts, A blocks B.
92
+ - Every issue description must include clear acceptance criteria.
93
+ - Every non-epic issue needs a story point estimate and priority.
94
+
95
+ INTERVIEW APPROACH:
96
+ - Ask ONE focused question at a time. Never dump a questionnaire.
97
+ - After each user response, create or update issues to capture what you learned.
98
+ - Briefly summarize what you added before asking your next question.
99
+ - When the plan feels complete, invite the user to say "finalize plan".
100
+
101
+ interview: |
102
+ ## Project: {{projectName}} ({{rootIdentifier}})
103
+
104
+ ### Current Plan
105
+ {{planSnapshot}}
106
+
107
+ ### Recent conversation ({{turnCount}} turns so far)
108
+ {{commentHistory}}
109
+
110
+ ### User just said:
111
+ > {{userMessage}}
112
+
113
+ Continue the planning interview. Use your tools to create/update Linear issues based
114
+ on the user's input, then respond with a summary of changes and your next question.
115
+
116
+ audit_prompt: |
117
+ The user wants to finalize the plan for {{projectName}}. Run the `audit_plan` tool.
118
+ If it passes, congratulate and summarize the complete plan.
119
+ If it fails, list the specific issues that need attention and ask the user to help.
120
+
121
+ welcome: |
122
+ I'm entering planning mode for **{{projectName}}**. I'll interview you about the
123
+ features you want to build, then structure everything into Linear issues with proper
124
+ epic hierarchy and dependency chains.
125
+
126
+ Let's start — what is this project about, and what are the main feature areas?