@nbardy/oompa 0.1.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
@@ -79,25 +79,51 @@ This repo has a fleshed out version of the idea. The oompa loompas are organized
79
79
 
80
80
  ### Configuration
81
81
 
82
- **oompa.json**:
82
+ **oompa.json** — the only file you need:
83
83
  ```json
84
84
  {
85
85
  "review_model": "codex:codex-5.2",
86
86
  "workers": [
87
- {"model": "claude:opus-4.5", "iterations": 5, "count": 1, "prompt": "config/prompts/planner.md"},
88
- {"model": "codex:codex-5.2-mini", "iterations": 10, "count": 3, "prompt": "config/prompts/executor.md"}
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, "can_plan": false}
89
89
  ]
90
90
  }
91
91
  ```
92
92
 
93
93
  This spawns:
94
- - **1 planner** (opus) — creates tasks, doesn't write code
94
+ - **1 planner** (opus) — reads spec, explores codebase, creates/refines tasks
95
95
  - **3 executors** (mini) — claims and executes tasks fast
96
96
  - **Reviews** done by codex-5.2 before any merge
97
97
 
98
+ #### Worker fields
99
+
100
+ | Field | Required | Description |
101
+ |-------|----------|-------------|
102
+ | `model` | yes | `harness:model` (e.g. `claude:opus-4.5`, `codex:codex-5.2-mini`) |
103
+ | `prompt` | no | String or array of paths — concatenated into one prompt |
104
+ | `iterations` | no | Max iterations per worker (default: 10) |
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`) |
107
+
108
+ #### Composable prompts
109
+
110
+ `prompt` accepts a string or an array. Arrays get concatenated, so you can reuse a shared base across workers:
111
+
112
+ ```json
113
+ {
114
+ "workers": [
115
+ {"model": "claude:opus-4.5", "prompt": ["prompts/base.md", "prompts/architect.md"], "count": 1},
116
+ {"model": "codex:codex-5.2-mini", "prompt": ["prompts/base.md", "prompts/frontend.md"], "count": 2},
117
+ {"model": "codex:codex-5.2-mini", "prompt": ["prompts/base.md", "prompts/backend.md"], "count": 2}
118
+ ]
119
+ }
120
+ ```
121
+
122
+ Every worker automatically gets task management instructions injected above your prompts. Your prompts just say *what* the worker should do — the framework handles *how* tasks work.
123
+
98
124
  ### Task System
99
125
 
100
- Workers self-organize via filesystem:
126
+ Workers self-organize via the filesystem. Tasks live at the project root and are shared across all worktrees:
101
127
 
102
128
  ```
103
129
  tasks/
@@ -106,20 +132,31 @@ tasks/
106
132
  └── complete/*.edn # done
107
133
  ```
108
134
 
109
- Workers can:
110
- - **Claim tasks**: `mv pending/task.edn current/`
111
- - **Complete tasks**: `mv current/task.edn complete/`
112
- - **Create tasks**: write new `.edn` to `pending/`
135
+ From inside a worktree, workers reach tasks via `../tasks/`:
136
+ - **See tasks**: `ls ../tasks/pending/`
137
+ - **Claim**: `mv ../tasks/pending/task.edn ../tasks/current/`
138
+ - **Complete**: `mv ../tasks/current/task.edn ../tasks/complete/`
139
+ - **Create**: write new `.edn` to `../tasks/pending/`
140
+
141
+ Task file format:
142
+ ```edn
143
+ {:id "task-001"
144
+ :summary "Add user authentication"
145
+ :description "Implement JWT-based auth for the API"
146
+ :difficulty :medium
147
+ :files ["src/auth.py" "tests/test_auth.py"]
148
+ :acceptance ["Login endpoint returns token" "Tests pass"]}
149
+ ```
113
150
 
114
- ### Prompts
151
+ ### Bundled Prompts
115
152
 
116
- Three built-in worker types:
153
+ Three prompt files ship with oompa that you can use in your `prompt` arrays:
117
154
 
118
- | Prompt | Role | Creates Tasks? | Executes Tasks? |
119
- |--------|------|----------------|-----------------|
120
- | `worker.md` | Hybrid | | |
121
- | `planner.md` | Planner | | |
122
- | `executor.md` | Executor | | |
155
+ | Prompt | Creates Tasks? | Executes Tasks? | Best For |
156
+ |--------|----------------|-----------------|----------|
157
+ | `config/prompts/worker.md` (default) | yes | yes | General purpose |
158
+ | `config/prompts/planner.md` | yes | sometimes | Big models — task design |
159
+ | `config/prompts/executor.md` | no | yes | Small/fast models — heads-down work |
123
160
 
124
161
  ---
125
162
 
@@ -300,10 +300,12 @@
300
300
  (println "{")
301
301
  (println " \"review_model\": \"codex:codex-5.2\",")
302
302
  (println " \"workers\": [")
303
- (println " {\"model\": \"codex:codex-5.2-mini\", \"iterations\": 10, \"count\": 3},")
304
- (println " {\"model\": \"codex:codex-5.2\", \"iterations\": 5, \"count\": 1, \"prompt\": \"prompts/planner.md\"}")
303
+ (println " {\"model\": \"codex:codex-5.2-mini\", \"prompt\": \"prompts/executor.md\", \"iterations\": 10, \"count\": 3, \"can_plan\": false},")
304
+ (println " {\"model\": \"claude:opus-4.5\", \"prompt\": [\"prompts/base.md\", \"prompts/planner.md\"], \"count\": 1}")
305
305
  (println " ]")
306
306
  (println "}")
307
+ (println)
308
+ (println "prompt: string or array of paths — concatenated into one prompt.")
307
309
  (System/exit 1))
308
310
  (let [config (json/parse-string (slurp f) true)
309
311
  review-model (some-> (:review_model config) parse-model-string)
@@ -325,7 +327,8 @@
325
327
  :harness harness
326
328
  :model model
327
329
  :iterations (or (:iterations wc) 10)
328
- :custom-prompt (:prompt wc)
330
+ :prompts (:prompt wc)
331
+ :can-plan (:can_plan wc)
329
332
  :review-harness (:harness review-model)
330
333
  :review-model (:model review-model)})))
331
334
  expanded-workers)]
@@ -93,15 +93,31 @@
93
93
  ;; Worker State
94
94
  ;; =============================================================================
95
95
 
96
+ (def ^:private package-root
97
+ "Root of the oompa package — set by bin/oompa.js, falls back to cwd."
98
+ (or (System/getenv "OOMPA_PACKAGE_ROOT") "."))
99
+
100
+ (defn- load-prompt
101
+ "Load a prompt file. Tries path as-is first, then from package root."
102
+ [path]
103
+ (or (agent/load-custom-prompt path)
104
+ (agent/load-custom-prompt (str package-root "/" path))))
105
+
96
106
  (defn create-worker
97
- "Create a worker config"
98
- [{:keys [id swarm-id harness model iterations custom-prompt review-harness review-model]}]
107
+ "Create a worker config.
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]}]
99
111
  {:id id
100
112
  :swarm-id swarm-id
101
113
  :harness (or harness :codex)
102
114
  :model model
103
115
  :iterations (or iterations 10)
104
- :custom-prompt custom-prompt
116
+ :prompts (cond
117
+ (vector? prompts) prompts
118
+ (string? prompts) [prompts]
119
+ :else [])
120
+ :can-plan (if (some? can-plan) can-plan true)
105
121
  :review-harness review-harness
106
122
  :review-model review-model
107
123
  :completed 0
@@ -128,25 +144,36 @@
128
144
 
129
145
  (defn- run-agent!
130
146
  "Run agent with prompt, return {:output string, :done? bool, :exit int}"
131
- [{:keys [id swarm-id harness model custom-prompt]} worktree-path context]
132
- (let [;; Load prompt (check config/prompts/ as default)
133
- prompt-content (or (agent/load-custom-prompt custom-prompt)
134
- (agent/load-custom-prompt "config/prompts/worker.md")
135
- "Goal: Match spec.md\nProcess: Create/claim tasks in tasks/{pending,current,complete}/*.edn\nMethod: Isolate changes to your worktree, commit and merge when complete")
136
-
137
- ;; Inject worktree and context
138
- full-prompt (str "Worktree: " worktree-path "\n"
139
- "Task Status: " (:task_status context) "\n\n"
140
- prompt-content)
147
+ [{:keys [id swarm-id harness model prompts]} worktree-path context]
148
+ (let [;; 1. Task header (always, from package)
149
+ task-header (or (load-prompt "config/prompts/_task_header.md") "")
150
+
151
+ ;; 2. Load and concatenate all user prompts (string or list)
152
+ user-prompts (if (seq prompts)
153
+ (->> prompts
154
+ (map load-prompt)
155
+ (remove nil?)
156
+ (str/join "\n\n"))
157
+ (or (load-prompt "config/prompts/worker.md")
158
+ "You are a worker. Claim tasks, execute them, complete them."))
159
+
160
+ ;; Assemble: task header + status + user prompts
161
+ full-prompt (str task-header "\n"
162
+ "Task Status: " (:task_status context) "\n"
163
+ "Pending: " (:pending_tasks context) "\n\n"
164
+ user-prompts)
141
165
  session-id (str/lower-case (str (java.util.UUID/randomUUID)))
142
166
  swarm-id* (or swarm-id "unknown")
143
167
  tagged-prompt (str "[oompa:" swarm-id* ":" id "] " full-prompt)
144
168
  abs-worktree (.getAbsolutePath (io/file worktree-path))
145
169
 
146
- ;; Build command
170
+ ;; Build command — both harnesses run with cwd=worktree, no sandbox
171
+ ;; so agents can `..` to reach project root for task management
147
172
  cmd (case harness
148
- :codex (cond-> ["codex" "exec" "--full-auto" "--skip-git-repo-check"
149
- "-C" worktree-path "--sandbox" "workspace-write"]
173
+ :codex (cond-> ["codex" "exec"
174
+ "--dangerously-bypass-approvals-and-sandbox"
175
+ "--skip-git-repo-check"
176
+ "-C" abs-worktree]
150
177
  model (into ["--model" model])
151
178
  true (conj "--" full-prompt))
152
179
  :claude (cond-> ["claude" "-p" "--dangerously-skip-permissions"
@@ -156,14 +183,13 @@
156
183
  _ (when (= harness :codex)
157
184
  (persist-message! id session-id abs-worktree "user" tagged-prompt))
158
185
 
159
- ;; Run agent
186
+ ;; Run agent — both run with cwd=worktree
160
187
  result (try
161
188
  (if (= harness :claude)
162
- ;; Claude reads from stdin
163
- (process/sh cmd {:in tagged-prompt :out :string :err :string})
164
- ;; Codex takes prompt as arg
165
- (process/sh cmd {:out :string :err :string}))
189
+ (process/sh cmd {:dir abs-worktree :in tagged-prompt :out :string :err :string})
190
+ (process/sh cmd {:dir abs-worktree :out :string :err :string}))
166
191
  (catch Exception e
192
+ (println (format "[%s] Agent exception: %s" id (.getMessage e)))
167
193
  {:exit -1 :out "" :err (.getMessage e)}))]
168
194
 
169
195
  (when (= harness :codex)
@@ -194,20 +220,24 @@
194
220
  "- NEEDS_CHANGES with bullet points of issues\n"
195
221
  "- REJECTED if fundamentally wrong")
196
222
 
197
- ;; Build command
223
+ abs-wt (.getAbsolutePath (io/file worktree-path))
224
+
225
+ ;; Build command — cwd=worktree, no sandbox
198
226
  cmd (case review-harness
199
- :codex (cond-> ["codex" "exec" "--full-auto" "--skip-git-repo-check"
200
- "-C" worktree-path "--sandbox" "workspace-write"]
227
+ :codex (cond-> ["codex" "exec"
228
+ "--dangerously-bypass-approvals-and-sandbox"
229
+ "--skip-git-repo-check"
230
+ "-C" abs-wt]
201
231
  review-model (into ["--model" review-model])
202
232
  true (conj "--" review-prompt))
203
233
  :claude (cond-> ["claude" "-p" "--dangerously-skip-permissions"]
204
234
  review-model (into ["--model" review-model])))
205
235
 
206
- ;; Run reviewer
236
+ ;; Run reviewer — cwd=worktree
207
237
  result (try
208
238
  (if (= review-harness :claude)
209
- (process/sh cmd {:in review-prompt :out :string :err :string})
210
- (process/sh cmd {:out :string :err :string}))
239
+ (process/sh cmd {:dir abs-wt :in review-prompt :out :string :err :string})
240
+ (process/sh cmd {:dir abs-wt :out :string :err :string}))
211
241
  (catch Exception e
212
242
  {:exit -1 :out "" :err (.getMessage e)}))
213
243
 
@@ -229,9 +259,13 @@
229
259
  feedback "\n\n"
230
260
  "Please fix these issues in the worktree.")
231
261
 
262
+ abs-wt (.getAbsolutePath (io/file worktree-path))
263
+
232
264
  cmd (case harness
233
- :codex (cond-> ["codex" "exec" "--full-auto" "--skip-git-repo-check"
234
- "-C" worktree-path "--sandbox" "workspace-write"]
265
+ :codex (cond-> ["codex" "exec"
266
+ "--dangerously-bypass-approvals-and-sandbox"
267
+ "--skip-git-repo-check"
268
+ "-C" abs-wt]
235
269
  model (into ["--model" model])
236
270
  true (conj "--" fix-prompt))
237
271
  :claude (cond-> ["claude" "-p" "--dangerously-skip-permissions"]
@@ -239,8 +273,8 @@
239
273
 
240
274
  result (try
241
275
  (if (= harness :claude)
242
- (process/sh cmd {:in fix-prompt :out :string :err :string})
243
- (process/sh cmd {:out :string :err :string}))
276
+ (process/sh cmd {:dir abs-wt :in fix-prompt :out :string :err :string})
277
+ (process/sh cmd {:dir abs-wt :out :string :err :string}))
244
278
  (catch Exception e
245
279
  {:exit -1 :out "" :err (.getMessage e)}))]
246
280
 
@@ -249,18 +283,18 @@
249
283
 
250
284
  (defn- merge-to-main!
251
285
  "Merge worktree changes to main branch"
252
- [wt-path wt-id worker-id]
286
+ [wt-path wt-id worker-id project-root]
253
287
  (println (format "[%s] Merging changes to main" worker-id))
254
288
  (let [;; Commit in worktree if needed
255
289
  _ (process/sh ["git" "add" "-A"] {:dir wt-path})
256
290
  _ (process/sh ["git" "commit" "-m" (str "Work from " wt-id) "--allow-empty"]
257
291
  {:dir wt-path})
258
- ;; Checkout main and merge
292
+ ;; Checkout main and merge (in project root, not worktree)
259
293
  checkout-result (process/sh ["git" "checkout" "main"]
260
- {:out :string :err :string})
294
+ {:dir project-root :out :string :err :string})
261
295
  merge-result (when (zero? (:exit checkout-result))
262
296
  (process/sh ["git" "merge" wt-id "--no-edit"]
263
- {:out :string :err :string}))]
297
+ {:dir project-root :out :string :err :string}))]
264
298
  (and (zero? (:exit checkout-result))
265
299
  (zero? (:exit merge-result)))))
266
300
 
@@ -310,15 +344,17 @@
310
344
  Returns {:status :done|:continue|:error, :task task-or-nil}"
311
345
  [worker iteration total-iterations]
312
346
  (let [worker-id (:id worker)
313
- 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)
314
350
 
315
351
  ;; Create worktree
316
352
  _ (println (format "[%s] Starting iteration %d/%d" worker-id iteration total-iterations))
317
- wt-path (str (System/getProperty "user.dir") "/" wt-id)]
353
+ wt-path (str project-root "/" wt-dir)]
318
354
 
319
355
  (try
320
- ;; Setup worktree
321
- (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})
322
358
 
323
359
  ;; Build context
324
360
  (let [context (build-context)
@@ -336,7 +372,7 @@
336
372
  ;; Agent errored
337
373
  (not (zero? exit))
338
374
  (do
339
- (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 ""))))))
340
376
  {:status :error :exit exit})
341
377
 
342
378
  ;; Success - run review loop before merge
@@ -344,7 +380,7 @@
344
380
  (let [{:keys [approved?]} (review-loop! worker wt-path worker-id)]
345
381
  (if approved?
346
382
  (do
347
- (merge-to-main! wt-path wt-id worker-id)
383
+ (merge-to-main! wt-path wt-branch worker-id project-root)
348
384
  (println (format "[%s] Iteration %d/%d complete" worker-id iteration total-iterations))
349
385
  {:status :continue})
350
386
  (do
@@ -352,13 +388,33 @@
352
388
  {:status :continue})))))
353
389
 
354
390
  (finally
355
- ;; Cleanup worktree
356
- (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})))))
357
393
 
358
394
  ;; =============================================================================
359
395
  ;; Worker Loop
360
396
  ;; =============================================================================
361
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
+
362
418
  (defn run-worker!
363
419
  "Run worker loop until done or iterations exhausted.
364
420
 
@@ -372,6 +428,10 @@
372
428
  (or (:model worker) "default")
373
429
  iterations))
374
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
+
375
435
  (loop [iter 1
376
436
  completed 0]
377
437
  (if (> iter iterations)
package/bin/oompa.js CHANGED
@@ -18,7 +18,7 @@ if (!fs.existsSync(swarmScript) || !fs.existsSync(classpath)) {
18
18
  const result = spawnSync("bb", ["--classpath", classpath, swarmScript, ...argv], {
19
19
  stdio: "inherit",
20
20
  cwd: process.cwd(),
21
- env: process.env
21
+ env: { ...process.env, OOMPA_PACKAGE_ROOT: packageRoot }
22
22
  });
23
23
 
24
24
  if (result.error) {
@@ -0,0 +1,46 @@
1
+ ## Task Management (auto-injected by oompa)
2
+
3
+ You are working in a git worktree. Your code changes go in `.` (current directory).
4
+ Tasks live in the project root at `../tasks/`. You can reach them from your worktree.
5
+
6
+ ### See available tasks
7
+
8
+ ```bash
9
+ ls ../tasks/pending/
10
+ cat ../tasks/pending/*.edn
11
+ ```
12
+
13
+ ### Claim a task (mark as in-progress)
14
+
15
+ ```bash
16
+ mv ../tasks/pending/<task-file>.edn ../tasks/current/<task-file>.edn
17
+ ```
18
+
19
+ ### Complete a task
20
+
21
+ ```bash
22
+ mv ../tasks/current/<task-file>.edn ../tasks/complete/<task-file>.edn
23
+ ```
24
+
25
+ ### Create a new task
26
+
27
+ ```bash
28
+ cat > ../tasks/pending/task-NNN.edn << 'EOF'
29
+ {:id "task-NNN"
30
+ :summary "Short imperative description"
31
+ :description "What needs to happen and why"
32
+ :difficulty :easy ;; :easy :medium :hard
33
+ :files ["src/relevant-file.py"]
34
+ :acceptance ["Specific condition that means done"]}
35
+ EOF
36
+ ```
37
+
38
+ ### Rules
39
+
40
+ - Before starting work: read the project spec and all tasks to understand scope.
41
+ - First action: claim your task by moving it to `../tasks/current/`.
42
+ - If the `mv` fails (another worker claimed it first), pick a different task.
43
+ - One task per commit (or a small, tightly-related set with overlapping files).
44
+ - If tasks are missing or underspecified: stop and write tasks before coding.
45
+ - If work emerges during execution: create new tasks in `../tasks/pending/`.
46
+ - When all tasks are complete and the spec is satisfied, output: __DONE__
@@ -1,32 +1,7 @@
1
- Goal: Execute tasks from tasks/pending/
2
- Process: Claim task (mv pending/ → current/), execute, complete (mv current/ → complete/)
3
- Method: Isolate changes to your worktree, commit and merge when complete
1
+ You are an executor. You claim tasks and complete them. Nothing else.
4
2
 
5
- ## Your Role
6
-
7
- You are an executor. You:
8
- - Claim and execute tasks
9
- - Do NOT create new tasks
10
- - Do NOT plan or design
11
- - Just execute what's assigned
12
-
13
- ## Workflow
14
-
15
- 1. Pick a task from tasks/pending/
16
- 2. Move it to tasks/current/
17
- 3. Execute the task in your worktree
18
- 4. Commit your changes
19
- 5. Move task to tasks/complete/
20
- 6. Merge your worktree to main
21
-
22
- ## Guidelines
23
-
24
- - Focus on one task at a time
25
- - Follow the task description exactly
26
- - If a task is unclear, skip it (leave in pending/)
27
- - Keep changes minimal and focused
28
-
29
- ## Exit Condition
30
-
31
- When tasks/pending/ is empty:
32
- Output: __DONE__
3
+ - Pick a task from pending, claim it, execute it, complete it.
4
+ - Follow the task description and acceptance criteria exactly.
5
+ - Do not create new tasks. Do not redesign. Do not refactor beyond the task scope.
6
+ - If a task is unclear, skip it (leave in pending/) and pick another.
7
+ - Keep changes minimal.
@@ -1,35 +1,11 @@
1
- Goal: Break spec.md into executable tasks
2
- Process: Create tasks in tasks/pending/*.edn
3
- Method: Do NOT write code. Only create and refine tasks.
4
-
5
- ## Your Role
6
-
7
- You are a planner. You:
8
- - Read spec.md to understand the goal
9
- - Create small, focused tasks in tasks/pending/
10
- - Monitor progress by checking tasks/complete/
11
- - Refine or split tasks that are too large
12
- - Do NOT execute tasks yourself
13
-
14
- ## Task Creation
15
-
16
- Write .edn files to tasks/pending/:
17
- ```edn
18
- {:id "task-001"
19
- :summary "Add user authentication"
20
- :description "Implement JWT-based auth for the API"
21
- :files ["src/auth.py" "tests/test_auth.py"]
22
- :acceptance ["Login endpoint returns token" "Tests pass"]}
23
- ```
24
-
25
- ## Guidelines
26
-
27
- - Keep tasks small (1-2 files max)
28
- - Be specific about acceptance criteria
29
- - Consider dependencies between tasks
30
- - Check what's already complete before creating duplicates
31
-
32
- ## Exit Condition
33
-
34
- When spec.md is fully covered by tasks and all are complete:
35
- Output: __DONE__
1
+ You are a planner. You read the spec, explore the codebase, and create well-scoped tasks.
2
+
3
+ - Read spec.md and understand the full goal before creating any tasks.
4
+ - Explore the existing code to understand what exists and what's missing.
5
+ - Create small, focused tasks with clear acceptance criteria.
6
+ - Set :difficulty on each task (:easy, :medium, :hard) so the right worker picks it up.
7
+ - Refine or split tasks that are too large or vague.
8
+ - Check ../tasks/complete/ before creating duplicates.
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.
11
+ - Spend time thinking. Good task decomposition is the highest-leverage thing you can do.
@@ -1,31 +1,6 @@
1
- Goal: Match spec.md
2
- Process: Create/claim tasks in tasks/{pending,current,complete}/*.edn
3
- Method: Isolate changes to your worktree, commit and merge when complete
1
+ You are a worker. You claim tasks, execute them, and complete them.
4
2
 
5
- ## Task Management
6
-
7
- Check tasks/pending/ for available work:
8
- - To claim: move file from pending/ to current/
9
- - To complete: move file from current/ to complete/
10
- - To create: write new .edn file to pending/
11
-
12
- Task file format:
13
- ```edn
14
- {:id "task-001"
15
- :summary "Short description"
16
- :description "Detailed description"
17
- :files ["src/foo.py"]}
18
- ```
19
-
20
- ## Workflow
21
-
22
- 1. Check if tasks/pending/ has tasks
23
- 2. If yes: claim one (mv to current/), execute it, complete it (mv to complete/)
24
- 3. If no: check spec.md for gaps, create new tasks if needed
25
- 4. Commit changes to your worktree
26
- 5. Merge your worktree branch to main
27
-
28
- ## Exit Condition
29
-
30
- When spec.md is fully satisfied and no more tasks are needed:
31
- Output: __DONE__
3
+ - Pick tasks that match your strengths.
4
+ - If no tasks exist, read the spec and create them.
5
+ - Keep changes focused. Commit when a task is done.
6
+ - If a task is too big, split it into smaller tasks and work on one.
@@ -4,15 +4,16 @@
4
4
  "workers": [
5
5
  {
6
6
  "model": "claude:opus-4.5",
7
+ "prompt": ["config/prompts/planner.md"],
7
8
  "iterations": 5,
8
- "count": 1,
9
- "prompt": "config/prompts/planner.md"
9
+ "count": 1
10
10
  },
11
11
  {
12
12
  "model": "codex:codex-5.2-mini",
13
+ "prompt": ["config/prompts/executor.md"],
13
14
  "iterations": 10,
14
15
  "count": 3,
15
- "prompt": "config/prompts/executor.md"
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.1.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",