@nbardy/oompa 0.2.0 → 0.3.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.
package/README.md CHANGED
@@ -85,7 +85,7 @@ This repo has a fleshed out version of the idea. The oompa loompas are organized
85
85
  "review_model": "codex:codex-5.2",
86
86
  "workers": [
87
87
  {"model": "claude:opus-4.5", "prompt": ["config/prompts/planner.md"], "iterations": 5, "count": 1},
88
- {"model": "codex:codex-5.2-mini", "prompt": ["config/prompts/executor.md"], "iterations": 10, "count": 3}
88
+ {"model": "codex:codex-5.2-mini", "prompt": ["config/prompts/executor.md"], "iterations": 10, "count": 3, "can_plan": false}
89
89
  ]
90
90
  }
91
91
  ```
@@ -103,6 +103,7 @@ This spawns:
103
103
  | `prompt` | no | String or array of paths — concatenated into one prompt |
104
104
  | `iterations` | no | Max iterations per worker (default: 10) |
105
105
  | `count` | no | Number of workers with this config (default: 1) |
106
+ | `can_plan` | no | If `false`, worker waits for tasks before starting (default: `true`) |
106
107
 
107
108
  #### Composable prompts
108
109
 
@@ -300,7 +300,7 @@
300
300
  (println "{")
301
301
  (println " \"review_model\": \"codex:codex-5.2\",")
302
302
  (println " \"workers\": [")
303
- (println " {\"model\": \"codex:codex-5.2-mini\", \"prompt\": \"prompts/executor.md\", \"iterations\": 10, \"count\": 3},")
303
+ (println " {\"model\": \"codex:codex-5.2-mini\", \"prompt\": \"prompts/executor.md\", \"iterations\": 10, \"count\": 3, \"can_plan\": false},")
304
304
  (println " {\"model\": \"claude:opus-4.5\", \"prompt\": [\"prompts/base.md\", \"prompts/planner.md\"], \"count\": 1}")
305
305
  (println " ]")
306
306
  (println "}")
@@ -328,6 +328,7 @@
328
328
  :model model
329
329
  :iterations (or (:iterations wc) 10)
330
330
  :prompts (:prompt wc)
331
+ :can-plan (:can_plan wc)
331
332
  :review-harness (:harness review-model)
332
333
  :review-model (:model review-model)})))
333
334
  expanded-workers)]
@@ -105,8 +105,9 @@
105
105
 
106
106
  (defn create-worker
107
107
  "Create a worker config.
108
- :prompts is a string or vector of strings — paths to prompt files."
109
- [{:keys [id swarm-id harness model iterations prompts review-harness review-model]}]
108
+ :prompts is a string or vector of strings — paths to prompt files.
109
+ :can-plan when false, worker waits for tasks before starting (backpressure)."
110
+ [{:keys [id swarm-id harness model iterations prompts can-plan review-harness review-model]}]
110
111
  {:id id
111
112
  :swarm-id swarm-id
112
113
  :harness (or harness :codex)
@@ -116,6 +117,7 @@
116
117
  (vector? prompts) prompts
117
118
  (string? prompts) [prompts]
118
119
  :else [])
120
+ :can-plan (if (some? can-plan) can-plan true)
119
121
  :review-harness review-harness
120
122
  :review-model review-model
121
123
  :completed 0
@@ -187,6 +189,7 @@
187
189
  (process/sh cmd {:dir abs-worktree :in tagged-prompt :out :string :err :string})
188
190
  (process/sh cmd {:dir abs-worktree :out :string :err :string}))
189
191
  (catch Exception e
192
+ (println (format "[%s] Agent exception: %s" id (.getMessage e)))
190
193
  {:exit -1 :out "" :err (.getMessage e)}))]
191
194
 
192
195
  (when (= harness :codex)
@@ -280,18 +283,18 @@
280
283
 
281
284
  (defn- merge-to-main!
282
285
  "Merge worktree changes to main branch"
283
- [wt-path wt-id worker-id]
286
+ [wt-path wt-id worker-id project-root]
284
287
  (println (format "[%s] Merging changes to main" worker-id))
285
288
  (let [;; Commit in worktree if needed
286
289
  _ (process/sh ["git" "add" "-A"] {:dir wt-path})
287
290
  _ (process/sh ["git" "commit" "-m" (str "Work from " wt-id) "--allow-empty"]
288
291
  {:dir wt-path})
289
- ;; Checkout main and merge
292
+ ;; Checkout main and merge (in project root, not worktree)
290
293
  checkout-result (process/sh ["git" "checkout" "main"]
291
- {:out :string :err :string})
294
+ {:dir project-root :out :string :err :string})
292
295
  merge-result (when (zero? (:exit checkout-result))
293
296
  (process/sh ["git" "merge" wt-id "--no-edit"]
294
- {:out :string :err :string}))]
297
+ {:dir project-root :out :string :err :string}))]
295
298
  (and (zero? (:exit checkout-result))
296
299
  (zero? (:exit merge-result)))))
297
300
 
@@ -341,15 +344,17 @@
341
344
  Returns {:status :done|:continue|:error, :task task-or-nil}"
342
345
  [worker iteration total-iterations]
343
346
  (let [worker-id (:id worker)
344
- wt-id (format ".w%s-i%d" worker-id iteration)
347
+ project-root (System/getProperty "user.dir")
348
+ wt-dir (format ".w%s-i%d" worker-id iteration)
349
+ wt-branch (format "oompa/%s-i%d" worker-id iteration)
345
350
 
346
351
  ;; Create worktree
347
352
  _ (println (format "[%s] Starting iteration %d/%d" worker-id iteration total-iterations))
348
- wt-path (str (System/getProperty "user.dir") "/" wt-id)]
353
+ wt-path (str project-root "/" wt-dir)]
349
354
 
350
355
  (try
351
- ;; Setup worktree
352
- (process/sh ["git" "worktree" "add" wt-id "-b" wt-id])
356
+ ;; Setup worktree (in project root) — dir starts with . but branch name must be valid
357
+ (process/sh ["git" "worktree" "add" wt-dir "-b" wt-branch] {:dir project-root})
353
358
 
354
359
  ;; Build context
355
360
  (let [context (build-context)
@@ -367,7 +372,7 @@
367
372
  ;; Agent errored
368
373
  (not (zero? exit))
369
374
  (do
370
- (println (format "[%s] Agent error (exit %d)" worker-id exit))
375
+ (println (format "[%s] Agent error (exit %d): %s" worker-id exit (subs (or output "") 0 (min 200 (count (or output ""))))))
371
376
  {:status :error :exit exit})
372
377
 
373
378
  ;; Success - run review loop before merge
@@ -375,7 +380,7 @@
375
380
  (let [{:keys [approved?]} (review-loop! worker wt-path worker-id)]
376
381
  (if approved?
377
382
  (do
378
- (merge-to-main! wt-path wt-id worker-id)
383
+ (merge-to-main! wt-path wt-branch worker-id project-root)
379
384
  (println (format "[%s] Iteration %d/%d complete" worker-id iteration total-iterations))
380
385
  {:status :continue})
381
386
  (do
@@ -383,13 +388,33 @@
383
388
  {:status :continue})))))
384
389
 
385
390
  (finally
386
- ;; Cleanup worktree
387
- (process/sh ["git" "worktree" "remove" wt-id "--force"])))))
391
+ ;; Cleanup worktree (in project root)
392
+ (process/sh ["git" "worktree" "remove" wt-dir "--force"] {:dir project-root})))))
388
393
 
389
394
  ;; =============================================================================
390
395
  ;; Worker Loop
391
396
  ;; =============================================================================
392
397
 
398
+ (def ^:private max-wait-for-tasks 60)
399
+ (def ^:private wait-poll-interval 5)
400
+
401
+ (defn- wait-for-tasks!
402
+ "Wait up to 60s for pending/current tasks to appear. Used for backpressure
403
+ on workers that can't create their own tasks (can_plan: false)."
404
+ [worker-id]
405
+ (loop [waited 0]
406
+ (cond
407
+ (pos? (tasks/pending-count)) true
408
+ (pos? (tasks/current-count)) true
409
+ (>= waited max-wait-for-tasks)
410
+ (do (println (format "[%s] No tasks after %ds, proceeding anyway" worker-id waited))
411
+ false)
412
+ :else
413
+ (do (when (zero? (mod waited 15))
414
+ (println (format "[%s] Waiting for tasks... (%ds)" worker-id waited)))
415
+ (Thread/sleep (* wait-poll-interval 1000))
416
+ (recur (+ waited wait-poll-interval))))))
417
+
393
418
  (defn run-worker!
394
419
  "Run worker loop until done or iterations exhausted.
395
420
 
@@ -403,6 +428,10 @@
403
428
  (or (:model worker) "default")
404
429
  iterations))
405
430
 
431
+ ;; Backpressure: workers that can't create tasks wait for tasks to exist
432
+ (when-not (:can-plan worker)
433
+ (wait-for-tasks! id))
434
+
406
435
  (loop [iter 1
407
436
  completed 0]
408
437
  (if (> iter iterations)
@@ -6,5 +6,6 @@ You are a planner. You read the spec, explore the codebase, and create well-scop
6
6
  - Set :difficulty on each task (:easy, :medium, :hard) so the right worker picks it up.
7
7
  - Refine or split tasks that are too large or vague.
8
8
  - Check ../tasks/complete/ before creating duplicates.
9
- - You may also execute tasks if the queue is full and you see something quick to do.
9
+ - Do NOT claim or complete tasks. Your job is to create them for other workers.
10
+ - Do NOT write application code. Only write task .edn files.
10
11
  - Spend time thinking. Good task decomposition is the highest-leverage thing you can do.
@@ -12,7 +12,8 @@
12
12
  "model": "codex:codex-5.2-mini",
13
13
  "prompt": ["config/prompts/executor.md"],
14
14
  "iterations": 10,
15
- "count": 3
15
+ "count": 3,
16
+ "can_plan": false
16
17
  }
17
18
  ]
18
19
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nbardy/oompa",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Git-worktree multi-agent swarm orchestrator for Codex and Claude",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",