@calltelemetry/openclaw-linear 0.8.0 → 0.8.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 CHANGED
@@ -11,8 +11,9 @@ Connect Linear to AI agents. Issues get triaged, implemented, and audited — au
11
11
 
12
12
  - **New issue?** Agent estimates story points, adds labels, sets priority.
13
13
  - **Assign to agent?** A worker implements it, an independent auditor verifies it, done.
14
- - **Comment `@qa review this`?** The QA agent responds with its expertise.
15
- - **Say "plan this project"?** A planner interviews you and builds your full issue hierarchy.
14
+ - **Comment anything?** The bot understands natural language no magic commands needed.
15
+ - **Say "let's plan the features"?** A planner interviews you, writes user stories, and builds your full issue hierarchy.
16
+ - **Plan looks good?** A different AI model automatically audits the plan before dispatch.
16
17
  - **Agent goes silent?** A watchdog kills it and retries automatically.
17
18
  - **Want updates?** Get notified on Discord, Slack, Telegram, or Signal.
18
19
 
@@ -284,53 +285,99 @@ If something went wrong, start with `log.jsonl` — it shows every phase, how lo
284
285
 
285
286
  ---
286
287
 
288
+ ## Comment Routing — Talk Naturally
289
+
290
+ You don't need to memorize magic commands. The bot uses an LLM-based intent classifier to understand what you want from any comment.
291
+
292
+ ```
293
+ User comment → Intent Classifier (small model, ~2s) → Route to handler
294
+ ↓ (on failure)
295
+ Regex fallback → Route to handler
296
+ ```
297
+
298
+ **What the bot understands:**
299
+
300
+ | What you say | What happens |
301
+ |---|---|
302
+ | "let's plan the features for this" | Starts planning interview |
303
+ | "looks good, ship it" (during planning) | Runs plan audit + cross-model review |
304
+ | "nevermind, cancel this" (during planning) | Exits planning mode |
305
+ | "hey kaylee can you look at this?" | Routes to Kaylee (no `@` needed) |
306
+ | "what can I do here?" | Default agent responds (not silently dropped) |
307
+ | "fix the search bug" | Default agent dispatches work |
308
+
309
+ `@mentions` still work as a fast path — if you write `@kaylee`, the classifier is skipped entirely for speed.
310
+
311
+ > **Tip:** Configure `classifierAgentId` to point to a small/fast model agent (like Haiku) for low-latency, low-cost intent classification. The classifier only needs ~300 tokens per call.
312
+
313
+ ---
314
+
287
315
  ## Planning a Project
288
316
 
289
317
  For larger work, the planner helps you break a project into issues with dependencies, then dispatches them automatically.
290
318
 
291
319
  ### Start planning
292
320
 
293
- Comment on any issue that belongs to a Linear project:
321
+ Comment on any issue that belongs to a Linear project — use natural language:
294
322
 
295
- > `@ctclaw plan this project`
323
+ > "let's plan out the features for this project"
296
324
 
297
- The planner enters **interview mode** and asks you questions:
325
+ The planner enters **interview mode** and asks you questions one at a time:
298
326
 
299
- > Entering planning mode for **Search Feature**. What are the main feature areas you'd like to build?
327
+ > I'm entering planning mode for **Search Feature**. I'll interview you about the features you want to build, then structure everything into Linear issues.
328
+ >
329
+ > Let's start — what is this project about, and what are the main feature areas?
300
330
 
301
331
  ### Build the plan
302
332
 
303
- Reply with your ideas. The planner creates issues, sets dependencies, and asks follow-up questions:
333
+ Reply with your ideas. The planner creates issues with **user stories** and **acceptance criteria**, sets dependencies, and asks follow-up questions:
304
334
 
305
335
  > I've created 3 issues:
306
336
  > - **PROJ-2:** Build search API endpoint (3 pts, blocks PROJ-3)
307
337
  > - **PROJ-3:** Search results page (2 pts, blocked by PROJ-2)
308
338
  > - **PROJ-4:** Autocomplete suggestions (1 pt, independent)
309
339
  >
310
- > Should the autocomplete call a separate endpoint or share the search API?
340
+ > For PROJ-2, here's what I wrote for acceptance criteria:
341
+ > - *Given* a user sends a search query, *When* results exist, *Then* they are returned with pagination
342
+ >
343
+ > Does that cover it? Should the autocomplete call a separate endpoint or share the search API?
344
+
345
+ The planner proactively asks for:
346
+ - **User stories** — "As a [role], I want [feature] so that [benefit]"
347
+ - **Acceptance criteria** — Given/When/Then format
348
+ - **UAT test scenarios** — How to manually verify the feature
311
349
 
312
350
  Keep replying until the plan looks right. The planner updates issues in real time.
313
351
 
314
- ### Finalize
352
+ ### Finalize & Cross-Model Review
315
353
 
316
- When you're happy with the plan, comment:
354
+ When you're happy, say something like "looks good" or "finalize plan". The planner runs a validation check:
355
+ - Every issue has a description (50+ characters) with acceptance criteria
356
+ - Every non-epic issue has an estimate and priority
357
+ - No circular dependencies in the DAG
317
358
 
318
- > `finalize plan`
359
+ **If validation passes, a cross-model review runs automatically:**
319
360
 
320
- The planner runs a validation check:
321
- - Every issue has a description (50+ characters)
322
- - Every issue has an estimate
323
- - Every issue has a priority
324
- - No circular dependencies
361
+ > ## Plan Passed Checks
362
+ >
363
+ > **3 issues** with valid dependency graph.
364
+ >
365
+ > Let me have **Codex** audit this and make recommendations.
325
366
 
326
- **If validation passes:**
367
+ A different AI model (always the complement of your primary model) reviews the plan for gaps:
327
368
 
328
- > ## Plan Approved
329
- >
330
- > The plan for **Search Feature** passed all checks.
331
- > **3 issues** created with valid dependency graph.
369
+ | Your primary model | Auto-reviewer |
370
+ |---|---|
371
+ | Claude / Anthropic | Codex |
372
+ | Codex / OpenAI | Gemini |
373
+ | Gemini / Google | Codex |
374
+ | Other (Kimi, Mistral, etc.) | Gemini |
375
+
376
+ After the review, the planner summarizes recommendations and asks you to approve:
332
377
 
333
- The project enters **DAG dispatch mode** issues are assigned to the agent automatically, respecting dependency order. Up to 3 issues run in parallel. As each completes, newly unblocked issues start.
378
+ > Codex suggested adding error handling scenarios to PROJ-2 and noted PROJ-4 could be split into frontend/backend. I've updated PROJ-2's acceptance criteria. The PROJ-4 split is optional your call.
379
+ >
380
+ > If you're happy with this plan, say **approve plan** to start dispatching.
334
381
 
335
382
  **If validation fails:**
336
383
 
@@ -340,13 +387,16 @@ The project enters **DAG dispatch mode** — issues are assigned to the agent au
340
387
  > - PROJ-2: description too short (< 50 chars)
341
388
  > - PROJ-3: missing estimate
342
389
  >
390
+ > **Warnings:**
391
+ > - PROJ-4: no acceptance criteria found in description
392
+ >
343
393
  > Please address these issues, then say "finalize plan" again.
344
394
 
345
- Fix the issues and try again. You can also say `abandon planning` to exit without dispatching.
395
+ Fix the issues and try again. You can also say "cancel" or "stop planning" to exit without dispatching.
346
396
 
347
397
  ### DAG dispatch progress
348
398
 
349
- As issues complete, you'll get progress notifications:
399
+ After approval, issues are assigned to the agent automatically in dependency order. Up to 3 issues run in parallel.
350
400
 
351
401
  > `📊 Search Feature: 2/3 complete`
352
402
 
@@ -364,11 +414,14 @@ If an issue gets stuck (all retries failed), dependent issues are blocked and yo
364
414
  |---|---|
365
415
  | Create a new issue | Agent triages — adds estimate, labels, priority |
366
416
  | Assign an issue to the agent | Worker → Audit → Done (or retry, or escalate) |
367
- | Comment `@qa check the tests` | QA agent responds |
368
- | Comment `@ctclaw plan this project` | Planning interview starts |
369
- | Reply during planning | Issues created/updated, follow-up questions |
370
- | Comment `finalize plan` | Validates, then auto-dispatches |
371
- | Comment `abandon planning` | Exits planning mode |
417
+ | Comment anything on an issue | Intent classifier routes to the right handler |
418
+ | Mention an agent by name (with or without `@`) | That agent responds |
419
+ | Ask a question or request work | Default agent handles it |
420
+ | Say "plan this project" (on a project issue) | Planning interview starts |
421
+ | Reply during planning | Issues created/updated with user stories & AC |
422
+ | Say "looks good" / "finalize plan" | Validates → cross-model review → approval |
423
+ | Say "approve plan" (after review) | Dispatches all issues in dependency order |
424
+ | Say "cancel" / "abandon planning" | Exits planning mode |
372
425
  | `/dispatch list` | Shows all active dispatches |
373
426
  | `/dispatch retry CT-123` | Re-runs a stuck dispatch |
374
427
  | `/dispatch status CT-123` | Detailed dispatch info |
@@ -401,6 +454,8 @@ Add settings under the plugin entry in `openclaw.json`:
401
454
  | Key | Type | Default | What it does |
402
455
  |---|---|---|---|
403
456
  | `defaultAgentId` | string | `"default"` | Which agent runs the pipeline |
457
+ | `classifierAgentId` | string | — | Agent for intent classification (use a small/fast model like Haiku) |
458
+ | `plannerReviewModel` | string | auto | Cross-model plan reviewer: `"claude"`, `"codex"`, or `"gemini"`. Auto-detects the complement of your primary model. |
404
459
  | `enableAudit` | boolean | `true` | Run auditor after implementation |
405
460
  | `enableOrchestration` | boolean | `true` | Allow `spawn_agent` / `ask_agent` tools |
406
461
  | `maxReworkAttempts` | number | `2` | Max audit failures before escalation |
@@ -408,11 +463,13 @@ Add settings under the plugin entry in `openclaw.json`:
408
463
  | `worktreeBaseDir` | string | `"~/.openclaw/worktrees"` | Where worktrees are created |
409
464
  | `repos` | object | — | Multi-repo map (see [Multi-Repo](#multi-repo)) |
410
465
  | `dispatchStatePath` | string | `"~/.openclaw/linear-dispatch-state.json"` | Dispatch state file |
466
+ | `planningStatePath` | string | `"~/.openclaw/linear-planning-state.json"` | Planning session state file |
411
467
  | `promptsPath` | string | — | Custom prompts file path |
412
468
  | `notifications` | object | — | Notification targets (see [Notifications](#notifications)) |
413
469
  | `inactivitySec` | number | `120` | Kill agent if silent this long |
414
470
  | `maxTotalSec` | number | `7200` | Max total agent session time |
415
471
  | `toolTimeoutSec` | number | `600` | Max single `code_run` time |
472
+ | `claudeApiKey` | string | — | Anthropic API key for Claude CLI (passed as `ANTHROPIC_API_KEY` env var). Required if using Claude backend. |
416
473
 
417
474
  ### Environment Variables
418
475
 
@@ -456,9 +513,17 @@ One agent must have `"isDefault": true` — that's the one that handles triage a
456
513
 
457
514
  Create `coding-tools.json` in the plugin root to configure which CLI backend agents use:
458
515
 
516
+ > **Warning — Claude Code (Anthropic) and headless/automated usage**
517
+ >
518
+ > Calling Claude Code via CLI in a headless or automated context (which is how this plugin
519
+ > uses it) may violate [Anthropic's Terms of Service](https://www.anthropic.com/terms).
520
+ > The default backend is **Codex CLI** (OpenAI). **Gemini CLI** (Google) is used as the
521
+ > cross-model reviewer. If you choose to use Claude despite this, you do so at your own risk.
522
+ > See [Claude API Key](#claude-api-key) below for opt-in configuration.
523
+
459
524
  ```json
460
525
  {
461
- "codingTool": "claude",
526
+ "codingTool": "codex",
462
527
  "agentCodingTools": {},
463
528
  "backends": {
464
529
  "claude": { "aliases": ["claude", "claude code", "anthropic"] },
@@ -468,7 +533,33 @@ Create `coding-tools.json` in the plugin root to configure which CLI backend age
468
533
  }
469
534
  ```
470
535
 
471
- The agent calls `code_run` without knowing which backend is active. Resolution order: explicit `backend` parameter > per-agent override > global default > `"claude"`.
536
+ The agent calls `code_run` without knowing which backend is active. Resolution order: explicit `backend` parameter > per-agent override > global default > `"codex"`.
537
+
538
+ #### Claude API Key
539
+
540
+ If you opt in to using Claude as a backend (despite the TOS concerns noted above), you can
541
+ provide an Anthropic API key so the Claude CLI authenticates via API key instead of its
542
+ built-in interactive auth.
543
+
544
+ Set `claudeApiKey` in the plugin config:
545
+
546
+ ```json
547
+ {
548
+ "plugins": {
549
+ "entries": {
550
+ "openclaw-linear": {
551
+ "config": {
552
+ "claudeApiKey": "sk-ant-..."
553
+ }
554
+ }
555
+ }
556
+ }
557
+ }
558
+ ```
559
+
560
+ The key is passed to the Claude CLI subprocess as the `ANTHROPIC_API_KEY` environment variable.
561
+ You can also set `ANTHROPIC_API_KEY` as a process-level environment variable (e.g., in your
562
+ systemd unit file) as a fallback. The plugin config value takes precedence if both are set.
472
563
 
473
564
  ---
474
565
 
@@ -569,6 +660,10 @@ rework:
569
660
  | `{{tier}}` | Complexity tier (junior/medior/senior) |
570
661
  | `{{attempt}}` | Current attempt number |
571
662
  | `{{gaps}}` | Audit gaps from previous attempt |
663
+ | `{{projectName}}` | Project name (planner prompts) |
664
+ | `{{planSnapshot}}` | Current plan structure (planner prompts) |
665
+ | `{{reviewModel}}` | Name of cross-model reviewer (planner review) |
666
+ | `{{crossModelFeedback}}` | Review recommendations (planner review) |
572
667
 
573
668
  ### CLI
574
669
 
@@ -762,8 +857,8 @@ Example output:
762
857
  ✔ Default agent: coder
763
858
 
764
859
  Coding Tools
765
- ✔ coding-tools.json loaded (default: claude)
766
- claude: found at /usr/local/bin/claude
860
+ ✔ coding-tools.json loaded (default: codex)
861
+ codex: found at /usr/local/bin/codex
767
862
 
768
863
  Files & Directories
769
864
  ✔ Dispatch state: 1 active, 5 completed
@@ -785,7 +880,7 @@ Every warning and error includes a `→` line telling you what to do. Run `docto
785
880
 
786
881
  ### Unit tests
787
882
 
788
- 422 tests covering the full pipeline — triage, dispatch, audit, planning, notifications, and infrastructure:
883
+ 454 tests covering the full pipeline — triage, dispatch, audit, planning, intent classification, cross-model review, notifications, and infrastructure:
789
884
 
790
885
  ```bash
791
886
  cd ~/claw-extensions/linear
@@ -806,6 +901,7 @@ npx tsx scripts/uat-linear.ts
806
901
  npx tsx scripts/uat-linear.ts --test dispatch
807
902
  npx tsx scripts/uat-linear.ts --test planning
808
903
  npx tsx scripts/uat-linear.ts --test mention
904
+ npx tsx scripts/uat-linear.ts --test intent
809
905
  ```
810
906
 
811
907
  **What each scenario does:**
@@ -868,6 +964,25 @@ npx tsx scripts/uat-linear.ts --test mention
868
964
  [mention] Total: 18s
869
965
  ```
870
966
 
967
+ #### `--test intent` (Natural language routing)
968
+
969
+ 1. Creates a test issue and posts a question (no `@mention`)
970
+ 2. Verifies the bot responds (not silently dropped)
971
+ 3. Posts a comment with an agent name but no `@` prefix
972
+ 4. Verifies that agent responds
973
+ 5. Tests plan review flow with cross-model audit
974
+
975
+ **Expected output:**
976
+
977
+ ```
978
+ [intent] Created issue ENG-202
979
+ [intent] Posted "what can I do with this?" — waiting for response...
980
+ [intent] ✔ Bot responded to question (12s)
981
+ [intent] Posted "hey kaylee analyze this" — waiting for response...
982
+ [intent] ✔ Kaylee responded without @mention (15s)
983
+ [intent] Total: 27s
984
+ ```
985
+
871
986
  ### Verify notifications
872
987
 
873
988
  ```bash
@@ -947,6 +1062,9 @@ journalctl --user -u openclaw-gateway -f # Watch live logs
947
1062
  | Audit always fails | Run `openclaw openclaw-linear prompts validate` to check prompt syntax. |
948
1063
  | Multi-repo not detected | Markers must be `<!-- repos: name1, name2 -->`. Names must match `repos` config keys. |
949
1064
  | `/dispatch` not responding | Restart gateway. Check plugin loaded with `openclaw doctor`. |
1065
+ | Comments ignored (no response) | Check logs for intent classification results. If classifier fails, regex fallback may not match. |
1066
+ | Intent classifier slow | Set `classifierAgentId` to a small model agent (Haiku). Default uses your primary model. |
1067
+ | Cross-model review fails | The reviewer model CLI must be installed. Check logs for "cross-model review unavailable". |
950
1068
  | Rich notifications are plain text | Set `"richFormat": true` in notifications config. |
951
1069
  | Gateway rejects config keys | Strict validator. Run `openclaw doctor --fix`. |
952
1070
 
@@ -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.8.0",
5
+ "version": "0.8.1",
6
6
  "configSchema": {
7
7
  "type": "object",
8
8
  "additionalProperties": false,
@@ -58,7 +58,8 @@
58
58
  "maxReworkAttempts": { "type": "number", "description": "Max audit failures before escalation", "default": 2 },
59
59
  "inactivitySec": { "type": "number", "description": "Kill sessions with no I/O for this many seconds (default: 120)", "default": 120 },
60
60
  "maxTotalSec": { "type": "number", "description": "Max total runtime for agent sessions in seconds (default: 7200)", "default": 7200 },
61
- "toolTimeoutSec": { "type": "number", "description": "Max runtime for a single code_run CLI invocation in seconds (default: 600)", "default": 600 }
61
+ "toolTimeoutSec": { "type": "number", "description": "Max runtime for a single code_run CLI invocation in seconds (default: 600)", "default": 600 },
62
+ "claudeApiKey": { "type": "string", "description": "Anthropic API key for Claude CLI backend (passed as ANTHROPIC_API_KEY env var)", "sensitive": true }
62
63
  }
63
64
  }
64
65
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calltelemetry/openclaw-linear",
3
- "version": "0.8.0",
3
+ "version": "0.8.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",
package/prompts.yaml CHANGED
@@ -96,13 +96,20 @@ planner:
96
96
  - Issues under epics are concrete deliverables with acceptance criteria.
97
97
  - Sub-issues are atomic work units that together complete a parent issue.
98
98
  - Use "blocks" relationships to express ordering: if A must finish before B starts, A blocks B.
99
- - Every issue description must include clear acceptance criteria.
100
99
  - Every non-epic issue needs a story point estimate and priority.
100
+ - Every issue description must include:
101
+ - A user story: "As a [role], I want [feature] so that [benefit]"
102
+ - Acceptance criteria in Given/When/Then format
103
+ - At least one UAT test scenario describing how to verify the feature manually
104
+ - If the user skips acceptance criteria, write reasonable defaults and confirm with them.
101
105
 
102
106
  INTERVIEW APPROACH:
103
107
  - Ask ONE focused question at a time. Never dump a questionnaire.
104
108
  - After each user response, create or update issues to capture what you learned.
105
109
  - Briefly summarize what you added before asking your next question.
110
+ - After capturing a feature, ask for acceptance criteria: "How would you know this is working? What should a user be able to do?"
111
+ - Proactively suggest UAT scenarios: "Here's how I'd test this — does that cover it?"
112
+ - Don't front-load all questions — weave user stories and acceptance criteria into the natural conversation.
106
113
  - When the plan feels complete, invite the user to say "finalize plan".
107
114
  - If the user is vague ("make it better", "you decide"), propose concrete options and ask them to pick.
108
115
  - If you've gathered enough info after several turns with no new details, suggest: "This looks ready — say **finalize plan** when you're happy with it."
@@ -138,3 +145,22 @@ planner:
138
145
  - If you want to stop, say **"abandon planning"**
139
146
 
140
147
  Let's start — what is this project about, and what are the main feature areas?
148
+
149
+ review: |
150
+ ## Plan Review for {{projectName}}
151
+
152
+ The plan passed all deterministic checks ({{issueCount}} issues, valid DAG, all have estimates and priorities).
153
+
154
+ ### Current Plan
155
+ {{planSnapshot}}
156
+
157
+ ### {{reviewModel}}'s Recommendations
158
+ {{crossModelFeedback}}
159
+
160
+ Your job:
161
+ 1. Evaluate the recommendations above — which ones are worth applying?
162
+ 2. If any are good, use your tools to update the relevant issues now
163
+ 3. Summarize what you changed (if anything) and what you didn't change (and why)
164
+ 4. End with: "If you're happy with this plan, say **approve plan** to start dispatching."
165
+
166
+ Post your review as a comment.
@@ -204,6 +204,55 @@ describe("runAgent subprocess", () => {
204
204
  });
205
205
  });
206
206
 
207
+ describe("runAgent date/time injection", () => {
208
+ it("injects current date/time into the message sent to subprocess", async () => {
209
+ const api = createApi();
210
+ const runCmd = vi.fn().mockResolvedValue({
211
+ code: 0,
212
+ stdout: JSON.stringify({ result: { payloads: [{ text: "done" }] } }),
213
+ stderr: "",
214
+ });
215
+ (api.runtime.system as any).runCommandWithTimeout = runCmd;
216
+
217
+ await runAgent({
218
+ api,
219
+ agentId: "test",
220
+ sessionId: "s1",
221
+ message: "do something",
222
+ });
223
+
224
+ // The --message arg should contain the date context prefix
225
+ const args: string[] = runCmd.mock.calls[0][0];
226
+ const msgIdx = args.indexOf("--message");
227
+ const passedMessage = args[msgIdx + 1];
228
+ expect(passedMessage).toMatch(/^\[Current date\/time:.*\d{4}.*\]/);
229
+ expect(passedMessage).toContain("do something");
230
+ });
231
+
232
+ it("includes ISO timestamp in the injected context", async () => {
233
+ const api = createApi();
234
+ const runCmd = vi.fn().mockResolvedValue({
235
+ code: 0,
236
+ stdout: "ok",
237
+ stderr: "",
238
+ });
239
+ (api.runtime.system as any).runCommandWithTimeout = runCmd;
240
+
241
+ await runAgent({
242
+ api,
243
+ agentId: "test",
244
+ sessionId: "s1",
245
+ message: "test task",
246
+ });
247
+
248
+ const args: string[] = runCmd.mock.calls[0][0];
249
+ const msgIdx = args.indexOf("--message");
250
+ const passedMessage = args[msgIdx + 1];
251
+ // Should contain ISO format like 2026-02-19T05:45:00.000Z
252
+ expect(passedMessage).toMatch(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/);
253
+ });
254
+ });
255
+
207
256
  describe("runAgent retry wrapper", () => {
208
257
  it("returns success on first attempt when no watchdog kill", async () => {
209
258
  const api = createApi();
@@ -95,6 +95,27 @@ export async function runAgent(params: {
95
95
  return { success: false, output: "Watchdog retry exhausted" };
96
96
  }
97
97
 
98
+ // ---------------------------------------------------------------------------
99
+ // Date/time injection — every LLM request gets the current timestamp so models
100
+ // don't hallucinate the year (Kimi K2.5 thinks it's 2025).
101
+ // ---------------------------------------------------------------------------
102
+
103
+ function buildDateContext(): string {
104
+ const now = new Date();
105
+ const iso = now.toISOString();
106
+ // Human-readable: "Tuesday, February 18, 2026, 11:42 PM CST"
107
+ const human = now.toLocaleString("en-US", {
108
+ weekday: "long",
109
+ year: "numeric",
110
+ month: "long",
111
+ day: "numeric",
112
+ hour: "numeric",
113
+ minute: "2-digit",
114
+ timeZoneName: "short",
115
+ });
116
+ return `[Current date/time: ${human} (${iso})]`;
117
+ }
118
+
98
119
  /**
99
120
  * Single attempt to run an agent (no retry logic).
100
121
  */
@@ -106,7 +127,11 @@ async function runAgentOnce(params: {
106
127
  timeoutMs?: number;
107
128
  streaming?: AgentStreamCallbacks;
108
129
  }): Promise<AgentRunResult> {
109
- const { api, agentId, sessionId, message, streaming } = params;
130
+ const { api, agentId, sessionId, streaming } = params;
131
+
132
+ // Inject current timestamp into every LLM request
133
+ const message = `${buildDateContext()}\n\n${params.message}`;
134
+
110
135
  const pluginConfig = (api as any).pluginConfig as Record<string, unknown> | undefined;
111
136
  const wdConfig = resolveWatchdogConfig(agentId, pluginConfig);
112
137
  const timeoutMs = params.timeoutMs ?? wdConfig.maxTotalMs;
@@ -321,13 +321,13 @@ export function checkCodingTools(): CheckResult[] {
321
321
  const config = loadCodingConfig();
322
322
  const hasConfig = !!config.codingTool || !!config.backends;
323
323
  if (hasConfig) {
324
- checks.push(pass(`coding-tools.json loaded (default: ${config.codingTool ?? "claude"})`));
324
+ checks.push(pass(`coding-tools.json loaded (default: ${config.codingTool ?? "codex"})`));
325
325
  } else {
326
326
  checks.push(warn("coding-tools.json not found or empty (using defaults)", undefined, { fix: "Create coding-tools.json in the plugin root — see README for format" }));
327
327
  }
328
328
 
329
329
  // Validate default backend
330
- const defaultBackend = config.codingTool ?? "claude";
330
+ const defaultBackend = config.codingTool ?? "codex";
331
331
  if (VALID_BACKENDS.includes(defaultBackend)) {
332
332
  // already reported in the line above
333
333
  } else {