Skip to content

Commit 997c887

Browse files
docs+feat: update README for recent work, add pending pipeline improvements
README: update Project Status checklist (planner, cross-model review, sub-issue decomposition, multi-repo, webhook provisioning, setup wizard, project context, per-backend CLI tools all checked off). Replace all code_run references with cli_codex/cli_claude/cli_gemini. Update test count to 1170+. Add setup command to CLI reference. Pipeline: guidance caching, artifact collection, multi-repo label sync enhancements, backend tool streaming improvements, Linear API extensions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 3007bca commit 997c887

19 files changed

Lines changed: 1186 additions & 141 deletions

README.md

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,18 @@ Connect Linear to AI agents. Issues get triaged, implemented, and audited — au
3030
- [x] Worker → Auditor pipeline (hard-enforced, not LLM-mediated)
3131
- [x] Audit rework loop (gaps fed back, automatic retry)
3232
- [x] Watchdog timeout + escalation
33-
- [x] Webhook deduplication (60s sliding window across session/comment/assignment)
34-
- [ ] Multi-repo worktree support
35-
- [ ] Project planner (interview → user stories → sub-issues → DAG dispatch)
36-
- [ ] Cross-model plan review (Claude ↔ Codex ↔ Gemini)
33+
- [x] Webhook deduplication (60s sliding window + `activeRuns` race guard on all paths)
34+
- [x] Webhook auto-provisioning (`webhooks setup` CLI, `doctor --fix`)
35+
- [x] Multi-repo worktree support
36+
- [x] Project planner (interview → user stories → sub-issues → DAG dispatch)
37+
- [x] Cross-model plan review (Claude ↔ Codex ↔ Gemini)
3738
- [x] Issue closure with summary report
38-
- [ ] Sub-issue decomposition (orchestrator-level only)
39+
- [x] Sub-issue decomposition (orchestrator-level only)
3940
- [x] `spawn_agent` / `ask_agent` sub-agent tools
40-
- [x] CI + coverage badges (1000+ tests, Codecov integration)
41+
- [x] CI + coverage badges (1170+ tests, Codecov integration)
42+
- [x] Setup wizard (`openclaw openclaw-linear setup`) + `doctor --fix` auto-repair
43+
- [x] Project context auto-detection (repo, framework, build/test commands → worker/audit prompts)
44+
- [x] Per-backend CLI tools (`cli_codex`, `cli_claude`, `cli_gemini`) with Linear session activity streaming
4145
- [ ] **Worktree → PR merge**`createPullRequest()` exists but is not wired into the pipeline. After audit pass, commits sit on a `codex/{identifier}` branch. You create the PR manually.
4246
- [ ] **Sub-agent worktree sharing** — Sub-agents spawned via `spawn_agent`/`ask_agent` do not inherit the parent worktree. They run in their own session without code access.
4347
- [ ] **Parallel worktree conflict resolution** — DAG dispatch runs up to 3 issues concurrently in separate worktrees, but there's no merge conflict detection across them.
@@ -109,12 +113,12 @@ The end result: you work in Linear. You create issues, assign them, comment in p
109113

110114
- **Named agents** — Define agents with different roles and expertise. Route work by `@mention` or natural language ("hey kaylee look at this").
111115
- **Intent classification** — An LLM classifier (~300 tokens, ~2s) runs on every user request across all webhook paths — not just comments. Classifies intent and gates work requests on untriaged issues. Regex fallback if the classifier fails.
112-
- **Scope enforcement** — Three-layer defense prevents agents from building code on issues that haven't been planned. Intent gate blocks `request_work` pre-dispatch; prompt-level constraints limit `code_run` to planning-only; a `before_tool_call` hook prepends hard constraints to worker prompts.
116+
- **Scope enforcement** — Three-layer defense prevents agents from building code on issues that haven't been planned. Intent gate blocks `request_work` pre-dispatch; prompt-level constraints limit CLI tools to planning-only; a `before_tool_call` hook prepends hard constraints to worker prompts.
113117
- **One-time detour**`@mention` a different agent in a session and it handles that single interaction. The session stays with the original agent.
114118

115119
### Multi-Backend & Multi-Repo
116120

117-
- **Three coding backends** — Codex (OpenAI), Claude (Anthropic), Gemini (Google). Configurable globally or per-agent. The agent writes the prompt; the plugin handles backend selection.
121+
- **Three coding backends** — Codex (OpenAI), Claude (Anthropic), Gemini (Google). Configurable globally or per-agent. Each backend registers as a dedicated tool (`cli_codex`, `cli_claude`, `cli_gemini`) so agents and Linear session UI show exactly which backend is running. Per-agent overrides let you assign different backends to different team members.
118122
- **Multi-repo dispatch** — Tag an issue with `<!-- repos: api, frontend -->` and the worker gets isolated worktrees for each repo. One issue, multiple codebases, one agent session.
119123

120124
### Operations
@@ -723,18 +727,18 @@ To move forward:
723727
I can help you scope and plan — just ask questions or discuss the approach.
724728
```
725729

726-
This prevents the most common failure mode: an agent receiving a casual comment like "build X" on an unscoped issue and immediately spinning up `code_run` to build something that was never planned.
730+
This prevents the most common failure mode: an agent receiving a casual comment like "build X" on an unscoped issue and immediately spinning up a CLI tool to build something that was never planned.
727731

728732
**What's allowed on untriaged issues:**
729733
- Questions, discussion, scope refinement
730734
- Planning (`plan_start`, `plan_continue`, `plan_finalize`)
731735
- Agent routing (`@mention` or natural language)
732736
- Issue closure
733-
- `code_run` in **planning mode only** — workers can explore code and write plan files but cannot create, modify, or delete source code
737+
- `cli_codex`/`cli_claude`/`cli_gemini` in **planning mode only** — workers can explore code and write plan files but cannot create, modify, or delete source code
734738

735739
**What's blocked on untriaged issues:**
736740
- `request_work` intent — the gate returns a rejection message before any agent runs
737-
- Full `code_run` implementation — even if the orchestrator LLM ignores prompt rules, a `before_tool_call` hook prepends hard planning-only constraints to the worker's prompt
741+
- Full CLI tool implementation — even if the orchestrator LLM ignores prompt rules, a `before_tool_call` hook prepends hard planning-only constraints to the worker's prompt
738742

739743
### Agent Routing
740744

@@ -885,7 +889,7 @@ Add settings under the plugin entry in `openclaw.json`:
885889
| `notifications` | object || Notification targets (see [Notifications](#notifications)) |
886890
| `inactivitySec` | number | `120` | Kill agent if silent this long |
887891
| `maxTotalSec` | number | `7200` | Max total agent session time |
888-
| `toolTimeoutSec` | number | `600` | Max single `code_run` time |
892+
| `toolTimeoutSec` | number | `600` | Max single CLI tool time |
889893
| `enableGuidance` | boolean | `true` | Inject Linear workspace/team guidance into agent prompts |
890894
| `teamGuidanceOverrides` | object || Per-team guidance toggle. Key = team ID, value = boolean. Unset teams inherit `enableGuidance`. |
891895
| `claudeApiKey` | string || Anthropic API key for Claude CLI (passed as `ANTHROPIC_API_KEY` env var). Required if using Claude backend. |
@@ -952,7 +956,7 @@ Create `coding-tools.json` in the plugin root to configure which CLI backend age
952956
}
953957
```
954958

955-
The agent calls `code_run` without knowing which backend is active. Resolution order: explicit `backend` parameter > per-agent override > global default > `"codex"`.
959+
Each backend registers as a dedicated tool — `cli_codex`, `cli_claude`, or `cli_gemini` — so agents and Linear's session UI show exactly which backend is running. The agent's prompt references the correct tool name automatically. Resolution order for which tool is exposed: per-agent override (`agentCodingTools`) > global default (`codingTool`) > `"codex"`.
956960

957961
#### Claude API Key
958962

@@ -1126,7 +1130,7 @@ rework:
11261130
| `{{reviewModel}}` | Name of cross-model reviewer (planner review) |
11271131
| `{{crossModelFeedback}}` | Review recommendations (planner review) |
11281132
| `{{guidance}}` | Linear workspace/team guidance (if available, empty string otherwise) |
1129-
| `{{projectContext}}` | Project context from config (project name, repo paths). Framework/build/test info belongs in CLAUDE.md. |
1133+
| `{{projectContext}}` | Auto-detected project context (repo paths, framework, build commands, test commands) injected into worker and audit prompts. |
11301134

11311135
### CLI
11321136

@@ -1287,7 +1291,7 @@ If an agent goes silent (LLM timeout, API hang, CLI lockup), the watchdog handle
12871291
|---|---|---|
12881292
| `inactivitySec` | 120s | Kill if no output for this long |
12891293
| `maxTotalSec` | 7200s (2 hrs) | Hard ceiling on total session time |
1290-
| `toolTimeoutSec` | 600s (10 min) | Max time for a single `code_run` call |
1294+
| `toolTimeoutSec` | 600s (10 min) | Max time for a single CLI tool call |
12911295

12921296
Configure per-agent in `agent-profiles.json` or globally in plugin config.
12931297

@@ -1297,9 +1301,9 @@ Configure per-agent in `agent-profiles.json` or globally in plugin config.
12971301

12981302
Every agent session gets these registered tools. They're available as native tool calls — no CLI parsing, no shell execution, no flag guessing.
12991303

1300-
### `code_run` — Coding backend dispatch
1304+
### `cli_codex` / `cli_claude` / `cli_gemini` — Coding backend tools
13011305

1302-
Sends a task to whichever coding CLI is configured (Codex, Claude Code, or Gemini). The agent writes the prompt; the plugin handles backend selection, worktree setup, and output capture.
1306+
Three per-backend tools that send tasks to their respective coding CLIs. Each agent sees only the tool matching its configured backend (e.g., an agent configured for `codex` gets `cli_codex`). The tool name is visible in Linear's agent session UI, so you always know which backend is running. The agent writes the prompt; the plugin handles worktree setup, session activity streaming, and output capture.
13031307

13041308
### `linear_issues` — Native Linear API
13051309

@@ -1320,7 +1324,7 @@ Agents call `linear_issues` with typed JSON parameters. The tool wraps the Linea
13201324

13211325
Delegate work to other crew agents. `spawn_agent` is fire-and-forget (parallel), `ask_agent` waits for a reply (synchronous). Disabled with `enableOrchestration: false`.
13221326

1323-
Sub-agents run in their own context — they do **not** share the parent's worktree or get `code_run` access. They're useful for reasoning, research, and coordination (e.g., "ask Inara how to phrase this error message") but cannot directly modify code. To give a sub-agent code context, include the relevant snippets in the task message.
1327+
Sub-agents run in their own context — they do **not** share the parent's worktree or get CLI tool access. They're useful for reasoning, research, and coordination (e.g., "ask Inara how to phrase this error message") but cannot directly modify code. To give a sub-agent code context, include the relevant snippets in the task message.
13241328

13251329
### `dispatch_history` — Recent dispatch context
13261330

@@ -1330,9 +1334,9 @@ Returns recent dispatch activity. Agents use this for situational awareness when
13301334

13311335
Tool access varies by context. Orchestrators get the full toolset; workers and auditors are restricted:
13321336

1333-
| Context | `linear_issues` | `code_run` | `spawn_agent` / `ask_agent` | Filesystem |
1337+
| Context | `linear_issues` | `cli_*` | `spawn_agent` / `ask_agent` | Filesystem |
13341338
|---|---|---|---|---|
1335-
| Orchestrator (triaged issue) | Full (read, create, update, comment) | Yes | Yes | Read + write |
1339+
| Orchestrator (triaged issue) | Full (read, create, update, comment) | Yes (backend-specific tool) | Yes | Read + write |
13361340
| Orchestrator (untriaged issue) | Read only | Planning only | Yes | Read + write |
13371341
| Worker | None | None | None | Read + write |
13381342
| Auditor | Prompt-constrained (has tool, instructed to verify only) | None | None | Read only (by prompt) |
@@ -1342,7 +1346,7 @@ Tool access varies by context. Orchestrators get the full toolset; workers and a
13421346

13431347
**Auditors** have access to `linear_issues` (the tool is registered) but are instructed via prompt to verify only — they return a JSON verdict, not code or issue mutations. Write access is not enforced at the tool level.
13441348

1345-
**Sub-agents** spawned via `spawn_agent`/`ask_agent` run in their own session with no worktree access and no `code_run`. They're information workers — useful for reasoning and coordination, not code execution.
1349+
**Sub-agents** spawned via `spawn_agent`/`ask_agent` run in their own session with no worktree access and no CLI tools. They're information workers — useful for reasoning and coordination, not code execution.
13461350

13471351
---
13481352

@@ -1457,12 +1461,12 @@ The plugin registers four lifecycle hooks via `api.on()` in `index.ts`:
14571461
- Reads dispatch state and finds up to 3 active dispatches
14581462
- Prepends a `<dispatch-history>` block so the agent has situational awareness of concurrent work
14591463

1460-
**`before_tool_call`** — Planning-only enforcement for `code_run`. When the active issue is not in "started" state:
1464+
**`before_tool_call`** — Planning-only enforcement for CLI tools (`cli_codex`, `cli_claude`, `cli_gemini`). When the active issue is not in "started" state:
14611465
- Fetches the issue's current workflow state from the Linear API
14621466
- If the issue is in Triage, Todo, Backlog, or any non-started state, prepends hard constraints to the worker's prompt:
14631467
- Workers may read/explore files and write plan files (PLAN.md, design docs)
14641468
- Workers must NOT create/modify/delete source code, run deployments, or make system changes
1465-
- This is the deepest layer of scope enforcement — even if the orchestrator LLM ignores prompt-level scope rules and calls `code_run` anyway, the worker receives constraints that prevent implementation
1469+
- This is the deepest layer of scope enforcement — even if the orchestrator LLM ignores prompt-level scope rules and calls a CLI tool anyway, the worker receives constraints that prevent implementation
14661470

14671471
**`message_sending`** — Narration guard. Catches short (~250 char) "Let me explore..." responses where the agent narrates intent without actually calling tools:
14681472
- Appends a warning: "Agent acknowledged but may not have completed the task"
@@ -1762,7 +1766,8 @@ openclaw openclaw-linear prompts show # View the active prompts
17621766
## CLI Reference
17631767

17641768
```bash
1765-
# Auth & status
1769+
# Setup & auth
1770+
openclaw openclaw-linear setup # Guided first-time setup (profiles, auth, webhook, doctor)
17661771
openclaw openclaw-linear auth # Run OAuth flow
17671772
openclaw openclaw-linear status # Check connection
17681773

@@ -1826,8 +1831,8 @@ journalctl --user -u openclaw-gateway -f # Watch live logs
18261831
|---|---|
18271832
| Agent goes silent | Watchdog auto-kills after `inactivitySec` and retries. Check logs for `Watchdog KILL`. |
18281833
| Dispatch stuck after watchdog | Both retries failed. Check `.claw/log.jsonl`. Re-assign issue to restart. |
1829-
| `code_run` uses wrong backend | Check `coding-tools.json`explicit backend > per-agent > global default. Run `code-run doctor` to see routing. |
1830-
| `code_run` fails at runtime | Run `openclaw openclaw-linear code-run doctor` — checks binary, API key, and live callability for each backend. |
1834+
| `cli_*` uses wrong backend | Check `coding-tools.json` — per-agent override > global default. Run `code-run doctor` to see routing. |
1835+
| `cli_*` fails at runtime | Run `openclaw openclaw-linear code-run doctor` — checks binary, API key, and live callability for each backend. |
18311836
| Webhook events not arriving | Run `openclaw openclaw-linear webhooks setup` to auto-provision. Both webhooks must point to `/linear/webhook`. Check tunnel is running. |
18321837
| Tunnel down / webhooks silently failing | `systemctl status cloudflared` (or `systemctl --user status cloudflared`). Restart with `systemctl restart cloudflared`. Test: `curl -s -X POST https://your-domain.com/linear/webhook -H 'Content-Type: application/json' -d '{"type":"test"}'` — should return `"ok"`. |
18331838
| OAuth token expired | Auto-refreshes. If stuck, re-run `openclaw openclaw-linear auth` and restart. |

index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { createPlannerTools } from "./src/tools/planner-tools.js";
1818
import { registerDispatchCommands } from "./src/infra/commands.js";
1919
import { createDispatchHistoryTool } from "./src/tools/dispatch-history-tool.js";
2020
import { readDispatchState as readStateForHook, listActiveDispatches as listActiveForHook } from "./src/pipeline/dispatch-state.js";
21+
import { startTokenRefreshTimer, stopTokenRefreshTimer } from "./src/infra/token-refresh-timer.js";
2122

2223
export default function register(api: OpenClawPluginApi) {
2324
const pluginConfig = (api as any).pluginConfig as Record<string, unknown> | undefined;
@@ -337,4 +338,10 @@ export default function register(api: OpenClawPluginApi) {
337338
api.logger.info(
338339
`Linear agent extension registered (agent: ${agentId}, token: ${tokenInfo.source !== "none" ? `${tokenInfo.source}` : "missing"}, ${cliSummary}, orchestration: ${orchestration})`,
339340
);
341+
342+
// Start proactive token refresh timer (runs immediately, then every 6h)
343+
startTokenRefreshTimer(api, pluginConfig);
344+
345+
// Clean up timer on process exit
346+
process.on("beforeExit", () => stopTokenRefreshTimer());
340347
}

openclaw.plugin.json

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,46 @@
1717
"codexBaseRepo": { "type": "string", "description": "Path to git repo for Codex worktrees", "default": "/home/claw/ai-workspace" },
1818
"enableOrchestration": { "type": "boolean", "description": "Allow agents to spawn sub-agents via spawn_agent/ask_agent tools", "default": true },
1919
"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" } },
20+
"repos": {
21+
"type": "object",
22+
"description": "Multi-repo map — each key is a repo name, value is a path string or object with path + GitHub identity",
23+
"additionalProperties": {
24+
"oneOf": [
25+
{ "type": "string", "description": "Filesystem path (backward compat)" },
26+
{
27+
"type": "object",
28+
"required": ["path"],
29+
"properties": {
30+
"path": { "type": "string", "description": "Absolute filesystem path to git repo" },
31+
"github": { "type": "string", "description": "GitHub owner/repo (e.g. 'calltelemetry/cisco-cdr')" },
32+
"hostname": { "type": "string", "description": "Git host (default: 'github.com')", "default": "github.com" }
33+
}
34+
}
35+
]
36+
}
37+
},
38+
"teamMappings": {
39+
"type": "object",
40+
"description": "Map Linear team keys to repos, agents, and team-specific context",
41+
"additionalProperties": {
42+
"type": "object",
43+
"properties": {
44+
"repos": {
45+
"type": "array",
46+
"items": { "type": "string" },
47+
"description": "Repo names (keys in 'repos' config) for this team"
48+
},
49+
"defaultAgent": {
50+
"type": "string",
51+
"description": "OpenClaw agent ID to handle issues from this team"
52+
},
53+
"context": {
54+
"type": "string",
55+
"description": "Extra context injected into worker/audit prompts for this team"
56+
}
57+
}
58+
}
59+
},
2160
"dispatchStatePath": { "type": "string", "description": "Path to dispatch state JSON file (default: ~/.openclaw/linear-dispatch-state.json)" },
2261
"planningStatePath": { "type": "string", "description": "Path to planning state JSON file (default: ~/.openclaw/linear-planning-state.json)" },
2362
"notifications": {
@@ -61,7 +100,10 @@
61100
"toolTimeoutSec": { "type": "number", "description": "Max runtime for a single code_run CLI invocation in seconds (default: 600)", "default": 600 },
62101
"claudeApiKey": { "type": "string", "description": "Anthropic API key for Claude CLI backend (passed as ANTHROPIC_API_KEY env var)", "sensitive": true },
63102
"enableGuidance": { "type": "boolean", "description": "Inject Linear workspace/team guidance into agent prompts (default: true)", "default": true },
64-
"teamGuidanceOverrides": { "type": "object", "description": "Per-team guidance toggle. Key = Linear team ID, value = boolean. Unset teams inherit enableGuidance.", "additionalProperties": { "type": "boolean" } }
103+
"teamGuidanceOverrides": { "type": "object", "description": "Per-team guidance toggle. Key = Linear team ID, value = boolean. Unset teams inherit enableGuidance.", "additionalProperties": { "type": "boolean" } },
104+
"enableTmux": { "type": "boolean", "default": true, "description": "Enable tmux wrapping for code_run CLI backends (enables steering)" },
105+
"enableRetro": { "type": "boolean", "default": true, "description": "Enable post-task retrospective analysis" },
106+
"retroDir": { "type": "string", "description": "Override path for coding retrospective files (default: {stateDir}/shared/coding)" }
65107
}
66108
}
67109
}

0 commit comments

Comments
 (0)