Skip to content

nbardy/oompa

Repository files navigation

oompa

Oompa Loompas building code

Getting your ralphs to work together


The Minimal Idea

From the Oompa Loompas blog post — the simplest multi-agent swarm:

oompa_loompas.sh (7 lines):

#!/bin/bash
for w in $(seq 1 ${WORKERS:-3}); do
  (for i in $(seq 1 ${ITERATIONS:-5}); do
    wt=".w${w}-i${i}"
    git worktree add $wt -b $wt 2>/dev/null
    { echo "Worktree: $wt"; cat prompts/worker.md; } | claude -p -
  done) &
done; wait

prompts/worker.md (3 lines):

Goal: Match spec.md
Process: Create/claim tasks in tasks/{pending,in_progress,complete}.md
Method: Isolate changes to your worktree, commit and merge when complete

That's it. Parallel agents with worktree isolation.


The Full Version

This repo has a fleshed out version of the idea. The oompa loompas are organized by a more sophisticated Clojure harness, enabling advanced features:

  • Different worker types — small models for fast execution, big models for planning
  • Separate review model — use a smart model to check work before merging
  • Mixed harnesses — combine Claude, Codex, and Opencode workers in one swarm
  • Self-directed tasks — workers create and claim tasks from shared folders

Architecture

┌─────────────────────────────────────────────────────────────────────┐
│                         SELF-DIRECTED WORKERS                        │
│                                                                      │
│   tasks/pending/*.edn ──→ Worker claims ──→ tasks/current/*.edn     │
│      ▲                         │                                     │
│      │                         ▼                                     │
│      │                    Execute in worktree                        │
│      │                         │                                     │
│      │                         ▼                                     │
│      │                    Commit changes                             │
│      │                         │                                     │
│      │                         ▼                                     │
│      │               ┌─────────────────────┐                         │
│      │               │  REVIEWER checks    │                         │
│      │               │  (review_model)     │                         │
│      │               └──────────┬──────────┘                         │
│      │                    ┌─────┴─────┐                              │
│      │                    ▼           ▼                              │
│      │               Approved     Rejected                           │
│      │                    │           │                              │
│      │                    ▼           └──────┐                       │
│      │               Merge to                │                       │
│      │                 main                  │                       │
│      │                    │                  ▼                       │
│      │                    │            Fix & retry ──→ Reviewer      │
│      │                    │                                          │
│      └─── Create tasks ◄──┘                                          │
│                                                                      │
│   Exit when: __DONE__ token emitted                                 │
└─────────────────────────────────────────────────────────────────────┘

Configuration

oompa.json — the only file you need:

{
  "workers": [
    {"model": "claude:opus", "prompt": ["config/prompts/planner.md"], "iterations": 5, "count": 1},
    {"model": "codex:gpt-5.3-codex:medium", "prompt": ["config/prompts/executor.md"], "iterations": 10, "count": 2, "can_plan": false},
    {"model": "opencode:opencode/kimi-k2.5-free", "prompt": ["config/prompts/executor.md"], "iterations": 10, "count": 1, "can_plan": false}
  ]
}

This spawns:

  • 1 planner (opus) — reads spec, explores codebase, creates/refines tasks
  • 2 codex executors (gpt-5.3-codex, medium reasoning) — claims and executes tasks fast
  • 1 opencode executor (opencode/kimi-k2.5-free) — same task loop via opencode run

Worker fields

Field Required Description
model yes harness:model or harness:model:reasoning (e.g. codex:gpt-5.3-codex:medium, claude:opus, opencode:opencode/kimi-k2.5-free)
prompt no String or array of paths — concatenated into one prompt
iterations no Max iterations per worker (default: 10)
count no Number of workers with this config (default: 1)
can_plan no If false, worker waits for tasks before starting (default: true)
max_wait_for_tasks no Max seconds a can_plan: false worker waits for queue work (default: 600)

Composable prompts

prompt accepts a string or an array. Arrays get concatenated, so you can reuse a shared base across workers:

{
  "workers": [
    {"model": "claude:opus-4.5", "prompt": ["prompts/base.md", "prompts/architect.md"], "count": 1},
    {"model": "opencode:opencode/kimi-k2.5-free", "prompt": ["prompts/base.md", "prompts/frontend.md"], "count": 2},
    {"model": "codex:codex-5.2-mini", "prompt": ["prompts/base.md", "prompts/backend.md"], "count": 2}
  ]
}

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.

Prompt includes

Prompts support #oompa_directive:include_file "path/to/file.md" lines.

Use it to share common instructions across roles without copying content.
Paths are resolved relative to the prompt file containing the directive.

Example:

#oompa_directive:include_file "config/prompts/_agent_scope_rules.md"

You are an executor. Focus on minimal changes and complete tasks.

The included file is inlined during prompt load, with a short header noting the injected source.

Task System

Workers self-organize via the filesystem. Tasks live at the project root and are shared across all worktrees:

tasks/
├── pending/*.edn     # unclaimed tasks
├── current/*.edn     # in progress
└── complete/*.edn    # done

From inside a worktree, workers reach tasks via ../tasks/:

  • See tasks: ls ../tasks/pending/
  • Claim: mv ../tasks/pending/task.edn ../tasks/current/
  • Complete: mv ../tasks/current/task.edn ../tasks/complete/
  • Create: write new .edn to ../tasks/pending/

Task file format:

{:id "task-001"
 :summary "Add user authentication"
 :description "Implement JWT-based auth for the API"
 :difficulty :medium
 :files ["src/auth.py" "tests/test_auth.py"]
 :acceptance ["Login endpoint returns token" "Tests pass"]}

Bundled Prompts

Three prompt files ship with oompa that you can use in your prompt arrays:

Prompt Creates Tasks? Executes Tasks? Best For
config/prompts/worker.md (default) yes yes General purpose
config/prompts/planner.md yes sometimes Big models — task design
config/prompts/executor.md no yes Small/fast models — heads-down work

Quick Start

# Clone
git clone https://github.com/nbardy/oompa.git
cd oompa

# Check backends
./swarm.bb check

# Create a spec
echo "Build a simple todo API with CRUD endpoints" > spec.md

# Run the swarm
./swarm.bb run

# Run detached with startup validation (fails fast if startup fails)
./swarm.bb run --detach --config oompa.json

Install (npm)

# Run without installing globally
npx @nbardy/oompa check
npx @nbardy/oompa swarm
# Or install globally
npm install -g @nbardy/oompa
oompa check
oompa swarm

Commands

oompa run [file]            # Run from config (defaults: oompa.json, oompa/oompa.json)
oompa run --detach --config oompa.json
oompa swarm [file]          # Direct swarm command (foreground)
oompa list                  # List 20 most recent swarms
oompa list --all            # Full swarm history
oompa view [swarm-id]       # Per-worker runtime status (default: latest swarm)
oompa tasks                 # Show task status
oompa check                 # Check available backends
oompa cleanup               # Remove worktrees
oompa help                  # Show all commands

./swarm.bb ... works the same when running from a source checkout.

Opencode Harness

opencode workers use one-shot opencode run --format json calls with the same worker prompt tagging:

  • First prompt line still starts with [oompa:<swarmId>:<workerId>]
  • -m/--model is passed when a worker model is configured
  • First iteration starts without --session; the worker captures sessionID from that exact run output
  • On resumed iterations, workers pass -s/--session <captured-id> --continue
  • Oompa does not call opencode session list to guess a "latest" session
  • Worker completion markers (COMPLETE_AND_READY_FOR_MERGE, __DONE__) are evaluated from extracted text events, preserving existing done/merge behavior
  • Optional attach mode: set OOMPA_OPENCODE_ATTACH (or OPENCODE_ATTACH) to add --attach <url>

Worker Conversation Persistence

Workers rely on each CLI's native session persistence (no custom mirror writer):

  • Codex: native rollouts under ~/.codex/sessions/YYYY/MM/DD/*.jsonl
  • Claude: native project sessions under ~/.claude/projects/*/*.jsonl
  • Opencode: native session store managed by opencode

Oompa still tags the first prompt line with [oompa:<swarmId>:<workerId>] so downstream UIs can identify and group worker conversations.

Requirements

License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors