agentainer 0.1.7 → 2.0.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 (44) hide show
  1. package/README.md +248 -677
  2. package/agentainer +16 -18
  3. package/agentainer.example.yaml +86 -0
  4. package/bin/agentainer.js +9 -8
  5. package/examples/brainstorm.yaml +27 -128
  6. package/examples/bug-hunt.yaml +51 -96
  7. package/examples/code-review.yaml +73 -0
  8. package/examples/debate.yaml +16 -90
  9. package/examples/incident-response.yaml +52 -109
  10. package/examples/localization.yaml +56 -123
  11. package/examples/quickstart.yaml +48 -0
  12. package/examples/research.yaml +25 -0
  13. package/examples/software-company.yaml +71 -128
  14. package/examples/tdd-pingpong.yaml +36 -68
  15. package/examples/writers-room.yaml +49 -111
  16. package/hooks/claude_stop.sh +5 -3
  17. package/hooks/codex_notify.sh +4 -3
  18. package/lib/cli.py +929 -0
  19. package/lib/config.py +247 -305
  20. package/lib/hooks.py +246 -0
  21. package/lib/lock.py +75 -0
  22. package/lib/log.py +64 -0
  23. package/lib/mail.py +634 -0
  24. package/lib/minyaml.py +1 -39
  25. package/lib/reconcile.py +473 -0
  26. package/lib/sessions.py +223 -0
  27. package/lib/supervisor.py +216 -0
  28. package/lib/telegram.py +372 -0
  29. package/lib/tmux.py +355 -0
  30. package/lib/turn.py +159 -0
  31. package/lib/ui.py +1020 -0
  32. package/llms.txt +145 -429
  33. package/package.json +9 -7
  34. package/scripts/check-deps.js +18 -61
  35. package/ui/app.js +869 -0
  36. package/ui/index.html +348 -0
  37. package/agents.example.yaml +0 -257
  38. package/examples/code-review-broadcast.yaml +0 -109
  39. package/examples/existing-repo.yaml +0 -74
  40. package/examples/multi-language-broadcast.yaml +0 -127
  41. package/examples/ping-pong.yaml +0 -89
  42. package/examples/red-team.yaml +0 -117
  43. package/examples/research-swarm.yaml +0 -129
  44. package/lib/swarm.py +0 -2461
package/agentainer CHANGED
@@ -1,22 +1,23 @@
1
1
  #!/usr/bin/env bash
2
2
  #
3
- # Agentainer -- launch a configurable swarm of coding agents in tmux.
3
+ # Agentainer -- launch a configurable team of coding agents in tmux.
4
4
  #
5
- # ./agentainer up start every agent in agents.yaml
6
- # ./agentainer up -c my-swarm.yaml ...from a different config
7
- # ./agentainer agents.yaml shorthand for `up -c agents.yaml`
8
- # ./agentainer status see who is running
9
- # ./agentainer send --to dev "hi" message an agent
10
- # ./agentainer attach dev jump into an agent's tmux session
11
- # ./agentainer down stop everything
5
+ # ./agentainer up start every agent in agentainer.yaml
6
+ # ./agentainer up -c my-swarm.yaml ...from a different config
7
+ # ./agentainer my-swarm.yaml shorthand for `up -c my-swarm.yaml`
8
+ # ./agentainer validate print the resolved config, launch nothing
9
+ # ./agentainer status see who is running
10
+ # ./agentainer send --to dev "hi" mail an agent
11
+ # ./agentainer attach dev jump into an agent's tmux session
12
+ # ./agentainer down stop everything
12
13
  #
13
14
  # See README.md for the full reference, or llms.txt if you are an LLM.
14
15
  set -euo pipefail
15
16
 
16
- SWARM_HOME="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
17
- export SWARM_HOME
17
+ AGENTAINER_HOME="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
18
+ export AGENTAINER_HOME
18
19
 
19
- PYTHON="${SWARM_PYTHON:-}"
20
+ PYTHON="${AGENTAINER_PYTHON:-}"
20
21
  if [[ -z "$PYTHON" ]]; then
21
22
  for candidate in python3 python; do
22
23
  if command -v "$candidate" >/dev/null 2>&1; then
@@ -27,7 +28,7 @@ if [[ -z "$PYTHON" ]]; then
27
28
  fi
28
29
 
29
30
  if [[ -z "$PYTHON" ]]; then
30
- echo "xx Agentainer needs python3 on PATH (or set SWARM_PYTHON)" >&2
31
+ echo "xx Agentainer needs python3 on PATH (or set AGENTAINER_PYTHON)" >&2
31
32
  exit 1
32
33
  fi
33
34
 
@@ -35,9 +36,6 @@ if ! command -v tmux >/dev/null 2>&1; then
35
36
  echo "!! tmux was not found on PATH; every command except 'validate' will fail" >&2
36
37
  fi
37
38
 
38
- # The config is resolved in lib/swarm.py: -c, then $SWARM_CONFIG, then
39
- # ./agents.yaml, then the agents.yaml next to this script. Deliberately NOT
40
- # exported here -- a stale SWARM_CONFIG would shadow the config that a hook
41
- # discovers from the agent's working directory.
42
-
43
- exec "$PYTHON" "$SWARM_HOME/lib/swarm.py" "$@"
39
+ # The config is resolved in lib/cli.py: -c, then $AGENTAINER_CONFIG, then
40
+ # ./agentainer.yaml, then the agentainer.yaml next to this script.
41
+ exec "$PYTHON" "$AGENTAINER_HOME/lib/cli.py" "$@"
@@ -0,0 +1,86 @@
1
+ # =============================================================================
2
+ # agentainer.example.yaml — reference configuration for Agentainer v2.
3
+ #
4
+ # Copy it to start your own swarm:
5
+ #
6
+ # cp agentainer.example.yaml my-swarm.yaml
7
+ # agentainer up -c my-swarm.yaml
8
+ # agentainer status -c my-swarm.yaml
9
+ # agentainer send -c my-swarm.yaml --to orchestrator "Build a CSV->Parquet CLI."
10
+ # agentainer down -c my-swarm.yaml
11
+ #
12
+ # This file is FULLY COMMENTED and KEY-FREE: every `command:` runs a tiny
13
+ # `bash` loop instead of a real agent CLI, so the swarm comes up and routes
14
+ # mail with NO API keys and NO model calls. To run real agents, swap each
15
+ # `command` for the actual CLI you installed and drop `capture: none` so turns
16
+ # get detected.
17
+ #
18
+ # The v2 model: agents RECEIVE by reading a file (inbox/) and SEND by writing a
19
+ # file (outbox/<name>/). The orchestrator owns routing, ACL, message IDs,
20
+ # read-state, queueing, retries, and the durable log.
21
+ # =============================================================================
22
+
23
+ swarm:
24
+ name: my-swarm # any label; shown in `status` / logs
25
+ root: ./my-swarm-workspace # disposable working dir; agents get <root>/<name>/ subdirs
26
+ supervise: true # run the liveness supervisor (heartbeat) at up
27
+ supervise_interval_ms: 15000 # how often the supervisor reconciles agents
28
+ ready_timeout_ms: 30000 # give up waiting for an agent's input prompt after this
29
+ busy_timeout_ms: 120000 # mark a silent agent idle after this long
30
+ user_available: false # the human mailbox starts away (set `agentainer user available`)
31
+
32
+ # Optional Telegram bridge (off by default). When enabled, the orchestrator
33
+ # mirrors mail to a Telegram chat over HTTPS (stdlib only, no dependency), and a
34
+ # Telegram reply to a mirrored message routes back into the swarm as `user` mail.
35
+ # Create a bot with @BotFather for the token; get your chat id from @userinfobot.
36
+ # It is easiest to set all of this from the UI (`agentainer serve` -> Settings).
37
+ # telegram:
38
+ # enabled: true
39
+ # bot_token: "123456:ABC-DEF..." # keep this secret; it is a credential
40
+ # chat_id: "123456789" # the chat/user id to send to & accept replies from
41
+ # mirror: "*" # "*"/all, or a list of agent names to mirror
42
+ # mirror_user: true # also mirror mail addressed to you (default true)
43
+ # mirror_system: false # mirror system pings/bounces too (default false)
44
+
45
+ defaults:
46
+ # capture: how the orchestrator knows a turn finished.
47
+ # hook -> per-type hook/notify (claude Stop hook, codex `notify`) [default for those types]
48
+ # pane -> poll the tmux pane (gemini / hermes, or any CLI without a hook)
49
+ # none -> no turn detection (mock agents; the agent never "finishes")
50
+ # `capture: none` is auto-upgraded to `hook` on hook-backed types at load time.
51
+ capture: none
52
+ can_talk_to: [] # tightened per agent below
53
+
54
+ agents:
55
+ # The orchestrator fans work out to the workers. It may also talk to the human.
56
+ - name: orchestrator
57
+ type: claude
58
+ can_talk_to: [developer, reviewer, user] # may also talk to the human mailbox
59
+ # Real agent: command: "claude --dangerously-skip-permissions"
60
+ command: "claude --dangerously-skip-permissions"
61
+ role: "You are the orchestrator. Wait for the user's task, then delegate to workers."
62
+
63
+ # A worker that can only reply to the orchestrator (enforced by the ACL).
64
+ - name: developer
65
+ type: codex
66
+ can_talk_to: [orchestrator]
67
+ # Real agent: command: "codex"
68
+ command: "codex --yolo"
69
+ role: "You are a developer. Implement what the orchestrator asks."
70
+
71
+ # A reviewer that checks the developer's work.
72
+ - name: reviewer
73
+ type: claude
74
+ can_talk_to: [developer]
75
+ # Real agent: command: "claude"
76
+ command: "claude --dangerously-skip-permissions"
77
+ role: "You are a reviewer. Read the developer's output and critique it."
78
+
79
+ # An optional idle pinger: every N seconds, if idle, the orchestrator drops a
80
+ # `system` nudge into this agent's queue (idle-only, no pile-up, min-cadence).
81
+ # - name: researcher
82
+ # type: gemini
83
+ # can_talk_to: [orchestrator]
84
+ # command: "bash -c 'while true; do read -r l || sleep 1; done'"
85
+ # periodically_ping_seconds: 600
86
+ # periodically_ping_message: "Any progress to report? Reply, or stay quiet."
package/bin/agentainer.js CHANGED
@@ -4,14 +4,15 @@
4
4
  // npm symlinks this file into a bin directory (e.g. /usr/local/bin/agentainer).
5
5
  // Node resolves that symlink before setting __dirname, so __dirname always
6
6
  // points at the real bin/ inside the installed package -- which makes the
7
- // package root, and therefore SWARM_HOME, reliable no matter where npm puts us.
7
+ // package root, and therefore AGENTAINER_HOME, reliable no matter where npm
8
+ // puts us.
8
9
  "use strict";
9
10
 
10
11
  const path = require("path");
11
12
  const { spawnSync } = require("child_process");
12
13
 
13
14
  const PKG_ROOT = path.resolve(__dirname, "..");
14
- const ENTRY = path.join(PKG_ROOT, "lib", "swarm.py");
15
+ const ENTRY = path.join(PKG_ROOT, "lib", "cli.py");
15
16
 
16
17
  // `agentainer doctor` re-runs the dependency check without touching Python.
17
18
  if (process.argv[2] === "doctor") {
@@ -21,11 +22,11 @@ if (process.argv[2] === "doctor") {
21
22
  process.exit(r.status === null ? 1 : r.status);
22
23
  }
23
24
 
24
- // Locate a Python interpreter, mirroring ./agentainer (SWARM_PYTHON, then python3,
25
- // then python).
25
+ // Locate a Python interpreter, mirroring ./agentainer (AGENTAINER_PYTHON, then
26
+ // python3, then python).
26
27
  function findPython() {
27
- const candidates = process.env.SWARM_PYTHON
28
- ? [process.env.SWARM_PYTHON]
28
+ const candidates = process.env.AGENTAINER_PYTHON
29
+ ? [process.env.AGENTAINER_PYTHON]
29
30
  : ["python3", "python"];
30
31
  for (const cand of candidates) {
31
32
  const probe = spawnSync(cand, ["--version"], { stdio: "ignore" });
@@ -42,7 +43,7 @@ function has(cmd, args) {
42
43
  const python = findPython();
43
44
  if (!python) {
44
45
  process.stderr.write(
45
- "xx Agentainer needs python3 on PATH (or set SWARM_PYTHON).\n" +
46
+ "xx Agentainer needs python3 on PATH (or set AGENTAINER_PYTHON).\n" +
46
47
  " Run `agentainer doctor` for install hints.\n"
47
48
  );
48
49
  process.exit(1);
@@ -59,7 +60,7 @@ if (!has("tmux", ["-V"])) {
59
60
 
60
61
  const result = spawnSync(python, [ENTRY, ...process.argv.slice(2)], {
61
62
  stdio: "inherit",
62
- env: { ...process.env, SWARM_HOME: PKG_ROOT },
63
+ env: { ...process.env, AGENTAINER_HOME: PKG_ROOT },
63
64
  });
64
65
 
65
66
  if (result.error) {
@@ -1,147 +1,46 @@
1
1
  # =============================================================================
2
- # Brainstorm -- diverge into many ideas, then converge on a few worth doing.
2
+ # 💡 Brainstorm -- two agents riff on a prompt, each extending the other, with no
3
+ # orchestrator in the middle. A pure ping-pong of ideas via the mail model.
3
4
  #
4
- # agentainer up -c examples/brainstorm.yaml
5
- # agentainer send --to facilitator "Ways to cut our cloud bill by 30%."
5
+ # cp examples/brainstorm.yaml my-session.yaml
6
+ # agentainer up -c my-session.yaml
7
+ # agentainer send -c my-session.yaml --to a "We need a name for a CLI tool."
8
+ # agentainer down -c my-session.yaml
6
9
  #
7
- # Shape: fan-out then funnel. A FACILITATOR poses the prompt to three idea
8
- # generators who each riff from a different angle and never see each other's
9
- # lists (so they don't converge too early), then hands the pile to a SYNTHESISER
10
- # who clusters, de-dupes and ranks. The generators talk only to the facilitator.
10
+ # Shape: A <--> B, two-way, and that's the whole graph. Useful for ideation,
11
+ # rubber-ducking, or adversarial "yes, and..." loops. Either agent may also
12
+ # talk to `user` (the human can drop in).
11
13
  #
12
- # wildcard pragmatist contrarian
13
- # \ | /
14
- # `----- facilitator -----'
15
- # |
16
- # synthesiser
14
+ # a <----> b
17
15
  #
18
- # Every link is two-way (the facilitator prompts each generator and they
19
- # answer back). Ideas diverge across the three generators, then converge
20
- # through the facilitator to the synthesiser.
21
- #
22
- # Deliberately divergent roles keep the three from producing the same list three
23
- # times. This swarm creates its own folders under `root` -- no repo needed.
16
+ # Real agents: commands launch the actual CLIs (claude / codex / gemini / hermes). For a key-free demo, swap each `command` for a mock bash loop.
24
17
  # =============================================================================
25
18
 
26
19
  swarm:
27
20
  name: brainstorm
28
21
  root: ./brainstorm-workspace
29
- session_prefix: "bs-"
30
-
31
- # Fan-out then one funnel step: a single hop is enough.
32
- max_forward_hops: 1
33
22
 
34
23
  defaults:
35
- type: claude
24
+ capture: none
25
+ can_talk_to: []
36
26
 
37
27
  agents:
38
-
39
- - name: facilitator
40
- type: claude
41
- command: "claude --dangerously-skip-permissions --model opus"
42
- can_talk_to: ["wildcard", "pragmatist", "contrarian", "synthesiser"]
43
-
44
- # Waits for the human to supply the actual prompt.
45
- in_first_prompt_append_your_task_will_be_sent_in_the_next_prompt: true
46
-
47
- first_prompt: |
48
- You are the FACILITATOR. You run a divergent-then-convergent session.
49
-
50
- You do not generate ideas or judge them yourself. You frame the prompt,
51
- keep the three generators pulling in different directions, then hand the
52
- raw pile to the synthesiser and relay the result.
53
-
54
- Your room:
55
- - wildcard: unconstrained, ambitious, "what if budget were no object"
56
- - pragmatist: ships this quarter with what we already have
57
- - contrarian: attacks the framing and the obvious answers
58
- - synthesiser: clusters, de-dupes and ranks everything at the end
59
-
60
- How to run it:
61
- 1. Sharpen the human's prompt into one clear question with a success
62
- metric. Send it to all three generators, and tell each to lean fully
63
- into ITS angle -- no self-censoring, no converging yet.
64
- 2. Do NOT show generators each other's ideas mid-round; that collapses
65
- the diversity you are paying for.
66
- 3. When all three have reported, forward the combined, unedited list to
67
- the synthesiser.
68
- 4. Relay the synthesiser's ranked shortlist to the human, with the one
69
- bold idea and the one safe idea called out.
70
-
71
- In the diverge phase, quantity and range beat quality. Save judgement for
72
- the synthesiser.
73
-
74
- - name: wildcard
75
- type: claude
76
- command: "claude --dangerously-skip-permissions"
77
- can_talk_to: ["facilitator"]
78
-
79
- first_prompt: |
80
- You are the WILDCARD. Your job is range and ambition, not feasibility.
81
-
82
- Given the question, produce 8-12 genuinely different ideas, including ones
83
- that sound expensive, weird, or premature. Assume constraints can be
84
- renegotiated. Chase the idea that would matter most if it worked.
85
-
86
- For each: a one-line pitch and the single reason it could be a big deal.
87
- Do not filter for practicality -- the pragmatist and synthesiser do that.
88
- Avoid the obvious answer everyone already thought of; go past it.
89
-
90
- - name: pragmatist
91
- type: codex
92
- command: "codex --yolo"
93
- can_talk_to: ["facilitator"]
94
-
95
- first_prompt: |
96
- You are the PRAGMATIST. Your job is ideas that ship soon, cheaply.
97
-
98
- Given the question, produce 8-12 ideas that a small team could start this
99
- quarter with tools it already has. Favour reversible, low-risk moves with a
100
- clear owner and a visible payoff.
101
-
102
- For each: a one-line pitch, the rough effort, and the expected payoff. Bias
103
- toward things measurable within a few weeks. Leave the moonshots to the
104
- wildcard; you own "what can we actually do on Monday".
105
-
106
- - name: contrarian
28
+ - name: a
107
29
  type: claude
30
+ can_talk_to: [b, user]
108
31
  command: "claude --dangerously-skip-permissions"
109
- can_talk_to: ["facilitator"]
110
-
111
- first_prompt: |
112
- You are the CONTRARIAN. You attack the question and the easy answers.
113
-
114
- First, challenge the framing: is the stated goal the real goal? Is the
115
- metric measuring the right thing? Name the assumption everyone is making.
32
+ role: |
33
+ You are BRAINSTORMER A. You receive an idea in your inbox/ and extend it
34
+ -- build on it, add a twist, or sharpen it -- then send your riff back to
35
+ agent b (write a file into outbox/b/). Keep the energy up; one concrete
36
+ improvement per message. If the human (user) writes to you, answer them.
116
37
 
117
- Then produce 6-10 ideas that come from rejecting the obvious approach:
118
- do the opposite, remove the thing instead of optimising it, or solve the
119
- problem one level up so it disappears.
120
-
121
- For each: the conventional answer you are rejecting, and your alternative.
122
- Be provocative but honest -- the goal is better options, not just dissent.
123
-
124
- - name: synthesiser
38
+ - name: b
125
39
  type: claude
40
+ can_talk_to: [a, user]
126
41
  command: "claude --dangerously-skip-permissions"
127
- can_talk_to: ["facilitator"]
128
-
129
- # The shortlist lands somewhere predictable.
130
- workdir: ./brainstorm-output
131
-
132
- first_prompt: |
133
- You are the SYNTHESISER. You turn a messy pile of ideas into a decision.
134
-
135
- You receive every idea from all three generators. Write the result to
136
- SHORTLIST.md.
137
-
138
- Do this:
139
- 1. Cluster near-duplicates into single themes; note where two angles
140
- independently converged (that is a signal).
141
- 2. Score each theme on impact vs effort. Be explicit about the criteria.
142
- 3. Produce a ranked shortlist of 3-5 things worth doing, each with why it
143
- made the cut and the first concrete step.
144
- 4. Call out the single boldest bet and the single safest quick win, and
145
- name any idea that is a trap (looks great, fails in practice).
146
-
147
- Do not just list everything back. The value you add is cutting.
42
+ role: |
43
+ You are BRAINSTORMER B. You receive A's riff in your inbox/ and push it
44
+ further -- a new angle, a risk, a concrete next step -- then send it back
45
+ to agent a (write a file into outbox/a/). One concrete improvement per
46
+ message. If the human (user) writes to you, answer them.
@@ -1,112 +1,67 @@
1
1
  # =============================================================================
2
- # Bug hunt -- an automatic pipeline: reproduce -> diagnose -> fix -> verify.
2
+ # 🐛 Bug hunt -- one orchestrator fans a bug report out to several hunters who
3
+ # each investigate a different area, then report findings back.
3
4
  #
4
- # agentainer up -c examples/bug-hunt.yaml
5
- # agentainer send --to reproducer "Uploads over 2MB fail with a 500 in prod."
5
+ # cp examples/bug-hunt.yaml my-hunt.yaml
6
+ # agentainer up -c my-hunt.yaml
7
+ # agentainer send -c my-hunt.yaml --to orchestrator "Intermittent 500s on /api/login."
8
+ # agentainer down -c my-hunt.yaml
6
9
  #
7
- # This is the one shape where `forward_responses_to` earns its keep: each stage
8
- # hands its finished turn to the next stage automatically, with no human in the
9
- # loop. Everything flows one way, so the hop guard never has to save you.
10
+ # Shape: orchestrator is the hub. Hunters never talk to each other (they'd
11
+ # double up or step on each other's fixes); they report only to the orchestrator,
12
+ # who de-duplicates and assigns the fix.
10
13
  #
11
- # reproducer --> diagnoser --> fixer --> verifier
14
+ # orchestrator <--> hunter-a, hunter-b, hunter-c (spokes silent among selves)
12
15
  #
13
- # Auto-forwarding is chatty by nature. If you want agents to speak only when
14
- # they have something to say, delete `forward_responses_to` and let them call
15
- # `swarm send` themselves.
16
+ # Real agents: commands launch the actual CLIs (claude / codex / gemini / hermes). For a key-free demo, swap each `command` for a mock bash loop.
16
17
  # =============================================================================
17
18
 
18
19
  swarm:
19
- name: bughunt
20
- root: ./bughunt
21
- session_prefix: "bug-"
20
+ name: bug-hunt
21
+ root: ./bug-hunt-workspace
22
22
 
23
- # A straight line needs exactly as many hops as it has stages.
24
- max_forward_hops: 4
23
+ defaults:
24
+ capture: none
25
+ can_talk_to: []
25
26
 
26
27
  agents:
27
-
28
- - name: reproducer
28
+ - name: orchestrator
29
+ type: claude
30
+ can_talk_to: [hunter_a, hunter_b, hunter_c, user]
31
+ command: "claude --dangerously-skip-permissions"
32
+ role: |
33
+ You are the HUNT COORDINATOR. You receive a bug report (as mail in your
34
+ inbox/) and split it into disjoint leads -- one per hunter. Each hunter gets a
35
+ sharp, independent question and the file/area to focus on. Collect their
36
+ findings, de-duplicate, and decide who fixes what. Never let two hunters
37
+ investigate the same thing.
38
+
39
+ - name: hunter_a
29
40
  type: codex
41
+ can_talk_to: [orchestrator]
30
42
  command: "codex --yolo"
31
- can_talk_to: ["diagnoser"]
32
- forward_responses_to: ["diagnoser"]
33
-
34
- first_prompt: |
35
- You are the REPRODUCER, the first stage of a bug-hunting pipeline.
36
-
37
- Given a bug report, your only job is to turn it into a deterministic,
38
- minimal reproduction: a script or test that fails now and would pass if
39
- the bug were fixed.
40
-
41
- Report, in this order:
42
- 1. The exact command to reproduce.
43
- 2. The observed output, verbatim.
44
- 3. The expected output.
45
- 4. What you had to assume, because the report did not say.
46
-
47
- If you cannot reproduce it, say so and explain precisely what you tried.
48
- Do not attempt a fix -- the next stage does that. Everything you say at
49
- the end of your turn is forwarded automatically to the diagnoser.
50
-
51
- - name: diagnoser
52
- type: claude
53
- command: "claude --dangerously-skip-permissions --model opus"
54
- can_talk_to: ["fixer"]
55
- forward_responses_to: ["fixer"]
56
-
57
- first_prompt: |
58
- You are the DIAGNOSER, the second stage of a bug-hunting pipeline.
59
-
60
- You receive a reproduction. Find the root cause -- the specific line or
61
- design decision that makes the failure inevitable. Not the symptom, and
62
- not the first suspicious thing you see.
63
-
64
- Report:
65
- 1. Root cause, at file:line, in one paragraph.
66
- 2. The causal chain from input to wrong output.
67
- 3. Why it was not caught: the missing test, the wrong assumption.
68
- 4. The smallest correct fix, and one alternative you rejected (say why).
69
-
70
- Do not write the fix. Describe it. Your turn is forwarded to the fixer.
43
+ role: |
44
+ You are HUNTER A (backend/logic). When the orchestrator sends you a lead,
45
+ read the code and reproduce the failure with evidence (the log line, the
46
+ input, file:line). Report back to the orchestrator: what you found and how
47
+ confident you are. Do not fix it -- just find it.
71
48
 
72
- - name: fixer
49
+ - name: hunter_b
73
50
  type: codex
51
+ can_talk_to: [orchestrator]
74
52
  command: "codex --yolo"
75
- can_talk_to: ["verifier"]
76
- forward_responses_to: ["verifier"]
77
-
78
- first_prompt: |
79
- You are the FIXER, the third stage of a bug-hunting pipeline.
80
-
81
- You receive a diagnosis. Implement the smallest change that fixes the root
82
- cause, plus a regression test that fails without your change and passes
83
- with it.
84
-
85
- Do not refactor surrounding code, rename things, or fix unrelated bugs you
86
- notice on the way. Mention them instead.
87
-
88
- Report the diff you made, the test you added, and the test output. Your
89
- turn is forwarded to the verifier, who does not trust you.
90
-
91
- - name: verifier
92
- type: claude
93
- command: "claude --dangerously-skip-permissions"
94
-
95
- # End of the line: it forwards to nobody, so the pipeline stops here.
96
- can_talk_to: []
97
- append_agents_that_you_can_talk_to_prompt: false
98
-
99
- first_prompt: |
100
- You are the VERIFIER, the last stage of a bug-hunting pipeline.
101
-
102
- You receive a proposed fix. Assume it is wrong until you have checked.
103
-
104
- Do all of these:
105
- 1. Run the original reproduction. Does it now pass?
106
- 2. Run the whole test suite. Did anything else break?
107
- 3. Read the fix. Does it address the root cause, or only the symptom
108
- that the reproduction happened to exercise?
109
- 4. Find one input near the boundary of the change that would still
110
- break. If you find one, the fix is not done.
111
-
112
- Print a verdict: SHIPPABLE or NOT SHIPPABLE, then the evidence. Be blunt.
53
+ role: |
54
+ You are HUNTER B (frontend/UX). When the orchestrator sends you a lead,
55
+ trace the user-facing path that triggers the bug and capture the exact
56
+ steps + screenshots/state. Report to the orchestrator with evidence. Do not
57
+ fix it -- just find it.
58
+
59
+ - name: hunter_c
60
+ type: gemini
61
+ can_talk_to: [orchestrator]
62
+ capture: pane
63
+ command: "gemini --yolo"
64
+ role: |
65
+ You are HUNTER C (dependencies/config). Check recent dependency bumps,
66
+ config changes, and environment drift that could explain the symptom. Report
67
+ to the orchestrator with evidence. Do not fix it -- just find it.
@@ -0,0 +1,73 @@
1
+ # =============================================================================
2
+ # 🧐 Code review -- several developers each build a slice and a single REVIEWER
3
+ # checks every one of them. (v1 had a `broadcast` primitive; v2 has no
4
+ # broadcast -- instead the reviewer's `can_talk_to` simply lists all the
5
+ # developers, so it can address each one directly.)
6
+ #
7
+ # cp examples/code-review.yaml my-repo.yaml
8
+ # agentainer up -c my-repo.yaml
9
+ # agentainer send -c my-repo.yaml --to reviewer "Review the open PRs, report per dev."
10
+ # agentainer down -c my-repo.yaml
11
+ #
12
+ # Shape: developers never talk to each other; each talks only to the reviewer,
13
+ # who is the hub. This keeps every critique flowing through one consistent
14
+ # reviewer voice instead of N pairwise arguments.
15
+ #
16
+ # dev-1 \
17
+ # dev-2 > reviewer (hub)
18
+ # dev-3 /
19
+ #
20
+ # Key-free: commands are bash loops. Swap for real CLIs to review real code.
21
+ # =============================================================================
22
+
23
+ swarm:
24
+ name: code-review
25
+ root: ./code-review-workspace
26
+
27
+ defaults:
28
+ capture: none
29
+ can_talk_to: []
30
+
31
+ agents:
32
+ - name: reviewer
33
+ type: claude
34
+ can_talk_to: [dev_1, dev_2, dev_3, user]
35
+ command: "claude --dangerously-skip-permissions"
36
+ role: |
37
+ You are the REVIEWER -- the hub. When a developer sends you their work
38
+ (mail in your inbox/), read it and try to break it: wrong logic,
39
+ unhandled errors, race conditions, data loss, auth holes. Cite file:line.
40
+ Send each critique back to the specific developer who wrote it (write a file
41
+ into outbox/<their-name>/). Never let two developers argue with each other
42
+ directly -- all feedback goes through you. If the human (user) writes to
43
+ you, answer them.
44
+
45
+ - name: dev_1
46
+ type: codex
47
+ can_talk_to: [reviewer]
48
+ command: "codex --yolo"
49
+ role: |
50
+ You are DEVELOPER 1. Build your slice in your own directory. When a unit
51
+ of work is done, send the reviewer a short summary (write a file into
52
+ outbox/reviewer/): what changed, why, and what you are unsure about.
53
+ Ask for review. Act only on the reviewer's feedback.
54
+
55
+ - name: dev_2
56
+ type: codex
57
+ can_talk_to: [reviewer]
58
+ command: "codex --yolo"
59
+ role: |
60
+ You are DEVELOPER 2. Build your slice in your own directory. When a unit
61
+ of work is done, send the reviewer a short summary (write a file into
62
+ outbox/reviewer/): what changed, why, and what you are unsure about.
63
+ Ask for review. Act only on the reviewer's feedback.
64
+
65
+ - name: dev_3
66
+ type: codex
67
+ can_talk_to: [reviewer]
68
+ command: "codex --yolo"
69
+ role: |
70
+ You are DEVELOPER 3. Build your slice in your own directory. When a unit
71
+ of work is done, send the reviewer a short summary (write a file into
72
+ outbox/reviewer/): what changed, why, and what you are unsure about.
73
+ Ask for review. Act only on the reviewer's feedback.