oh-my-opencode 4.3.1 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. package/.agents/command/get-unpublished-changes.md +148 -0
  2. package/.agents/command/omomomo.md +37 -0
  3. package/.agents/command/publish.md +376 -0
  4. package/.agents/command/remove-deadcode.md +221 -0
  5. package/.agents/command/security-research.md +16 -0
  6. package/.agents/skills/get-unpublished-changes/SKILL.md +24 -0
  7. package/.agents/skills/github-triage/SKILL.md +587 -0
  8. package/.agents/skills/github-triage/scripts/gh_fetch.py +398 -0
  9. package/.agents/skills/hyperplan/SKILL.md +450 -0
  10. package/.agents/skills/omomomo/SKILL.md +36 -0
  11. package/.agents/skills/pre-publish-review/SKILL.md +407 -0
  12. package/.agents/skills/publish/SKILL.md +428 -0
  13. package/.agents/skills/remove-deadcode/SKILL.md +216 -0
  14. package/.agents/skills/security-research/SKILL.md +204 -0
  15. package/.agents/skills/work-with-pr/SKILL.md +360 -0
  16. package/.agents/skills/work-with-pr-workspace/evals/evals.json +76 -0
  17. package/.agents/skills/work-with-pr-workspace/iteration-1/benchmark.json +138 -0
  18. package/.agents/skills/work-with-pr-workspace/iteration-1/benchmark.md +42 -0
  19. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/eval_metadata.json +57 -0
  20. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/grading.json +15 -0
  21. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/code-changes.md +454 -0
  22. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/execution-plan.md +136 -0
  23. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/pr-description.md +47 -0
  24. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/verification-strategy.md +163 -0
  25. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/timing.json +1 -0
  26. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/grading.json +15 -0
  27. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/code-changes.md +615 -0
  28. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/execution-plan.md +99 -0
  29. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/pr-description.md +50 -0
  30. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/verification-strategy.md +111 -0
  31. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/timing.json +1 -0
  32. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/eval_metadata.json +37 -0
  33. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/grading.json +11 -0
  34. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/code-changes.md +205 -0
  35. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/execution-plan.md +78 -0
  36. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/pr-description.md +42 -0
  37. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/verification-strategy.md +87 -0
  38. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/timing.json +1 -0
  39. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/grading.json +11 -0
  40. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/code-changes.md +334 -0
  41. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/execution-plan.md +86 -0
  42. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/pr-description.md +23 -0
  43. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/verification-strategy.md +119 -0
  44. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/timing.json +1 -0
  45. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/eval_metadata.json +32 -0
  46. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/grading.json +10 -0
  47. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/code-changes.md +221 -0
  48. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/execution-plan.md +104 -0
  49. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/pr-description.md +41 -0
  50. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/verification-strategy.md +84 -0
  51. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/timing.json +1 -0
  52. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/grading.json +10 -0
  53. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/code-changes.md +342 -0
  54. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/execution-plan.md +131 -0
  55. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/pr-description.md +39 -0
  56. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/verification-strategy.md +128 -0
  57. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/timing.json +1 -0
  58. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/eval_metadata.json +32 -0
  59. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/grading.json +10 -0
  60. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/code-changes.md +143 -0
  61. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/execution-plan.md +82 -0
  62. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/pr-description.md +51 -0
  63. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/verification-strategy.md +69 -0
  64. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/timing.json +1 -0
  65. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/grading.json +10 -0
  66. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/code-changes.md +252 -0
  67. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/execution-plan.md +83 -0
  68. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/pr-description.md +33 -0
  69. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/verification-strategy.md +101 -0
  70. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/timing.json +1 -0
  71. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/eval_metadata.json +32 -0
  72. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/grading.json +10 -0
  73. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/code-changes.md +387 -0
  74. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/execution-plan.md +112 -0
  75. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/pr-description.md +51 -0
  76. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/verification-strategy.md +75 -0
  77. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/timing.json +1 -0
  78. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/grading.json +10 -0
  79. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/code-changes.md +529 -0
  80. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/execution-plan.md +127 -0
  81. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/pr-description.md +42 -0
  82. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/verification-strategy.md +120 -0
  83. package/.agents/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/timing.json +1 -0
  84. package/.agents/skills/work-with-pr-workspace/iteration-1/review.html +1326 -0
  85. package/.opencode/command/get-unpublished-changes.md +148 -0
  86. package/.opencode/command/omomomo.md +37 -0
  87. package/.opencode/command/publish.md +376 -0
  88. package/.opencode/command/remove-deadcode.md +221 -0
  89. package/.opencode/command/security-research.md +16 -0
  90. package/.opencode/skills/github-triage/SKILL.md +587 -0
  91. package/.opencode/skills/github-triage/scripts/gh_fetch.py +398 -0
  92. package/.opencode/skills/hyperplan/SKILL.md +450 -0
  93. package/.opencode/skills/pre-publish-review/SKILL.md +407 -0
  94. package/.opencode/skills/work-with-pr/SKILL.md +360 -0
  95. package/.opencode/skills/work-with-pr-workspace/evals/evals.json +76 -0
  96. package/.opencode/skills/work-with-pr-workspace/iteration-1/benchmark.json +138 -0
  97. package/.opencode/skills/work-with-pr-workspace/iteration-1/benchmark.md +42 -0
  98. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/eval_metadata.json +57 -0
  99. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/grading.json +15 -0
  100. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/code-changes.md +454 -0
  101. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/execution-plan.md +136 -0
  102. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/pr-description.md +47 -0
  103. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/outputs/verification-strategy.md +163 -0
  104. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/with_skill/timing.json +1 -0
  105. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/grading.json +15 -0
  106. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/code-changes.md +615 -0
  107. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/execution-plan.md +99 -0
  108. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/pr-description.md +50 -0
  109. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/outputs/verification-strategy.md +111 -0
  110. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-1/without_skill/timing.json +1 -0
  111. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/eval_metadata.json +37 -0
  112. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/grading.json +11 -0
  113. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/code-changes.md +205 -0
  114. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/execution-plan.md +78 -0
  115. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/pr-description.md +42 -0
  116. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/outputs/verification-strategy.md +87 -0
  117. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/with_skill/timing.json +1 -0
  118. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/grading.json +11 -0
  119. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/code-changes.md +334 -0
  120. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/execution-plan.md +86 -0
  121. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/pr-description.md +23 -0
  122. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/outputs/verification-strategy.md +119 -0
  123. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-2/without_skill/timing.json +1 -0
  124. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/eval_metadata.json +32 -0
  125. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/grading.json +10 -0
  126. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/code-changes.md +221 -0
  127. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/execution-plan.md +104 -0
  128. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/pr-description.md +41 -0
  129. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/outputs/verification-strategy.md +84 -0
  130. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/with_skill/timing.json +1 -0
  131. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/grading.json +10 -0
  132. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/code-changes.md +342 -0
  133. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/execution-plan.md +131 -0
  134. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/pr-description.md +39 -0
  135. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/outputs/verification-strategy.md +128 -0
  136. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-3/without_skill/timing.json +1 -0
  137. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/eval_metadata.json +32 -0
  138. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/grading.json +10 -0
  139. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/code-changes.md +143 -0
  140. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/execution-plan.md +82 -0
  141. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/pr-description.md +51 -0
  142. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/outputs/verification-strategy.md +69 -0
  143. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/with_skill/timing.json +1 -0
  144. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/grading.json +10 -0
  145. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/code-changes.md +252 -0
  146. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/execution-plan.md +83 -0
  147. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/pr-description.md +33 -0
  148. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/outputs/verification-strategy.md +101 -0
  149. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-4/without_skill/timing.json +1 -0
  150. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/eval_metadata.json +32 -0
  151. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/grading.json +10 -0
  152. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/code-changes.md +387 -0
  153. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/execution-plan.md +112 -0
  154. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/pr-description.md +51 -0
  155. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/outputs/verification-strategy.md +75 -0
  156. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/with_skill/timing.json +1 -0
  157. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/grading.json +10 -0
  158. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/code-changes.md +529 -0
  159. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/execution-plan.md +127 -0
  160. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/pr-description.md +42 -0
  161. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/outputs/verification-strategy.md +120 -0
  162. package/.opencode/skills/work-with-pr-workspace/iteration-1/eval-5/without_skill/timing.json +1 -0
  163. package/.opencode/skills/work-with-pr-workspace/iteration-1/review.html +1326 -0
  164. package/README.ja.md +1 -1
  165. package/README.ko.md +1 -1
  166. package/README.md +1 -1
  167. package/README.ru.md +1 -1
  168. package/README.zh-cn.md +1 -1
  169. package/dist/agents/atlas/agent.d.ts +6 -6
  170. package/dist/agents/prometheus/gemini.d.ts +0 -11
  171. package/dist/agents/prometheus/gpt.d.ts +0 -10
  172. package/dist/agents/prometheus/system-prompt.d.ts +2 -20
  173. package/dist/agents/types.d.ts +1 -16
  174. package/dist/cli/index.js +60 -20
  175. package/dist/config/schema/agent-names.d.ts +3 -3
  176. package/dist/config/schema/agent-overrides.d.ts +208 -208
  177. package/dist/config/schema/categories.d.ts +28 -28
  178. package/dist/config/schema/fallback-models.d.ts +20 -20
  179. package/dist/config/schema/oh-my-opencode-config.d.ts +208 -208
  180. package/dist/features/background-agent/parent-wake-dedupe.d.ts +19 -0
  181. package/dist/features/background-agent/parent-wake-notifier.d.ts +8 -19
  182. package/dist/help/schema/acp.d.ts +95 -0
  183. package/dist/help/schema/doctor.d.ts +147 -0
  184. package/dist/help/schema/sandbox.d.ts +74 -0
  185. package/dist/help/schema/status.d.ts +139 -0
  186. package/dist/hooks/keyword-detector/analyze/default.d.ts +1 -1
  187. package/dist/hooks/keyword-detector/hyperplan/default.d.ts +1 -1
  188. package/dist/hooks/keyword-detector/search/default.d.ts +1 -1
  189. package/dist/hooks/keyword-detector/team/default.d.ts +2 -7
  190. package/dist/hooks/keyword-detector/ultrawork/default.d.ts +1 -9
  191. package/dist/hooks/keyword-detector/ultrawork/gemini.d.ts +1 -16
  192. package/dist/hooks/keyword-detector/ultrawork/gpt.d.ts +1 -10
  193. package/dist/hooks/keyword-detector/ultrawork/planner.d.ts +1 -5
  194. package/dist/hooks/ralph-loop/no-progress-turn-detector.d.ts +7 -0
  195. package/dist/hooks/ralph-loop/pending-verification-handler.d.ts +1 -0
  196. package/dist/hooks/ralph-loop/types.d.ts +1 -0
  197. package/dist/hooks/runtime-fallback/error-classifier.d.ts +1 -0
  198. package/dist/hooks/tool-pair-validator/hook.d.ts +6 -1
  199. package/dist/index.js +51976 -50299
  200. package/dist/plugin-handlers/provider-config-handler.d.ts +1 -0
  201. package/dist/shared/migration/model-versions.d.ts +6 -0
  202. package/dist/shared/prompt-async-gate/pending-tool-turn.d.ts +1 -0
  203. package/dist/shared/prompt-async-gate/types.d.ts +4 -3
  204. package/package.json +19 -13
  205. package/dist/agents/atlas/default-prompt-sections.d.ts +0 -6
  206. package/dist/agents/atlas/default.d.ts +0 -2
  207. package/dist/agents/atlas/gemini-prompt-sections.d.ts +0 -6
  208. package/dist/agents/atlas/gemini.d.ts +0 -2
  209. package/dist/agents/atlas/gpt-prompt-sections.d.ts +0 -6
  210. package/dist/agents/atlas/gpt.d.ts +0 -2
  211. package/dist/agents/atlas/kimi-prompt-sections.d.ts +0 -6
  212. package/dist/agents/atlas/kimi.d.ts +0 -2
  213. package/dist/agents/atlas/opus-4-7-prompt-sections.d.ts +0 -6
  214. package/dist/agents/atlas/opus-4-7.d.ts +0 -2
  215. package/dist/agents/atlas/shared-prompt.d.ts +0 -9
  216. package/dist/agents/prometheus/behavioral-summary.d.ts +0 -6
  217. package/dist/agents/prometheus/high-accuracy-mode.d.ts +0 -6
  218. package/dist/agents/prometheus/identity-constraints.d.ts +0 -7
  219. package/dist/agents/prometheus/interview-mode.d.ts +0 -7
  220. package/dist/agents/prometheus/plan-generation.d.ts +0 -7
  221. package/dist/agents/prometheus/plan-template.d.ts +0 -7
  222. package/dist/agents/prometheus/spec-driven-mode.d.ts +0 -7
@@ -0,0 +1,454 @@
1
+ # Code Changes: `max_background_agents` Config Option
2
+
3
+ ## 1. `src/config/schema/background-task.ts` — Add schema field
4
+
5
+ ```typescript
6
+ import { z } from "zod"
7
+
8
+ export const BackgroundTaskConfigSchema = z.object({
9
+ defaultConcurrency: z.number().min(1).optional(),
10
+ providerConcurrency: z.record(z.string(), z.number().min(0)).optional(),
11
+ modelConcurrency: z.record(z.string(), z.number().min(0)).optional(),
12
+ maxDepth: z.number().int().min(1).optional(),
13
+ maxDescendants: z.number().int().min(1).optional(),
14
+ /** Maximum number of background agents that can run simultaneously across all models/providers (default: 5, minimum: 1) */
15
+ maxBackgroundAgents: z.number().int().min(1).optional(),
16
+ /** Stale timeout in milliseconds - interrupt tasks with no activity for this duration (default: 180000 = 3 minutes, minimum: 60000 = 1 minute) */
17
+ staleTimeoutMs: z.number().min(60000).optional(),
18
+ /** Timeout for tasks that never received any progress update, falling back to startedAt (default: 1800000 = 30 minutes, minimum: 60000 = 1 minute) */
19
+ messageStalenessTimeoutMs: z.number().min(60000).optional(),
20
+ syncPollTimeoutMs: z.number().min(60000).optional(),
21
+ })
22
+
23
+ export type BackgroundTaskConfig = z.infer<typeof BackgroundTaskConfigSchema>
24
+ ```
25
+
26
+ **Rationale:** Follows exact same pattern as `maxDepth` and `maxDescendants` — `z.number().int().min(1).optional()`. The field is optional; runtime default of 5 is applied in `ConcurrencyManager`. No barrel export changes needed since `src/config/schema.ts` already does `export * from "./schema/background-task"` and the type is inferred.
27
+
28
+ ---
29
+
30
+ ## 2. `src/config/schema/background-task.test.ts` — Add validation tests
31
+
32
+ Append after the existing `syncPollTimeoutMs` describe block (before the closing `})`):
33
+
34
+ ```typescript
35
+ describe("maxBackgroundAgents", () => {
36
+ describe("#given valid maxBackgroundAgents (10)", () => {
37
+ test("#when parsed #then returns correct value", () => {
38
+ const result = BackgroundTaskConfigSchema.parse({ maxBackgroundAgents: 10 })
39
+
40
+ expect(result.maxBackgroundAgents).toBe(10)
41
+ })
42
+ })
43
+
44
+ describe("#given maxBackgroundAgents of 1 (minimum)", () => {
45
+ test("#when parsed #then returns correct value", () => {
46
+ const result = BackgroundTaskConfigSchema.parse({ maxBackgroundAgents: 1 })
47
+
48
+ expect(result.maxBackgroundAgents).toBe(1)
49
+ })
50
+ })
51
+
52
+ describe("#given maxBackgroundAgents below minimum (0)", () => {
53
+ test("#when parsed #then throws ZodError", () => {
54
+ let thrownError: unknown
55
+
56
+ try {
57
+ BackgroundTaskConfigSchema.parse({ maxBackgroundAgents: 0 })
58
+ } catch (error) {
59
+ thrownError = error
60
+ }
61
+
62
+ expect(thrownError).toBeInstanceOf(ZodError)
63
+ })
64
+ })
65
+
66
+ describe("#given maxBackgroundAgents not provided", () => {
67
+ test("#when parsed #then field is undefined", () => {
68
+ const result = BackgroundTaskConfigSchema.parse({})
69
+
70
+ expect(result.maxBackgroundAgents).toBeUndefined()
71
+ })
72
+ })
73
+
74
+ describe('#given maxBackgroundAgents is non-integer (2.5)', () => {
75
+ test("#when parsed #then throws ZodError", () => {
76
+ let thrownError: unknown
77
+
78
+ try {
79
+ BackgroundTaskConfigSchema.parse({ maxBackgroundAgents: 2.5 })
80
+ } catch (error) {
81
+ thrownError = error
82
+ }
83
+
84
+ expect(thrownError).toBeInstanceOf(ZodError)
85
+ })
86
+ })
87
+ })
88
+ ```
89
+
90
+ **Rationale:** Follows exact test pattern from `maxDepth`, `maxDescendants`, and `syncPollTimeoutMs` tests. Uses `#given`/`#when`/`#then` nested describe style. Tests valid, minimum boundary, below minimum, not provided, and non-integer cases.
91
+
92
+ ---
93
+
94
+ ## 3. `src/features/background-agent/concurrency.ts` — Add global agent limit
95
+
96
+ ```typescript
97
+ import type { BackgroundTaskConfig } from "../../config/schema"
98
+
99
+ const DEFAULT_MAX_BACKGROUND_AGENTS = 5
100
+
101
+ /**
102
+ * Queue entry with settled-flag pattern to prevent double-resolution.
103
+ *
104
+ * The settled flag ensures that cancelWaiters() doesn't reject
105
+ * an entry that was already resolved by release().
106
+ */
107
+ interface QueueEntry {
108
+ resolve: () => void
109
+ rawReject: (error: Error) => void
110
+ settled: boolean
111
+ }
112
+
113
+ export class ConcurrencyManager {
114
+ private config?: BackgroundTaskConfig
115
+ private counts: Map<string, number> = new Map()
116
+ private queues: Map<string, QueueEntry[]> = new Map()
117
+ private globalRunningCount = 0
118
+
119
+ constructor(config?: BackgroundTaskConfig) {
120
+ this.config = config
121
+ }
122
+
123
+ getMaxBackgroundAgents(): number {
124
+ return this.config?.maxBackgroundAgents ?? DEFAULT_MAX_BACKGROUND_AGENTS
125
+ }
126
+
127
+ getGlobalRunningCount(): number {
128
+ return this.globalRunningCount
129
+ }
130
+
131
+ canSpawnGlobally(): boolean {
132
+ return this.globalRunningCount < this.getMaxBackgroundAgents()
133
+ }
134
+
135
+ acquireGlobal(): void {
136
+ this.globalRunningCount++
137
+ }
138
+
139
+ releaseGlobal(): void {
140
+ if (this.globalRunningCount > 0) {
141
+ this.globalRunningCount--
142
+ }
143
+ }
144
+
145
+ getConcurrencyLimit(model: string): number {
146
+ // ... existing implementation unchanged ...
147
+ }
148
+
149
+ async acquire(model: string): Promise<void> {
150
+ // ... existing implementation unchanged ...
151
+ }
152
+
153
+ release(model: string): void {
154
+ // ... existing implementation unchanged ...
155
+ }
156
+
157
+ cancelWaiters(model: string): void {
158
+ // ... existing implementation unchanged ...
159
+ }
160
+
161
+ clear(): void {
162
+ for (const [model] of this.queues) {
163
+ this.cancelWaiters(model)
164
+ }
165
+ this.counts.clear()
166
+ this.queues.clear()
167
+ this.globalRunningCount = 0
168
+ }
169
+
170
+ getCount(model: string): number {
171
+ return this.counts.get(model) ?? 0
172
+ }
173
+
174
+ getQueueLength(model: string): number {
175
+ return this.queues.get(model)?.length ?? 0
176
+ }
177
+ }
178
+ ```
179
+
180
+ **Key changes:**
181
+ - Add `DEFAULT_MAX_BACKGROUND_AGENTS = 5` constant
182
+ - Add `globalRunningCount` private field
183
+ - Add `getMaxBackgroundAgents()`, `getGlobalRunningCount()`, `canSpawnGlobally()`, `acquireGlobal()`, `releaseGlobal()` methods
184
+ - `clear()` resets `globalRunningCount` to 0
185
+ - All existing per-model methods remain unchanged
186
+
187
+ ---
188
+
189
+ ## 4. `src/features/background-agent/concurrency.test.ts` — Add global limit tests
190
+
191
+ Append new describe block:
192
+
193
+ ```typescript
194
+ describe("ConcurrencyManager global background agent limit", () => {
195
+ test("should default max background agents to 5 when no config", () => {
196
+ // given
197
+ const manager = new ConcurrencyManager()
198
+
199
+ // when
200
+ const max = manager.getMaxBackgroundAgents()
201
+
202
+ // then
203
+ expect(max).toBe(5)
204
+ })
205
+
206
+ test("should use configured maxBackgroundAgents", () => {
207
+ // given
208
+ const config: BackgroundTaskConfig = { maxBackgroundAgents: 10 }
209
+ const manager = new ConcurrencyManager(config)
210
+
211
+ // when
212
+ const max = manager.getMaxBackgroundAgents()
213
+
214
+ // then
215
+ expect(max).toBe(10)
216
+ })
217
+
218
+ test("should allow spawning when under global limit", () => {
219
+ // given
220
+ const config: BackgroundTaskConfig = { maxBackgroundAgents: 2 }
221
+ const manager = new ConcurrencyManager(config)
222
+
223
+ // when
224
+ manager.acquireGlobal()
225
+
226
+ // then
227
+ expect(manager.canSpawnGlobally()).toBe(true)
228
+ expect(manager.getGlobalRunningCount()).toBe(1)
229
+ })
230
+
231
+ test("should block spawning when at global limit", () => {
232
+ // given
233
+ const config: BackgroundTaskConfig = { maxBackgroundAgents: 2 }
234
+ const manager = new ConcurrencyManager(config)
235
+
236
+ // when
237
+ manager.acquireGlobal()
238
+ manager.acquireGlobal()
239
+
240
+ // then
241
+ expect(manager.canSpawnGlobally()).toBe(false)
242
+ expect(manager.getGlobalRunningCount()).toBe(2)
243
+ })
244
+
245
+ test("should allow spawning again after release", () => {
246
+ // given
247
+ const config: BackgroundTaskConfig = { maxBackgroundAgents: 1 }
248
+ const manager = new ConcurrencyManager(config)
249
+ manager.acquireGlobal()
250
+
251
+ // when
252
+ manager.releaseGlobal()
253
+
254
+ // then
255
+ expect(manager.canSpawnGlobally()).toBe(true)
256
+ expect(manager.getGlobalRunningCount()).toBe(0)
257
+ })
258
+
259
+ test("should not go below zero on extra release", () => {
260
+ // given
261
+ const manager = new ConcurrencyManager()
262
+
263
+ // when
264
+ manager.releaseGlobal()
265
+
266
+ // then
267
+ expect(manager.getGlobalRunningCount()).toBe(0)
268
+ })
269
+
270
+ test("should reset global count on clear", () => {
271
+ // given
272
+ const config: BackgroundTaskConfig = { maxBackgroundAgents: 5 }
273
+ const manager = new ConcurrencyManager(config)
274
+ manager.acquireGlobal()
275
+ manager.acquireGlobal()
276
+ manager.acquireGlobal()
277
+
278
+ // when
279
+ manager.clear()
280
+
281
+ // then
282
+ expect(manager.getGlobalRunningCount()).toBe(0)
283
+ })
284
+ })
285
+ ```
286
+
287
+ ---
288
+
289
+ ## 5. `src/features/background-agent/manager.ts` — Enforce global limit
290
+
291
+ ### In `launch()` method — add check before task creation (after `reserveSubagentSpawn`):
292
+
293
+ ```typescript
294
+ async launch(input: LaunchInput): Promise<BackgroundTask> {
295
+ // ... existing logging ...
296
+
297
+ if (!input.agent || input.agent.trim() === "") {
298
+ throw new Error("Agent parameter is required")
299
+ }
300
+
301
+ // Check global background agent limit before spawn guard
302
+ if (!this.concurrencyManager.canSpawnGlobally()) {
303
+ const max = this.concurrencyManager.getMaxBackgroundAgents()
304
+ const current = this.concurrencyManager.getGlobalRunningCount()
305
+ throw new Error(
306
+ `Background agent spawn blocked: ${current} agents running, max is ${max}. Wait for existing tasks to complete or increase background_task.maxBackgroundAgents.`
307
+ )
308
+ }
309
+
310
+ const spawnReservation = await this.reserveSubagentSpawn(input.parentSessionID)
311
+
312
+ try {
313
+ // ... existing code ...
314
+
315
+ // After task creation, before queueing:
316
+ this.concurrencyManager.acquireGlobal()
317
+
318
+ // ... rest of existing code ...
319
+ } catch (error) {
320
+ spawnReservation.rollback()
321
+ throw error
322
+ }
323
+ }
324
+ ```
325
+
326
+ ### In `trackTask()` method — add global check:
327
+
328
+ ```typescript
329
+ async trackTask(input: { ... }): Promise<BackgroundTask> {
330
+ const existingTask = this.tasks.get(input.taskId)
331
+ if (existingTask) {
332
+ // ... existing re-registration logic unchanged ...
333
+ return existingTask
334
+ }
335
+
336
+ // Check global limit for new external tasks
337
+ if (!this.concurrencyManager.canSpawnGlobally()) {
338
+ const max = this.concurrencyManager.getMaxBackgroundAgents()
339
+ const current = this.concurrencyManager.getGlobalRunningCount()
340
+ throw new Error(
341
+ `Background agent spawn blocked: ${current} agents running, max is ${max}. Wait for existing tasks to complete or increase background_task.maxBackgroundAgents.`
342
+ )
343
+ }
344
+
345
+ // ... existing task creation ...
346
+ this.concurrencyManager.acquireGlobal()
347
+
348
+ // ... rest unchanged ...
349
+ }
350
+ ```
351
+
352
+ ### In `tryCompleteTask()` — release global slot:
353
+
354
+ ```typescript
355
+ private async tryCompleteTask(task: BackgroundTask, source: string): Promise<boolean> {
356
+ if (task.status !== "running") {
357
+ // ... existing guard ...
358
+ return false
359
+ }
360
+
361
+ task.status = "completed"
362
+ task.completedAt = new Date()
363
+ // ... existing history record ...
364
+
365
+ removeTaskToastTracking(task.id)
366
+
367
+ // Release per-model concurrency
368
+ if (task.concurrencyKey) {
369
+ this.concurrencyManager.release(task.concurrencyKey)
370
+ task.concurrencyKey = undefined
371
+ }
372
+
373
+ // Release global slot
374
+ this.concurrencyManager.releaseGlobal()
375
+
376
+ // ... rest unchanged ...
377
+ }
378
+ ```
379
+
380
+ ### In `cancelTask()` — release global slot:
381
+
382
+ ```typescript
383
+ async cancelTask(taskId: string, options?: { ... }): Promise<boolean> {
384
+ // ... existing code up to concurrency release ...
385
+
386
+ if (task.concurrencyKey) {
387
+ this.concurrencyManager.release(task.concurrencyKey)
388
+ task.concurrencyKey = undefined
389
+ }
390
+
391
+ // Release global slot (only for running tasks, pending never acquired)
392
+ if (task.status !== "pending") {
393
+ this.concurrencyManager.releaseGlobal()
394
+ }
395
+
396
+ // ... rest unchanged ...
397
+ }
398
+ ```
399
+
400
+ ### In `handleEvent()` session.error handler — release global slot:
401
+
402
+ ```typescript
403
+ if (event.type === "session.error") {
404
+ // ... existing error handling ...
405
+
406
+ task.status = "error"
407
+ // ...
408
+
409
+ if (task.concurrencyKey) {
410
+ this.concurrencyManager.release(task.concurrencyKey)
411
+ task.concurrencyKey = undefined
412
+ }
413
+
414
+ // Release global slot
415
+ this.concurrencyManager.releaseGlobal()
416
+
417
+ // ... rest unchanged ...
418
+ }
419
+ ```
420
+
421
+ ### In prompt error handler inside `startTask()` — release global slot:
422
+
423
+ ```typescript
424
+ promptWithModelSuggestionRetry(this.client, { ... }).catch((error) => {
425
+ // ... existing error handling ...
426
+ if (existingTask) {
427
+ existingTask.status = "interrupt"
428
+ // ...
429
+ if (existingTask.concurrencyKey) {
430
+ this.concurrencyManager.release(existingTask.concurrencyKey)
431
+ existingTask.concurrencyKey = undefined
432
+ }
433
+
434
+ // Release global slot
435
+ this.concurrencyManager.releaseGlobal()
436
+
437
+ // ... rest unchanged ...
438
+ }
439
+ })
440
+ ```
441
+
442
+ ---
443
+
444
+ ## Summary of Changes
445
+
446
+ | File | Lines Added | Lines Modified |
447
+ |------|-------------|----------------|
448
+ | `src/config/schema/background-task.ts` | 2 | 0 |
449
+ | `src/config/schema/background-task.test.ts` | ~50 | 0 |
450
+ | `src/features/background-agent/concurrency.ts` | ~25 | 1 (`clear()`) |
451
+ | `src/features/background-agent/concurrency.test.ts` | ~70 | 0 |
452
+ | `src/features/background-agent/manager.ts` | ~20 | 0 |
453
+
454
+ Total: ~167 lines added, 1 line modified across 5 files.
@@ -0,0 +1,136 @@
1
+ # Execution Plan: `max_background_agents` Config Option
2
+
3
+ ## Phase 0: Setup — Branch + Worktree
4
+
5
+ 1. **Create branch** from `dev`:
6
+ ```bash
7
+ git checkout dev && git pull origin dev
8
+ git checkout -b feat/max-background-agents
9
+ ```
10
+
11
+ 2. **Create worktree** in sibling directory:
12
+ ```bash
13
+ mkdir -p ../omo-wt
14
+ git worktree add ../omo-wt/feat-max-background-agents feat/max-background-agents
15
+ ```
16
+
17
+ 3. **All subsequent work** happens in `../omo-wt/feat-max-background-agents/`, never in the main worktree.
18
+
19
+ ---
20
+
21
+ ## Phase 1: Implement — Atomic Commits
22
+
23
+ ### Commit 1: Add `max_background_agents` to config schema
24
+
25
+ **Files changed:**
26
+ - `src/config/schema/background-task.ts` — Add `maxBackgroundAgents` field to `BackgroundTaskConfigSchema`
27
+ - `src/config/schema/background-task.test.ts` — Add validation tests for the new field
28
+
29
+ **What:**
30
+ - Add `maxBackgroundAgents: z.number().int().min(1).optional()` to `BackgroundTaskConfigSchema`
31
+ - Default value handled at runtime (5), not in schema (all schema fields are optional per convention)
32
+ - Add given/when/then tests: valid value, below minimum, not provided, non-number
33
+
34
+ ### Commit 2: Enforce limit in BackgroundManager + ConcurrencyManager
35
+
36
+ **Files changed:**
37
+ - `src/features/background-agent/concurrency.ts` — Add global agent count tracking + `getGlobalRunningCount()` + `canSpawnGlobally()`
38
+ - `src/features/background-agent/concurrency.test.ts` — Tests for global limit enforcement
39
+ - `src/features/background-agent/manager.ts` — Check global limit before `launch()` and `trackTask()`
40
+
41
+ **What:**
42
+ - `ConcurrencyManager` already manages per-model concurrency. Add a separate global counter:
43
+ - `private globalRunningCount: number = 0`
44
+ - `private maxBackgroundAgents: number` (from config, default 5)
45
+ - `acquireGlobal()` / `releaseGlobal()` methods
46
+ - `getGlobalRunningCount()` for observability
47
+ - `BackgroundManager.launch()` checks `concurrencyManager.canSpawnGlobally()` before creating task
48
+ - `BackgroundManager.trackTask()` also checks global limit
49
+ - On task completion/cancellation/error, call `releaseGlobal()`
50
+ - Throw descriptive error when limit hit: `"Background agent spawn blocked: ${current} agents running, max is ${max}. Wait for existing tasks to complete or increase background_task.maxBackgroundAgents."`
51
+
52
+ ### Local Validation
53
+
54
+ ```bash
55
+ bun run typecheck
56
+ bun test src/config/schema/background-task.test.ts
57
+ bun test src/features/background-agent/concurrency.test.ts
58
+ bun run build
59
+ ```
60
+
61
+ ---
62
+
63
+ ## Phase 2: PR Creation
64
+
65
+ 1. **Push branch:**
66
+ ```bash
67
+ git push -u origin feat/max-background-agents
68
+ ```
69
+
70
+ 2. **Create PR** targeting `dev`:
71
+ ```bash
72
+ gh pr create \
73
+ --base dev \
74
+ --title "feat: add max_background_agents config to limit concurrent background agents" \
75
+ --body-file /tmp/pull-request-max-background-agents-$(date +%s).md
76
+ ```
77
+
78
+ ---
79
+
80
+ ## Phase 3: Verify Loop
81
+
82
+ ### Gate A: CI
83
+ - Wait for `ci.yml` workflow to complete
84
+ - Check: `gh pr checks <PR_NUMBER> --watch`
85
+ - If fails: read logs, fix, push, re-check
86
+
87
+ ### Gate B: review-work (5 agents)
88
+ - Run `/review-work` skill which launches 5 parallel background sub-agents:
89
+ 1. Oracle — goal/constraint verification
90
+ 2. Oracle — code quality
91
+ 3. Oracle — security
92
+ 4. Hephaestus — hands-on QA execution
93
+ 5. Hephaestus — context mining from GitHub/git
94
+ - All 5 must pass. If any fails, fix and re-push.
95
+
96
+ ### Gate C: Cubic (cubic-dev-ai[bot])
97
+ - Wait for Cubic bot review on PR
98
+ - Must say "No issues found"
99
+ - If issues found: address feedback, push, re-check
100
+
101
+ ### Loop
102
+ ```
103
+ while (!allGatesPass) {
104
+ if (CI fails) → fix → push → continue
105
+ if (review-work fails) → fix → push → continue
106
+ if (Cubic has issues) → fix → push → continue
107
+ }
108
+ ```
109
+
110
+ ---
111
+
112
+ ## Phase 4: Merge + Cleanup
113
+
114
+ 1. **Squash merge:**
115
+ ```bash
116
+ gh pr merge <PR_NUMBER> --squash --delete-branch
117
+ ```
118
+
119
+ 2. **Remove worktree:**
120
+ ```bash
121
+ git worktree remove ../omo-wt/feat-max-background-agents
122
+ ```
123
+
124
+ ---
125
+
126
+ ## File Impact Summary
127
+
128
+ | File | Change Type |
129
+ |------|-------------|
130
+ | `src/config/schema/background-task.ts` | Modified — add schema field |
131
+ | `src/config/schema/background-task.test.ts` | Modified — add validation tests |
132
+ | `src/features/background-agent/concurrency.ts` | Modified — add global limit tracking |
133
+ | `src/features/background-agent/concurrency.test.ts` | Modified — add global limit tests |
134
+ | `src/features/background-agent/manager.ts` | Modified — enforce global limit in launch/trackTask |
135
+
136
+ 5 files changed across 2 atomic commits. No new files created (follows existing patterns).
@@ -0,0 +1,47 @@
1
+ # PR Description
2
+
3
+ **Title:** `feat: add max_background_agents config to limit concurrent background agents`
4
+
5
+ **Base:** `dev`
6
+
7
+ ---
8
+
9
+ ## Summary
10
+
11
+ - Add `maxBackgroundAgents` field to `BackgroundTaskConfigSchema` (default: 5, min: 1) to cap total simultaneous background agents across all models/providers
12
+ - Enforce the global limit in `BackgroundManager.launch()` and `trackTask()` with descriptive error messages when the limit is hit
13
+ - Release global slots on task completion, cancellation, error, and interrupt to prevent slot leaks
14
+
15
+ ## Motivation
16
+
17
+ The existing concurrency system in `ConcurrencyManager` limits agents **per model/provider** (e.g., 5 concurrent `anthropic/claude-opus-4-6` tasks). However, there is no **global** cap across all models. A user running tasks across multiple providers could spawn an unbounded number of background agents, exhausting system resources.
18
+
19
+ `max_background_agents` provides a single knob to limit total concurrent background agents regardless of which model they use.
20
+
21
+ ## Config Usage
22
+
23
+ ```jsonc
24
+ // .opencode/oh-my-opencode.jsonc
25
+ {
26
+ "background_task": {
27
+ "maxBackgroundAgents": 10 // default: 5, min: 1
28
+ }
29
+ }
30
+ ```
31
+
32
+ ## Changes
33
+
34
+ | File | What |
35
+ |------|------|
36
+ | `src/config/schema/background-task.ts` | Add `maxBackgroundAgents` schema field |
37
+ | `src/config/schema/background-task.test.ts` | Validation tests (valid, boundary, invalid) |
38
+ | `src/features/background-agent/concurrency.ts` | Global counter + `canSpawnGlobally()` / `acquireGlobal()` / `releaseGlobal()` |
39
+ | `src/features/background-agent/concurrency.test.ts` | Global limit unit tests |
40
+ | `src/features/background-agent/manager.ts` | Enforce global limit in `launch()`, `trackTask()`; release in completion/cancel/error paths |
41
+
42
+ ## Testing
43
+
44
+ - `bun test src/config/schema/background-task.test.ts` — schema validation
45
+ - `bun test src/features/background-agent/concurrency.test.ts` — global limit enforcement
46
+ - `bun run typecheck` — clean
47
+ - `bun run build` — clean