@qodeca/xezar 0.11.2 → 0.13.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 (140) hide show
  1. package/README.md +97 -43
  2. package/dist/agent-config/catalog.d.ts +10 -0
  3. package/dist/agent-config/catalog.js.map +1 -1
  4. package/dist/automations/coordinator.js +8 -0
  5. package/dist/automations/coordinator.js.map +1 -1
  6. package/dist/automations/types.d.ts +2 -0
  7. package/dist/contract/automations.d.ts +8 -0
  8. package/dist/contract/events.test.d.ts +1 -0
  9. package/dist/contract/index.js +87 -3
  10. package/dist/contract/runs.d.ts +25 -0
  11. package/dist/contract/runs.test.d.ts +1 -0
  12. package/dist/contract/skills.d.ts +1 -0
  13. package/dist/contract/workflows.d.ts +6 -0
  14. package/dist/contract/workspace.d.ts +37 -4
  15. package/dist/core/agent-env.js +8 -1
  16. package/dist/core/agent-env.js.map +1 -1
  17. package/dist/core/agent-runner.d.ts +13 -0
  18. package/dist/core/agent-runner.js +22 -0
  19. package/dist/core/agent-runner.js.map +1 -1
  20. package/dist/core/backend-detect.js +11 -1
  21. package/dist/core/backend-detect.js.map +1 -1
  22. package/dist/core/claude-cli-runner.js +8 -2
  23. package/dist/core/claude-cli-runner.js.map +1 -1
  24. package/dist/core/codex-app-server-runner.js +6 -2
  25. package/dist/core/codex-app-server-runner.js.map +1 -1
  26. package/dist/core/opencode-server-runner.d.ts +12 -0
  27. package/dist/core/opencode-server-runner.js +326 -17
  28. package/dist/core/opencode-server-runner.js.map +1 -1
  29. package/dist/core/pi-model-catalog.d.ts +52 -0
  30. package/dist/core/pi-model-catalog.js +135 -0
  31. package/dist/core/pi-model-catalog.js.map +1 -0
  32. package/dist/core/pi-runner.d.ts +3 -0
  33. package/dist/core/pi-runner.js +139 -12
  34. package/dist/core/pi-runner.js.map +1 -1
  35. package/dist/core/pi-ui-mapper.js +39 -3
  36. package/dist/core/pi-ui-mapper.js.map +1 -1
  37. package/dist/core/runner-model-catalog.js +11 -2
  38. package/dist/core/runner-model-catalog.js.map +1 -1
  39. package/dist/index.js +2 -0
  40. package/dist/index.js.map +1 -1
  41. package/dist/paths.d.ts +7 -0
  42. package/dist/paths.js +8 -0
  43. package/dist/paths.js.map +1 -1
  44. package/dist/runs/event-corrections.d.ts +12 -0
  45. package/dist/runs/event-corrections.js +141 -0
  46. package/dist/runs/event-corrections.js.map +1 -0
  47. package/dist/runs/event-history.d.ts +5 -1
  48. package/dist/runs/event-history.js +66 -5
  49. package/dist/runs/event-history.js.map +1 -1
  50. package/dist/runs/project-writer.d.ts +11 -0
  51. package/dist/runs/project-writer.js +115 -0
  52. package/dist/runs/project-writer.js.map +1 -0
  53. package/dist/runs/retention.d.ts +1 -1
  54. package/dist/runs/retention.js +1 -1
  55. package/dist/runs/store.d.ts +2 -0
  56. package/dist/runs/store.js +13 -2
  57. package/dist/runs/store.js.map +1 -1
  58. package/dist/runs/task-markers.d.ts +4 -0
  59. package/dist/runs/task-markers.js +63 -5
  60. package/dist/runs/task-markers.js.map +1 -1
  61. package/dist/server/capabilities.d.ts +7 -5
  62. package/dist/server/capabilities.js +11 -7
  63. package/dist/server/capabilities.js.map +1 -1
  64. package/dist/server/project-context.js +2 -0
  65. package/dist/server/project-context.js.map +1 -1
  66. package/dist/server/server.d.ts +199 -47
  67. package/dist/server/server.js +195 -11
  68. package/dist/server/server.js.map +1 -1
  69. package/dist/workflows/run.d.ts +67 -2
  70. package/dist/workflows/run.js +233 -62
  71. package/dist/workflows/run.js.map +1 -1
  72. package/dist/workflows/types.d.ts +41 -0
  73. package/dist/workflows/types.js +72 -0
  74. package/dist/workflows/types.js.map +1 -1
  75. package/dist/workspace/config.d.ts +42 -0
  76. package/dist/workspace/config.js +132 -3
  77. package/dist/workspace/config.js.map +1 -1
  78. package/dist/workspace/semaphore.d.ts +63 -3
  79. package/dist/workspace/semaphore.js +76 -3
  80. package/dist/workspace/semaphore.js.map +1 -1
  81. package/package.json +3 -3
  82. package/web/dist/assets/{alert-dialog-CGskMvgc.js → alert-dialog-BVsVcbFy.js} +1 -1
  83. package/web/dist/assets/arrow-down-CYgAlZtW.js +1 -0
  84. package/web/dist/assets/arrow-left-BOqE0a3k.js +1 -0
  85. package/web/dist/assets/{centered-state-B_V_Ai2h.js → centered-state-Djgly6Ni.js} +1 -1
  86. package/web/dist/assets/chevron-right-Cc9BWnbN.js +1 -0
  87. package/web/dist/assets/{collapsible-B_8uYwHb.js → collapsible-DZ4D-DHG.js} +1 -1
  88. package/web/dist/assets/{commit-list-C4Dv6vUL.js → commit-list-B-z1JL9G.js} +1 -1
  89. package/web/dist/assets/{compare-variants-et0mplGi.js → compare-variants-D62m4j3B.js} +1 -1
  90. package/web/dist/assets/{diff-CbozNUJq.js → diff-BKew9rQX.js} +2 -2
  91. package/web/dist/assets/{diff-stat-btAmKFJr.js → diff-stat-D0mc5V6Z.js} +1 -1
  92. package/web/dist/assets/{diff-view-BpFTcG3R.js → diff-view-xpIcuLIC.js} +1 -1
  93. package/web/dist/assets/{dropdown-menu-Z80KMInL.js → dropdown-menu-CEQziH7X.js} +1 -1
  94. package/web/dist/assets/editable-title-BCX3T2BY.js +1 -0
  95. package/web/dist/assets/{ellipsis-vertical-Bmi2u2TG.js → ellipsis-vertical-ByVdDc4z.js} +1 -1
  96. package/web/dist/assets/{file-DKoYWRsv.js → file-xBSB5hXO.js} +1 -1
  97. package/web/dist/assets/{folder-u01HScRT.js → folder-CldgbZ5A.js} +1 -1
  98. package/web/dist/assets/{git-toolbar-Q2kk2F7v.js → git-toolbar-DJANqg7Y.js} +1 -1
  99. package/web/dist/assets/github-D6vK0jFn.js +1 -0
  100. package/web/dist/assets/{image-preview-BR3iIIhf.js → image-preview-Cv5mZr0n.js} +1 -1
  101. package/web/dist/assets/index-CkmR6h7s.css +2 -0
  102. package/web/dist/assets/index-DVDqF4bM.js +9 -0
  103. package/web/dist/assets/{markdown-5FuCZDA4.js → markdown-CgEEE2ND.js} +1 -1
  104. package/web/dist/assets/{new-task-form-BydHBbef.js → new-task-form-1r2bgsdD.js} +1 -1
  105. package/web/dist/assets/{pill-vNzaaYxj.js → pill-q-x22_ej.js} +1 -1
  106. package/web/dist/assets/{project-router-BbCzrHKs.js → project-router-VDN4jQM8.js} +1 -1
  107. package/web/dist/assets/{prompt-templates-B7Fs2b1S.js → prompt-templates-BmZtCe-L.js} +1 -1
  108. package/web/dist/assets/{refresh-cw-DGliez3E.js → refresh-cw-DcNCj2nu.js} +1 -1
  109. package/web/dist/assets/{repo-git-h1RFfly3.js → repo-git-btG0sdbO.js} +1 -1
  110. package/web/dist/assets/{run-diff-Bq9vkSNK.js → run-diff-vguEMJzh.js} +1 -1
  111. package/web/dist/assets/{run-header-Cd8mSKBG.js → run-header-DM7MiKj9.js} +1 -1
  112. package/web/dist/assets/{search-x-69n_672Y.js → search-x-QmhaAbg5.js} +1 -1
  113. package/web/dist/assets/{skill-empty-hint-CL0g7WBL.js → skill-empty-hint-BrzUwByZ.js} +1 -1
  114. package/web/dist/assets/{skills-BqAzyGS3.js → skills-DMfxQtrD.js} +1 -1
  115. package/web/dist/assets/{sparkles-B8agSxBZ.js → sparkles-CP8QDOgX.js} +1 -1
  116. package/web/dist/assets/{square-terminal-Cf4Og6ct.js → square-terminal-CGypshSD.js} +1 -1
  117. package/web/dist/assets/{tab-link-Cp2-CJS8.js → tab-link-D4lFzzI1.js} +1 -1
  118. package/web/dist/assets/{task-changes-DwXPFXqG.js → task-changes-BtZId14z.js} +1 -1
  119. package/web/dist/assets/{task-commits-Bessua-c.js → task-commits-BoeyJXrv.js} +1 -1
  120. package/web/dist/assets/{task-files-DxFIhRPP.js → task-files-DIy2oUnj.js} +1 -1
  121. package/web/dist/assets/task-thread-CbMPmrWq.js +9 -0
  122. package/web/dist/assets/{textarea--cpYshee.js → textarea-CyBCyKIk.js} +1 -1
  123. package/web/dist/assets/{thread-loading-ZhJref0J.js → thread-loading-Cuq2jchC.js} +1 -1
  124. package/web/dist/assets/{trash-2--ZtrzUx3.js → trash-2-B6Dp3ZNs.js} +1 -1
  125. package/web/dist/assets/{triangle-alert-D5tJwRD2.js → triangle-alert-xBya8FUp.js} +1 -1
  126. package/web/dist/assets/{upload-SnwVxKOA.js → upload-D6MXEB9p.js} +1 -1
  127. package/web/dist/assets/{use-desktop-Sr1QlxhT.js → use-desktop-CPBwzQ7M.js} +1 -1
  128. package/web/dist/assets/{use-submit-shortcut-JY8M_MPL.js → use-submit-shortcut-JTpNzU-u.js} +1 -1
  129. package/web/dist/assets/{utils-Bb8ohcr3.js → utils--z9hRtl3.js} +1 -1
  130. package/web/dist/assets/{workflows-9HC240Wx.js → workflows-DG115scU.js} +3 -3
  131. package/web/dist/assets/{zoomable-image-0G3IBXWC.js → zoomable-image-GTYwLtkS.js} +1 -1
  132. package/web/dist/index.html +23 -23
  133. package/web/dist/assets/arrow-down-G8adPhbu.js +0 -1
  134. package/web/dist/assets/arrow-left-BJsIW6A0.js +0 -1
  135. package/web/dist/assets/chevron-right-CFzn-von.js +0 -1
  136. package/web/dist/assets/editable-title-wS5NWwob.js +0 -1
  137. package/web/dist/assets/github-DjEYCxwt.js +0 -1
  138. package/web/dist/assets/index-BcI5hug3.css +0 -2
  139. package/web/dist/assets/index-Cz4GSAqV.js +0 -7
  140. package/web/dist/assets/task-thread-Dhkupf1-.js +0 -9
package/README.md CHANGED
@@ -97,7 +97,7 @@ and an orchestrator keeps a whole queue of them moving.
97
97
  **orchestrates** them: it runs up to your parallel limit and holds the rest in
98
98
  an ordered queue. Point it at a GitHub issue and it runs straight on that, so
99
99
  working the tracker down stops being a manual chore. Turn on the opt-in
100
- **Inbox** (`XEZ_FOLLOWUPS=1`) and an agent's leftover follow-ups become the
100
+ **Inbox** (Settings → Resources, or `XEZ_FOLLOWUPS=1`) and an agent's leftover follow-ups become the
101
101
  next tasks too — one click each.
102
102
  - 🤖 **"Autonomous" means you still have to sit there.** Flip the **Autonomous**
103
103
  flag and a run never parks to ask — it keeps going until the task is done. Pair
@@ -113,7 +113,7 @@ and an orchestrator keeps a whole queue of them moving.
113
113
  Take it over interactively in one click (`claude --resume <id>`), or continue it
114
114
  in-process from the cockpit.
115
115
  - 🔀 **Locked into one agent vendor.** Most tools wed you to a single CLI. xezar
116
- drives **Claude Code, Codex and OpenCode (experimental)** through one runner seam — set a
116
+ drives **Claude Code, Codex, OpenCode and pi (the last two experimental)** through one runner seam — set a
117
117
  default, pick a backend per task, or mix them inside one workflow (implement
118
118
  with one agent, review with another) — and through **OpenCode** you can point
119
119
  a run at **open-source or local models**, not just the big vendors. See
@@ -147,8 +147,9 @@ and an orchestrator keeps a whole queue of them moving.
147
147
 
148
148
  **Prerequisites:** Node 20+, at least one logged-in agent CLI — the
149
149
  [`claude` CLI](https://github.com/anthropics/claude-code) (Pro/Max subscription),
150
- the [`codex` CLI](https://github.com/openai/codex), or
151
- [OpenCode](https://opencode.ai) — and, optionally, `git` and the `gh` CLI.
150
+ the [`codex` CLI](https://github.com/openai/codex),
151
+ [OpenCode](https://opencode.ai), or [pi](https://github.com/badlogic/pi-mono)
152
+ and, optionally, `git` and the `gh` CLI.
152
153
 
153
154
  Install it once, then run it in any repo:
154
155
 
@@ -192,8 +193,8 @@ To upgrade later: `npm install -g @qodeca/xezar@latest`.
192
193
 
193
194
  You describe a task. xezar runs it as a **workflow** — an ordered list of agent
194
195
  steps and shell checks — shelling out to your locally installed agent CLI
195
- (Claude Code by default; Codex and OpenCode are drop-in alternatives, per task
196
- or per step). In a git repo each task gets its own worktree by default — switch
196
+ (Claude Code by default; Codex, OpenCode and pi are drop-in alternatives, per
197
+ task or per step). In a git repo each task gets its own worktree by default — switch
197
198
  the composer's **Worktree** toggle off to run in the repo working tree (under
198
199
  xezar's repository-root lease), and a non-git directory runs in place. A git
199
200
  task that asks for a worktree it cannot create stops as `failed`; it never falls
@@ -259,7 +260,7 @@ Three words, no jargon — **task**, **skill**, **chain**:
259
260
  AI draft a chain for your task that you review, trim and start. The built-in
260
261
  `quick-task` (one agent step) works with zero setup.
261
262
 
262
- Five moves that make the cockpit worth the browser tab:
263
+ Six moves that make the cockpit worth the browser tab:
263
264
 
264
265
  - 🗃️ **Queue + orchestration.** Start as many tasks as you like: xezar runs up to
265
266
  `maxParallel` at once across every project (default **2**; a non-git directory
@@ -269,18 +270,22 @@ Five moves that make the cockpit worth the browser tab:
269
270
  everything still `queued` is re-enqueued in order. It's the orchestration layer
270
271
  that turns "one agent at a time" into a backlog that drains itself.
271
272
  - 🧠 **Memory-aware runs.** Each run's whole process tree is sampled (~2 s) for CPU
272
- and RSS, and its **peak memory** is recorded and shown in the task table. Set an
273
- optional per-task **memory ceiling** (`memoryLimitMb`) and a run that crosses it
274
- is *paused* freeing its tree so the queue keeps advancing and resumes on
275
- demand. Event logs are append-only NDJSON and streamed rather than re-serialized,
273
+ and RSS, and its **peak memory** is recorded and shown in the task table. The
274
+ per-task **memory ceiling** (`memoryLimitMb`) is **on out of the box**: with no
275
+ setting at all xezar derives a host-sized ceiling from your machine's RAM, and a
276
+ run that crosses it is *paused* freeing its tree so the queue keeps advancing —
277
+ and resumes on demand. Adjust it in **Settings → Resources**; an explicit
278
+ `"memoryLimitMb": null` still means *no limit*, and a repo that sets its own value
279
+ overrides the workspace ceiling for its own runs. Event logs are append-only NDJSON and streamed rather than re-serialized,
276
280
  and live UI deltas are coalesced so they never hit disk.
277
281
  - 🪞 **Parallel variants (×2 / ×3).** Run the same task as competing agents in
278
282
  separate worktrees, then compare their diffs side by side and **pick** one —
279
283
  the losers are archived and their worktrees cleaned up.
280
284
  - 🧹 **Bounded worktree disk.** By default each git task runs in its own full checkout, so a busy
281
285
  cockpit would otherwise grow without limit. xezar keeps only the last
282
- `worktreeRetention` **finished** worktrees on disk (default **10**; `0` =
283
- unlimited) and reclaims the rest directory only, the `xez/<id8>` branch is
286
+ `worktreeRetention` **finished** worktrees on disk (default **10**, itself a
287
+ workspace setting`resources.worktreeRetentionDefault`, which every project
288
+ without its own value inherits; `0` = unlimited) and reclaims the rest — directory only, the `xez/<id8>` branch is
284
289
  always kept, so the work stays recoverable. Settings → Resources shows every
285
290
  worktree's disk use with per-row delete and a **Reclaim now** button.
286
291
  - 🛡️ **Review gate (optional, off by default).** Turn it on in Settings → Agents
@@ -300,18 +305,19 @@ Five moves that make the cockpit worth the browser tab:
300
305
 
301
306
  ## Cockpit tour
302
307
 
303
- Eight views, one browser window, all live over Server-Sent Events (seven until you opt into the Inbox):
308
+ Nine views, one browser window, all live over Server-Sent Events (seven by default the Inbox and Automations are each opt-in):
304
309
 
305
310
  | View | What's in it |
306
311
  |---|---|
307
- | **Tasks** | Every task with its status, live event stream (agent text · tool calls · tool results · pasted/generated screenshots and file attachments), tokens and cost. Continue, cancel, open in terminal (`claude --resume`), review the diff, or push a draft PR. |
312
+ | **Tasks** | Every task with its status, the tool and model it ran on, live event stream (agent text · tool calls · tool results · pasted/generated screenshots and file attachments), tokens and cost. Continue, cancel, open in terminal (`claude --resume`), review the diff, or push a draft PR. |
308
313
  | **All tasks** | Every *registered project's* tasks in one table, filtered and grouped by tag, project, status or workflow — see [Grouping connected repositories](#grouping-connected-repositories-tags-and-the-all-tasks-page). Appears once a second project is registered. |
309
- | **Inbox** | **Opt-in** (`XEZ_FOLLOWUPS=1`; hidden by default). Follow-ups an agent left behind (`todos.json`) — one click turns a suggestion into the next task, pre-wired to its suggested skill. Off, agents are never asked to leave follow-ups; each task's own **Notes** handoff journal is unaffected. |
314
+ | **Inbox** | **Opt-in**, hidden by default. Turn it on in **Settings → Resources** (the stored choice wins and needs no restart) or start with `XEZ_FOLLOWUPS=1`. Follow-ups an agent left behind (`todos.json`) — one click turns a suggestion into the next task, pre-wired to its suggested skill. Off, agents are never asked to leave follow-ups; each task's own **Notes** handoff journal is unaffected. |
310
315
  | **Git** | Branch, working-tree status, diff vs HEAD, recent commits (click one for its inline patch + GitHub link), and the configurable base branch that worktrees fork from and PRs target. |
311
316
  | **GitHub** | Open issues and PRs of the repo's origin, read through your logged-in `gh`. Hand an issue straight to the agent — pick a workflow and skills, one click runs it. |
317
+ | **Automations** | **Opt-in** (`XEZ_AUTOMATIONS=1`; hidden by default). Scheduled GitHub watches: each automation polls on its own interval and launches a task when its bounded filter matches. Test a filter before enabling it, and read the per-check log. |
312
318
  | **Skills** | Local skills plus the team skills repo, with a rendered body + prompt preview. Refresh pulls the latest from the remote. |
313
319
  | **Workflows** | Build a chain by drag-ordering skills, save it as portable YAML, import/export, or delete. Built-ins always come back. |
314
- | **Settings** | Appearance (dark/light theme, accent, density), agent backends, notifications, and the skills catalog. |
320
+ | **Settings** | Appearance (dark/light theme, accent, density), agent backends and their own config files, agent accounts, notifications, machine resources, projects, and skill-update checks. |
315
321
 
316
322
  The cockpit is a React app served pre-built from the package — running `xezar`
317
323
  needs no dev server on your machine — with a dark/light
@@ -325,7 +331,7 @@ a GitHub page.
325
331
  One `xezar serve` hosts **every repo you work in**, not just the one you started
326
332
  it in. Each repo xezar boots in registers itself in a per-user registry at
327
333
  `~/.xezar/config.json` — the workspace file that also holds the global knobs
328
- (the parallel cap, the memory ceiling, the browse root, and the checkout root). Nothing is added to
334
+ (the parallel cap, the memory ceiling, the idle timeout, the default worktree retention, the Inbox switch, the agent env passthrough list, the browse root, and the checkout root). Nothing is added to
329
335
  the repo: per-project state stays exactly where it was, in that repo's
330
336
  `.local/xezar/`.
331
337
 
@@ -368,10 +374,11 @@ These read and write `~/.xezar/config.json` directly, so they work with the
368
374
  server stopped, and `XEZ_HOME` selects which workspace they operate on.
369
375
 
370
376
  Settings split along the same line: **General** (the project's folder, its
371
- registry facts, its parallel-task ceiling, and Remove), **Agents**,
372
- **Worktrees**, **Bookmarklets**, **Prompt templates** and **MCP** describe one
373
- repo and live under `/p/<projectId>/settings`; **Appearance**,
374
- **Notifications**, **Resources**, **Projects** and **Keyboard** are yours or the
377
+ registry facts, its parallel-task ceiling, and Remove), **Agents**, **Agent
378
+ config** (each agent's own settings, MCP and memory files), **Worktrees**,
379
+ **Bookmarklets** and **Prompt templates** describe one repo and live under
380
+ `/p/<projectId>/settings`; **Appearance**, **Notifications**, **Resources**,
381
+ **Skills** (update checks), **Agent accounts** and **Projects** are yours or the
375
382
  machine's and live at `/settings/global`.
376
383
 
377
384
  ### Grouping connected repositories: tags and the All tasks page
@@ -463,6 +470,7 @@ steps:
463
470
  # model: opus # optional per-step model override
464
471
  # runner: codex # optional per-step backend: claude · codex · opencode · pi
465
472
  # allowedTools: [Read, Edit, Write, Grep, Glob, Bash]
473
+ # timeout: 90m # optional per-step wall clock: 45s · 90m · 2h · none
466
474
  - id: verify
467
475
  name: Verify
468
476
  command: "npm test" # a check step: exit 0 passes
@@ -475,6 +483,34 @@ steps:
475
483
  back, its failing output is appended to the retried agent's prompt so the next
476
484
  attempt can see what broke.
477
485
 
486
+ ### How long a step may run
487
+
488
+ Every agent step has a wall clock. Leave `timeout` out and nothing changes: the
489
+ workflow's **last** step stays open for your follow-ups with no cap, and every
490
+ **earlier** agent step is killed after **30 minutes** — which is fine for a
491
+ review or a docs pass, and too short for a long investigate-and-implement step.
492
+ `timeout` is how that step asks for more:
493
+
494
+ ```yaml
495
+ - id: investigate
496
+ prompt: "{{task}}"
497
+ timeout: 3h # this step only
498
+ ```
499
+
500
+ - `45s`, `90m`, `2h` — whole numbers with `s`, `m` or `h`. Nothing else parses:
501
+ `90 minutes`, `1.5h` and `30d` are load-time errors, and so is `0s` (say
502
+ `none` if you mean no cap). The ceiling is `596h`, where Node's own timer
503
+ stops being able to count.
504
+ - `none` — no wall clock at all. The step ends when the agent ends.
505
+ - The field belongs to an **agent** step. A check step is a shell command, and
506
+ putting `timeout` on one is a load-time error rather than a key that quietly
507
+ does nothing.
508
+
509
+ **All four backends honour it.** `claude`, `codex`, `opencode` and `pi` each arm
510
+ the deadline from the same per-step value; on `claude`, `codex` and `pi` a step
511
+ that overruns is interrupted and then `SIGKILL`ed after a short grace period,
512
+ while `opencode` interrupts and waits for the session to close.
513
+
478
514
  Prefer skills over steps? A workflow can also be written in the portable
479
515
  shorthand — an ordered list of skill names, each becoming one agent step:
480
516
 
@@ -507,7 +543,7 @@ Useful environment variables:
507
543
  | `XEZ_DRY_RUN=1` | Use the bundled mock instead of the real `claude` CLI — the entire cockpit works offline, for demos and development. |
508
544
  | `XEZ_AGENT_MODELS_LOCKED=1` | Globally lock each runner to the model configured in its native Claude/Codex/OpenCode settings while keeping runner selection available. Exact `1` also delegates authentication and provider enablement to those native agents, so Xezar skips its credential probes and provider-disable preferences. Existing Xezar presets are preserved but ignored, and an environment change requires a restart. The config-file equivalent is `"modelsLocked": true` in global `~/.xezar/config.json` or one repository's `.xezar/config.json`; config-file locks do not disable provider checks. |
509
545
  | `XEZ_APPROVAL_GATE=1` | Opt into Claude's interactive approval UI; by default, unapproved tools are denied without interrupting the run. |
510
- | `XEZ_FOLLOWUPS=1` | Turn on the global follow-up **Inbox**: agents are asked to leave follow-ups in `todos.json` when they finish, and the Inbox view appears. Off by default — each task's own **Notes** handoff journal runs either way. |
546
+ | `XEZ_FOLLOWUPS=1` | Turn on the global follow-up **Inbox**: agents are asked to leave follow-ups in `todos.json` when they finish, and the Inbox view appears. Off by default — each task's own **Notes** handoff journal runs either way. The Settings → Resources toggle overrides this default and needs no restart. |
511
547
  | `XEZ_AUTOMATIONS=1` | Turn on **GitHub automations**: the Automations view appears and xezar polls GitHub on each enabled automation's interval, launching tasks from what it finds. Off by default, and only the exact value `1` enables it — without it nothing polls GitHub, the automations endpoints answer `409`, and the nav item is absent. Read at boot, so restart after changing it; definitions, receipts and high-watermarks are retained, so unsetting it and restarting restores the feature without migration or data loss. |
512
548
  | `XEZ_AUTOSAVE=1` | Re-enable the periodic (90 s) autosave commit in task worktrees. Off by default (#471) — turn-end and pre-PR flushes always run, so branches still end complete. Every autosave names its trigger in the commit subject (`xezar autosave (periodic)` vs `(turn end)` / `(run finalize)` / `(pre-PR)`), so the flushes you keep are distinguishable from the timer you disabled. |
513
549
  | `XEZ_CLAUDE_BIN=/path/to/claude` | Override which `claude` binary is used. |
@@ -527,7 +563,7 @@ Useful environment variables:
527
563
  | `XEZ_HIDE_COST=1` | Hide backend-reported monetary cost throughout the browser cockpit while leaving raw input/output token counts visible. Only the exact value `1` enables it; telemetry and API payloads are unchanged, and a restart is required after changing it. |
528
564
  | `XEZ_HIDE_TOKEN_METRICS=1` | Legacy master switch that hides both token usage and cost. It takes precedence over the two independent flags; only the exact value `1` enables it, payloads are unchanged, and a restart is required. |
529
565
  | `GITHUB_TOKEN` | Fallback for GitHub reads/PRs when `gh` isn't authenticated. |
530
- | `XEZ_ENV_PASSTHROUGH=A,B` | Forward these extra host env vars to spawned agents. By default agents get a least-privilege env (safe shell/toolchain vars + the backend's own auth + `GITHUB_TOKEN` + `XEZ_*`), not your full environment — use this to add a var an agent needs. |
566
+ | `XEZ_ENV_PASSTHROUGH=A,B` | Forward these extra host env vars to spawned agents. By default agents get a least-privilege env (safe shell/toolchain vars + the backend's own auth + `GITHUB_TOKEN` + `XEZ_*`), not your full environment — use this to add a var an agent needs. The Settings → Resources control overrides this default and needs no restart. |
531
567
  | `XEZ_AGENT_ENV_FULL=1` | Escape hatch: give spawned agents the full host environment (pre-hardening behavior). Off by default; only set it if you understand that this hands every host secret to the agent process. |
532
568
  | `XEZ_AGENT_TMPDIR=0` | Stop giving each task its own temp directory and hand agents the host `TMPDIR` again (pre-#785 behavior). On by default: every run gets `TMPDIR`/`TEMP`/`TMP` pointing at `.local/xezar/tmp/<task-id>`, created and write-probed before the agent spawns and reaped when the run ends, so concurrent tasks stop sharing one directory and a task refuses to start rather than run against a temp directory that silently swallows its shell output (see Troubleshooting below). Only an exact `0` disables it, and it disables the whole thing — the pre-spawn check included, so this stays an escape hatch you can actually take. |
533
569
  | `XEZ_REDACT_SECRETS=0` | Disable scrubbing of credential values/token shapes from the on-disk state (the NDJSON transcript and the free-text fields of `runs.json`). On by default; leave it on. Best-effort defense-in-depth, not a guarantee: it catches known token shapes and the values of your own secret-named env vars, so a credential in neither category can still get through. |
@@ -589,16 +625,16 @@ On startup xezar probes which CLIs are installed and the cockpit only offers
589
625
  the backends it found — install any one of the four and you're operational.
590
626
 
591
627
  **Models come from your own machine.** The model picker does not ship a list of
592
- vendor releases that goes stale between xezar versions. For Claude, Codex and
593
- OpenCode xezar asks the CLI on your host what *it* currently offers (Claude
594
- Code's `list_models` control request; the Codex app-server's `model/list`;
595
- `opencode models`) and shows exactly that, in that order — so a model your
596
- account gained yesterday is selectable today with no xezar release, and one your
597
- provider retired stops being offered. Discovery is read-only, costs no tokens,
598
- and is cached briefly in memory. If the CLI is missing, logged out, too old or
599
- slow, the picker quietly falls back to that runner's built-in entries (`auto`
600
- plus Claude's tier aliases) and says so in a status row; `pi`, which has no
601
- host-local catalog yet, always shows its built-in entries. `auto` — send no
628
+ vendor releases that goes stale between xezar versions. For each backend xezar
629
+ reads what *your host* currently offers Claude Code's `list_models` control
630
+ request, the Codex app-server's `model/list`, `opencode models`, and for pi its
631
+ own `~/.pi/agent/models.json` and `settings.json` — and shows exactly that, in
632
+ that order, so a model your account gained yesterday is selectable today with no
633
+ xezar release, and one your provider retired stops being offered. Discovery is
634
+ read-only, costs no tokens, and is cached briefly in memory. If a CLI is
635
+ missing, logged out, too old or slow or pi has no providers configured yet —
636
+ the picker quietly falls back to that runner's built-in entries (`auto` plus
637
+ Claude's tier aliases) and says so in a status row. `auto` — send no
602
638
  model at all and let the CLI decide — is always available, and a model you
603
639
  pinned by hand stays selectable even when it is no longer advertised.
604
640
 
@@ -654,8 +690,8 @@ happens per task and per step, not inside a variant group.
654
690
 
655
691
  The seam is deliberately small: a backend is one class implementing the
656
692
  `AgentRunner` interface (`packages/xezar/src/core/agent-runner.ts`) that turns a prompt into
657
- a stream of normalized events. Other CLIs pi, aider, whatever ships next
658
- can slot in the same way.
693
+ a stream of normalized events. `pi` was added exactly that way; other CLIs
694
+ aider, whatever ships next — can slot into the same seam.
659
695
 
660
696
  ---
661
697
 
@@ -739,12 +775,24 @@ Run data (`runs.json`, NDJSON event logs, worktrees, `todos.json`) is
739
775
  git-ignored automatically; your workflows and skills stay committable.
740
776
 
741
777
  Settings that belong to *you* rather than to a repo — the parallel cap
742
- (`maxParallel`, default **2**), the per-task memory ceiling and the checkout
743
- root live once in `~/.xezar/config.json`, alongside the
778
+ (`maxParallel`, default **2**), the per-task memory ceiling, the **idle timeout**
779
+ (`idleTimeoutMinutes`, default **15**), the default worktree retention
780
+ (`worktreeRetentionDefault`), the Inbox switch and the agent env passthrough list,
781
+ and the checkout root — live once in `~/.xezar/config.json`, alongside the
744
782
  [project registry](#multiple-projects-one-cockpit), and are edited from
745
- **Settings → Resources** and **Settings → Projects**. A `maxParallel` left over
746
- in a repo's `.xezar/config.json` is imported into the workspace file the
747
- first time xezar boots there, and ignored afterwards.
783
+ **Settings → Resources** and **Settings → Projects**.
784
+
785
+ The idle timeout is how long a task parked at `waiting` keeps its agent session
786
+ alive with nobody talking to it. After it expires the session is closed. Set it to
787
+ **Never** if you run long interactive sessions and would rather keep them — a
788
+ waiting task holds no parallel-task slot, so your queue keeps moving either way,
789
+ but its agent process stays alive and keeps using memory until you send it a
790
+ message or cancel it.
791
+
792
+ A `maxParallel` left over in a repo's `.xezar/config.json` is imported into the
793
+ workspace file the first time xezar boots there, and ignored afterwards. A per-repo
794
+ `memoryLimitMb` behaves differently on purpose: it is still honoured, and overrides
795
+ the workspace ceiling for runs in that repo.
748
796
 
749
797
  ### Editing the agents' own config (Settings → Agent config)
750
798
 
@@ -777,8 +825,9 @@ cd xezar
777
825
  npm install
778
826
  ```
779
827
 
780
- **3. Build** — compiles the api-client and the server (`tsc → packages/xezar/dist/`) and the cockpit
781
- (`vite build → packages/xezar/web/dist/`), then runs the pack gate:
828
+ **3. Build** — compiles the server (`tsc → packages/xezar/dist/`), folds the
829
+ contract into `dist/contract/` so the published tarball resolves it, and builds
830
+ the cockpit (`vite build → packages/xezar/web/dist/`), then runs the pack gate:
782
831
 
783
832
  ```bash
784
833
  npm run build
@@ -840,6 +889,11 @@ npm run test:package # pack/install and exercise the built CLI
840
889
  npm run test:e2e # real-browser cockpit suite (agent-browser)
841
890
  ```
842
891
 
892
+ Coverage is measured separately, and is not part of the validation gate:
893
+ `npm run test:coverage` runs the vitest suites under the v8 provider and writes line and branch
894
+ numbers to `.local/coverage/`. The behaviour-led gap analysis built from it lives in
895
+ [docs/testing/coverage-gaps.md](docs/testing/coverage-gaps.md).
896
+
843
897
  The stack is deliberately small: **TypeScript** (strict, ESM), **Hono** + SSE for
844
898
  the server, **Zod** at every boundary, **YAML** for workflows, and a **React 19 +
845
899
  Vite + Tailwind v4 + shadcn/ui** cockpit shipped pre-built in `packages/xezar/web/dist/` — the
@@ -28,6 +28,16 @@ export interface AgentHomePaths {
28
28
  codex: string;
29
29
  /** `$XDG_CONFIG_HOME/opencode` or `~/.config/opencode` */
30
30
  opencodeConfig: string;
31
+ /**
32
+ * `~/.pi/agent` — pi's whole per-user directory (`models.json`, `settings.json`, and the
33
+ * `auth.json` xezar never reads). No vendor variable relocates it (verified against pi 0.85.1,
34
+ * 2026-09-10), which is why this slot carries no `env.` alternative the way the three above do.
35
+ *
36
+ * `CONFIG_FILES` lists no pi entry yet, so nothing in the raw config editor resolves through
37
+ * this slot today; model discovery (#152) does, and it lives here so pi's home is derived in
38
+ * the one place every other agent's is.
39
+ */
40
+ pi: string;
31
41
  }
32
42
  export interface ConfigFileDef {
33
43
  /** Stable, opaque, URL-safe. The ONLY thing a client may name (traversal-proof). */
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/agent-config/catalog.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/agent-config/catalog.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ import { projectDataDir } from '../project-data-paths.js';
2
2
  import { existsSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
4
  import { AutomationStore } from './store.js';
5
+ import { ownProjectData } from '../runs/project-writer.js';
5
6
  /**
6
7
  * Lightweight workspace index for project automation state. Discovery checks
7
8
  * only the optional definitions file and never materializes a RunManager or a
@@ -46,6 +47,13 @@ export class AutomationCoordinator {
46
47
  const projectRoot = root ?? this.roots.get(projectId);
47
48
  if (!projectRoot)
48
49
  return undefined;
50
+ try {
51
+ ownProjectData(projectDataDir(projectRoot));
52
+ }
53
+ catch (error) {
54
+ this.options.warn?.(`Automation project is unavailable: ${error instanceof Error ? error.message : String(error)}`);
55
+ return undefined;
56
+ }
49
57
  const store = AutomationStore.open(projectDataDir(projectRoot), { warn: this.options.warn });
50
58
  this.stores.set(projectId, store);
51
59
  this.roots.set(projectId, projectRoot);
@@ -1 +1 @@
1
- {"version":3,"file":"coordinator.js","sourceRoot":"","sources":["../../src/automations/coordinator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"coordinator.js","sourceRoot":"","sources":["../../src/automations/coordinator.ts"],"names":[],"mappings":"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"}
@@ -32,6 +32,7 @@ export declare const automationTaskSchema: z.ZodObject<{
32
32
  }>>;
33
33
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
34
34
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
35
+ timeout: z.ZodOptional<z.ZodString>;
35
36
  command: z.ZodOptional<z.ZodString>;
36
37
  onFail: z.ZodOptional<z.ZodObject<{
37
38
  retry: z.ZodString;
@@ -91,6 +92,7 @@ export declare const automationDefinitionSchema: z.ZodObject<{
91
92
  }>>;
92
93
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
93
94
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
95
+ timeout: z.ZodOptional<z.ZodString>;
94
96
  command: z.ZodOptional<z.ZodString>;
95
97
  onFail: z.ZodOptional<z.ZodObject<{
96
98
  retry: z.ZodString;
@@ -73,6 +73,7 @@ export declare const automationTaskSchema: z.ZodObject<{
73
73
  }>>;
74
74
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
75
75
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
76
+ timeout: z.ZodOptional<z.ZodString>;
76
77
  command: z.ZodOptional<z.ZodString>;
77
78
  onFail: z.ZodOptional<z.ZodObject<{
78
79
  retry: z.ZodString;
@@ -135,6 +136,7 @@ export declare const automationDefinitionSchema: z.ZodObject<{
135
136
  }>>;
136
137
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
137
138
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
139
+ timeout: z.ZodOptional<z.ZodString>;
138
140
  command: z.ZodOptional<z.ZodString>;
139
141
  onFail: z.ZodOptional<z.ZodObject<{
140
142
  retry: z.ZodString;
@@ -290,6 +292,7 @@ export declare const automationListEntrySchema: z.ZodObject<{
290
292
  }>>;
291
293
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
292
294
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
295
+ timeout: z.ZodOptional<z.ZodString>;
293
296
  command: z.ZodOptional<z.ZodString>;
294
297
  onFail: z.ZodOptional<z.ZodObject<{
295
298
  retry: z.ZodString;
@@ -435,6 +438,7 @@ export declare const automationsResponseSchema: z.ZodObject<{
435
438
  }>>;
436
439
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
437
440
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
441
+ timeout: z.ZodOptional<z.ZodString>;
438
442
  command: z.ZodOptional<z.ZodString>;
439
443
  onFail: z.ZodOptional<z.ZodObject<{
440
444
  retry: z.ZodString;
@@ -565,6 +569,7 @@ export declare const automationResponseSchema: z.ZodObject<{
565
569
  }>>;
566
570
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
567
571
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
572
+ timeout: z.ZodOptional<z.ZodString>;
568
573
  command: z.ZodOptional<z.ZodString>;
569
574
  onFail: z.ZodOptional<z.ZodObject<{
570
575
  retry: z.ZodString;
@@ -632,6 +637,7 @@ export declare const automationDetailResponseSchema: z.ZodObject<{
632
637
  }>>;
633
638
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
634
639
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
640
+ timeout: z.ZodOptional<z.ZodString>;
635
641
  command: z.ZodOptional<z.ZodString>;
636
642
  onFail: z.ZodOptional<z.ZodObject<{
637
643
  retry: z.ZodString;
@@ -835,6 +841,7 @@ export declare const createAutomationInputSchema: z.ZodObject<{
835
841
  }>>;
836
842
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
837
843
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
844
+ timeout: z.ZodOptional<z.ZodString>;
838
845
  command: z.ZodOptional<z.ZodString>;
839
846
  onFail: z.ZodOptional<z.ZodObject<{
840
847
  retry: z.ZodString;
@@ -900,6 +907,7 @@ export declare const updateAutomationInputSchema: z.ZodObject<{
900
907
  }>>;
901
908
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
902
909
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
910
+ timeout: z.ZodOptional<z.ZodString>;
903
911
  command: z.ZodOptional<z.ZodString>;
904
912
  onFail: z.ZodOptional<z.ZodObject<{
905
913
  retry: z.ZodString;
@@ -0,0 +1 @@
1
+ export {};
@@ -357,6 +357,12 @@ var workflowStepDefSchema = z4.object({
357
357
  runner: runnerSchema.optional(),
358
358
  allowedTools: z4.array(z4.string()).optional(),
359
359
  bashAllowlist: z4.array(z4.string()).optional(),
360
+ /** This step's own wall-clock cap (#22): `45s` / `90m` / `2h`, or `none` for no cap.
361
+ * Typed as a plain string here, exactly as `model` is: the DURATION FORMAT is validated
362
+ * by `src/workflows/types.ts`'s `stepTimeoutSchema`, which is the single source of truth
363
+ * for what a user may author (workflow YAML and the inline chain on `POST /runs` both go
364
+ * through it). Restating the grammar here would be a second copy free to drift. */
365
+ timeout: z4.string().optional(),
360
366
  // check step
361
367
  command: z4.string().optional(),
362
368
  onFail: z4.object({
@@ -660,6 +666,43 @@ var runIndexEntrySchema = z5.object({
660
666
  * refinement `workflowLabel` applies needs `steps[]`, which this row deliberately omits, so
661
667
  * a `(planned)` chain reads as itself here rather than as its first agent's name. */
662
668
  workflow: z5.string(),
669
+ /**
670
+ * The backend this run ran as — RESOLVED server-side, in order of how good the evidence is.
671
+ *
672
+ * 1. `RunRecord.runner`. NOT "what the caller asked for": `execute` writes the resolved backend
673
+ * onto the record the moment a run starts, so for anything that ever ran this is a fact.
674
+ * 2. Otherwise the last step that recorded a backend — steps stamp theirs at spawn, so a record
675
+ * written before run-level backend affinity still says what it used.
676
+ * 3. Otherwise the project's current `defaultRunner`, and only then is `runnerInherited` set.
677
+ *
678
+ * Resolved HERE rather than in the browser because these rows span every registered project:
679
+ * finishing step 3 client-side would be one config request per project. A project-scoped surface
680
+ * does it itself, from the one `GET /config` it already holds.
681
+ */
682
+ runner: runnerSchema,
683
+ /**
684
+ * Present ONLY when true: the run carried no runner and no step backend, so `runner` above is
685
+ * the project's current default.
686
+ *
687
+ * That is the one case that is not history. A run with no evidence at all has not started, so
688
+ * the value is what the task WOULD run as — which is why the cockpit renders it muted. Absent
689
+ * means the row is reporting what actually ran.
690
+ */
691
+ runnerInherited: z5.boolean().optional(),
692
+ /** The model string the run recorded, VERBATIM (`RunRecord.model`). Absent means none was
693
+ * recorded and the backend picked, which the cockpit prints as a muted `auto` — the same word
694
+ * the task detail header uses. Never prettified through a catalog: a locally-hosted backend's
695
+ * own id is the only honest answer. */
696
+ model: z5.string().optional(),
697
+ /**
698
+ * How many DISTINCT backends this run's recorded steps used — a workflow may name one per step.
699
+ *
700
+ * A COUNT, deliberately, and present only when it is greater than 1. This row exists to be
701
+ * slim; `steps[]` is exactly the half it refuses to carry, so the mixed-chain signal is derived
702
+ * server-side and reduced to the one number the cell renders (`Claude Code +1`). Absent means
703
+ * one backend or none — which is every ordinary run.
704
+ */
705
+ stepBackends: z5.number().int().min(2).optional(),
663
706
  /** The task's branch, when it has one — a column on the global page, and the one field that
664
707
  * makes a cross-project row identifiable at a glance without opening it. */
665
708
  branch: z5.string().optional(),
@@ -1081,6 +1124,15 @@ var workspaceConfigResponseSchema = z8.object({
1081
1124
  /** Stored override; `null` means inherit `XEZ_SKILLS_AUTO_UPDATE`, then true. */
1082
1125
  skillsAutoUpdate: z8.boolean().nullable(),
1083
1126
  effectiveSkillsAutoUpdate: z8.boolean(),
1127
+ /** Stored follow-up Inbox override (F); `null` = no stored key, `XEZ_FOLLOWUPS` decides. */
1128
+ followups: z8.boolean().nullable(),
1129
+ /** What `followups` + the env actually resolve to right now — what the cockpit shows. */
1130
+ effectiveFollowups: z8.boolean(),
1131
+ /** Stored extra agent env-passthrough names (F); `null` = no stored key,
1132
+ * `XEZ_ENV_PASSTHROUGH` decides. `[]` is a real stored "forward nothing". */
1133
+ agentEnvPassthrough: z8.array(z8.string()).nullable(),
1134
+ /** What `agentEnvPassthrough` + the env actually resolve to right now. */
1135
+ effectiveAgentEnvPassthrough: z8.array(z8.string()),
1084
1136
  composerDefaults: z8.object({
1085
1137
  autonomous: z8.boolean().nullable(),
1086
1138
  worktree: z8.boolean().nullable(),
@@ -1094,7 +1146,13 @@ var workspaceConfigResponseSchema = z8.object({
1094
1146
  monitoringWakeIntervalMinutes: z8.number().nullable(),
1095
1147
  /** Resume a run a provider usage limit stopped, once the limit resets. Default `true`. */
1096
1148
  autoResumeOnUsageLimit: z8.boolean(),
1149
+ /** Wall clock for a session parked at `waiting`, in minutes; `null` = never close on
1150
+ * idle. Default 15. */
1151
+ idleTimeoutMinutes: z8.number().nullable(),
1097
1152
  memoryLimitMb: z8.number().nullable(),
1153
+ /** The host-derived ceiling an ABSENT `memoryLimitMb` falls back to (B1) — reported so
1154
+ * the settings pane can name the machine's own default instead of guessing it. */
1155
+ memoryLimitDefaultMb: z8.number(),
1098
1156
  worktreeRetentionDefault: z8.number()
1099
1157
  }),
1100
1158
  /**
@@ -1119,6 +1177,11 @@ var setWorkspaceConfigInputSchema = z8.object({
1119
1177
  browseRoot: z8.string().trim().min(1).max(4096).optional(),
1120
1178
  projectsDir: z8.string().trim().min(1).max(4096).optional(),
1121
1179
  skillsAutoUpdate: z8.boolean().nullable().optional(),
1180
+ /** Stored Inbox override (F): `null` clears the key back to the `XEZ_FOLLOWUPS` default. */
1181
+ followups: z8.boolean().nullable().optional(),
1182
+ /** Stored env-passthrough names (F): `null` clears the key back to the
1183
+ * `XEZ_ENV_PASSTHROUGH` default; `[]` stores a real "forward nothing". */
1184
+ agentEnvPassthrough: z8.array(z8.string().trim().min(1).max(200)).max(64).nullable().optional(),
1122
1185
  composerDefaults: z8.object({
1123
1186
  autonomous: z8.boolean().nullable().optional(),
1124
1187
  worktree: z8.boolean().nullable().optional()
@@ -1139,6 +1202,8 @@ var setWorkspaceConfigInputSchema = z8.object({
1139
1202
  maxMonitoringSessions: z8.number().int().min(0).max(16).optional(),
1140
1203
  monitoringWakeIntervalMinutes: z8.number().int().min(1).max(60).nullable().optional(),
1141
1204
  autoResumeOnUsageLimit: z8.boolean().optional(),
1205
+ /** `null` = never close an idle session; a number is minutes (1 to 1440). */
1206
+ idleTimeoutMinutes: z8.number().int().min(1).max(1440).nullable().optional(),
1142
1207
  memoryLimitMb: z8.number().int().min(0).max(1048576).nullable().optional(),
1143
1208
  worktreeRetentionDefault: z8.number().int().min(0).max(1e3).optional()
1144
1209
  }).optional()
@@ -1282,7 +1347,15 @@ var configResponseSchema = z8.object({
1282
1347
  liveTitleUpdates: z8.boolean().nullable(),
1283
1348
  /** Optional review gate (#489): null = no config key, the `XEZ_REVIEW_GATE` env default (OFF)
1284
1349
  * decides. */
1285
- reviewGate: z8.boolean().nullable()
1350
+ reviewGate: z8.boolean().nullable(),
1351
+ /** Model the chain planner runs on (Claude aliases only; other backends pick their own).
1352
+ * Always materialized — the file schema defaults it to `sonnet` (E). */
1353
+ plannerModel: z8.string(),
1354
+ /** Model the task namer runs on, same rule as `plannerModel`. Defaults to `haiku` (E). */
1355
+ namerModel: z8.string(),
1356
+ /** Team skill sources (E). Always materialized: the file schema defaults it to the shared
1357
+ * catalog, and `[]` is a real "no team skills" choice. */
1358
+ skillsRepos: z8.array(z8.object({ repo: z8.string(), ref: z8.string() }))
1286
1359
  });
1287
1360
  var setConfigResponseSchema = configResponseSchema;
1288
1361
  var setConfigInputSchema = z8.object({
@@ -1303,7 +1376,18 @@ var setConfigInputSchema = z8.object({
1303
1376
  /** null clears the key back to the env-default behavior. */
1304
1377
  liveTitleUpdates: z8.boolean().nullable().optional(),
1305
1378
  /** null clears the key back to the env-default behavior (OFF). */
1306
- reviewGate: z8.boolean().nullable().optional()
1379
+ reviewGate: z8.boolean().nullable().optional(),
1380
+ /** `null` clears the key back to the schema default (`sonnet`). */
1381
+ plannerModel: z8.string().trim().min(1).max(200).nullable().optional(),
1382
+ /** `null` clears the key back to the schema default (`haiku`). */
1383
+ namerModel: z8.string().trim().min(1).max(200).nullable().optional(),
1384
+ /** `null` clears the key back to the default catalog; `[]` disables team skills. */
1385
+ skillsRepos: z8.array(
1386
+ z8.object({
1387
+ repo: z8.string().trim().min(1).max(500),
1388
+ ref: z8.string().trim().min(1).max(200).optional()
1389
+ })
1390
+ ).max(32).nullable().optional()
1307
1391
  });
1308
1392
  var skillsUpdateStatusSchema = z8.enum([
1309
1393
  "idle",
@@ -1359,7 +1443,7 @@ var providerConnectResponseSchema = z8.discriminatedUnion("opened", [
1359
1443
  z8.object({ opened: z8.literal(true), command: z8.string() }),
1360
1444
  z8.object({ opened: z8.literal(false), connected: z8.literal(true), command: z8.string() })
1361
1445
  ]);
1362
- var modelDiscoveryRunnerSchema = z8.enum(["claude", "codex", "opencode"]);
1446
+ var modelDiscoveryRunnerSchema = z8.enum(["claude", "codex", "opencode", "pi"]);
1363
1447
  var MODEL_DISCOVERY_RUNNERS = modelDiscoveryRunnerSchema.options;
1364
1448
  function runnerDiscoversModels(runner) {
1365
1449
  return MODEL_DISCOVERY_RUNNERS.includes(runner);