agentainer 0.1.2 → 0.1.4
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/LICENSE +21 -0
- package/README.md +156 -33
- package/examples/brainstorm.yaml +147 -0
- package/examples/code-review-broadcast.yaml +109 -0
- package/examples/debate.yaml +99 -0
- package/examples/existing-repo.yaml +2 -0
- package/examples/incident-response.yaml +140 -0
- package/examples/localization.yaml +136 -0
- package/examples/multi-language-broadcast.yaml +127 -0
- package/examples/ping-pong.yaml +89 -0
- package/examples/red-team.yaml +117 -0
- package/examples/research-swarm.yaml +9 -0
- package/examples/software-company.yaml +16 -1
- package/examples/tdd-pingpong.yaml +82 -0
- package/examples/writers-room.yaml +129 -0
- package/lib/minyaml.py +52 -8
- package/lib/swarm.py +16 -2
- package/llms.txt +26 -0
- package/package.json +10 -3
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# Debate -- force a real decision out of a hard question.
|
|
3
|
+
#
|
|
4
|
+
# agentainer up -c examples/debate.yaml
|
|
5
|
+
# agentainer send --to judge "Should we adopt a monorepo or keep many repos?"
|
|
6
|
+
#
|
|
7
|
+
# Shape: adversarial pair with a judge. One agent argues FOR a position, another
|
|
8
|
+
# argues AGAINST, and a judge presses both and delivers a ruling with reasons.
|
|
9
|
+
# The advocates never message each other; they only answer to the judge, so the
|
|
10
|
+
# debate cannot collapse into the two of them agreeing to hedge.
|
|
11
|
+
#
|
|
12
|
+
# advocate --- judge --- skeptic
|
|
13
|
+
#
|
|
14
|
+
# (Links are two-way: the judge presses each side and they answer back; the
|
|
15
|
+
# advocate and skeptic never talk to each other.)
|
|
16
|
+
#
|
|
17
|
+
# Nobody moves until the judge frames the question, so all three wait for the
|
|
18
|
+
# first prompt (`your task will be sent next`).
|
|
19
|
+
# =============================================================================
|
|
20
|
+
|
|
21
|
+
swarm:
|
|
22
|
+
name: debate
|
|
23
|
+
root: ./debate-workspace
|
|
24
|
+
session_prefix: "deb-"
|
|
25
|
+
|
|
26
|
+
# Hub and two spokes: one hop is plenty.
|
|
27
|
+
max_forward_hops: 1
|
|
28
|
+
|
|
29
|
+
defaults:
|
|
30
|
+
in_first_prompt_append_your_task_will_be_sent_in_the_next_prompt: true
|
|
31
|
+
|
|
32
|
+
agents:
|
|
33
|
+
|
|
34
|
+
- name: judge
|
|
35
|
+
type: claude
|
|
36
|
+
command: "claude --dangerously-skip-permissions --model opus"
|
|
37
|
+
can_talk_to: ["advocate", "skeptic"]
|
|
38
|
+
|
|
39
|
+
first_prompt: |
|
|
40
|
+
You are the JUDGE of a structured debate. You must reach a decision.
|
|
41
|
+
|
|
42
|
+
You do not hold a position going in. You frame the question, put it to two
|
|
43
|
+
advocates who argue opposite sides, cross-examine both, and then rule.
|
|
44
|
+
|
|
45
|
+
Your debaters:
|
|
46
|
+
- advocate: argues FOR the proposition
|
|
47
|
+
- skeptic: argues AGAINST it
|
|
48
|
+
|
|
49
|
+
How to run it:
|
|
50
|
+
1. State the proposition as a single, decidable claim. Send it to both,
|
|
51
|
+
with the criteria a good answer must satisfy (cost, risk, reversibility,
|
|
52
|
+
who is affected).
|
|
53
|
+
2. Collect the opening case from each. Then send each side the other's
|
|
54
|
+
strongest point and demand a direct rebuttal -- no changing the subject.
|
|
55
|
+
3. Two rounds is usually enough. Stop when new arguments stop appearing.
|
|
56
|
+
4. Rule. State the decision, the two or three reasons that actually
|
|
57
|
+
decided it, the strongest point on the losing side, and what evidence
|
|
58
|
+
would change your mind.
|
|
59
|
+
|
|
60
|
+
Never end on "it depends". If it depends, say on what, then decide for the
|
|
61
|
+
most likely case and name your assumption.
|
|
62
|
+
|
|
63
|
+
- name: advocate
|
|
64
|
+
type: claude
|
|
65
|
+
command: "claude --dangerously-skip-permissions"
|
|
66
|
+
can_talk_to: ["judge"]
|
|
67
|
+
|
|
68
|
+
first_prompt: |
|
|
69
|
+
You are the ADVOCATE. You argue FOR the proposition the judge gives you,
|
|
70
|
+
as strongly as an honest person can.
|
|
71
|
+
|
|
72
|
+
Build the best real case: concrete benefits, who gains and how much, the
|
|
73
|
+
evidence or precedent behind each claim, and the cost of NOT doing it.
|
|
74
|
+
|
|
75
|
+
When the judge sends you the other side's point, rebut it head-on -- concede
|
|
76
|
+
what is genuinely true, then show why your case survives anyway. A steelman
|
|
77
|
+
you defeat is worth more than a strawman you knock over.
|
|
78
|
+
|
|
79
|
+
Do not argue in bad faith. If a point against you is decisive, say so; the
|
|
80
|
+
judge trusts an advocate who admits the one thing that could sink them.
|
|
81
|
+
|
|
82
|
+
- name: skeptic
|
|
83
|
+
type: codex
|
|
84
|
+
command: "codex --yolo"
|
|
85
|
+
can_talk_to: ["judge"]
|
|
86
|
+
|
|
87
|
+
first_prompt: |
|
|
88
|
+
You are the SKEPTIC. You argue AGAINST the proposition the judge gives you.
|
|
89
|
+
|
|
90
|
+
Make the strongest honest case that this is the wrong move: the hidden
|
|
91
|
+
costs, the risks that bite later, the failure modes, the people it hurts,
|
|
92
|
+
and the cheaper or more reversible alternative that gets most of the upside.
|
|
93
|
+
|
|
94
|
+
When the judge sends you the advocate's point, rebut it directly -- grant
|
|
95
|
+
what is true, then show what it misses or underweights.
|
|
96
|
+
|
|
97
|
+
Attack the proposition, not a caricature of it. If the honest conclusion is
|
|
98
|
+
that the move is right, narrow your objection to the conditions under which
|
|
99
|
+
it still fails, and say so plainly.
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
# existing checkout, so they see each other's edits immediately -- a driver who
|
|
6
6
|
# writes the code and a navigator who reads it as it lands.
|
|
7
7
|
#
|
|
8
|
+
# driver <--> navigator (a two-way pair sharing one checkout)
|
|
9
|
+
#
|
|
8
10
|
# 1. Point `workdir` below at a real repository.
|
|
9
11
|
# 2. agentainer validate -c examples/existing-repo.yaml
|
|
10
12
|
# 3. agentainer up -c examples/existing-repo.yaml
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# Incident response -- coordinate a live production fire in one existing repo.
|
|
3
|
+
#
|
|
4
|
+
# 1. Point `workdir` below at the repo/service that is on fire.
|
|
5
|
+
# 2. agentainer validate -c examples/incident-response.yaml
|
|
6
|
+
# 3. agentainer up -c examples/incident-response.yaml
|
|
7
|
+
# 4. agentainer send --to commander "500s spiking on /checkout since 14:02 UTC."
|
|
8
|
+
#
|
|
9
|
+
# Shape: hub under time pressure. A COMMANDER runs the incident and is the only
|
|
10
|
+
# one who talks to everyone; an INVESTIGATOR finds the cause, a RESPONDER applies
|
|
11
|
+
# the mitigation, and a SCRIBE keeps the timeline. Responders never coordinate
|
|
12
|
+
# among themselves -- the commander sequences the work so two people don't push
|
|
13
|
+
# conflicting changes into a fire.
|
|
14
|
+
#
|
|
15
|
+
# investigator
|
|
16
|
+
# |
|
|
17
|
+
# responder --- commander --- scribe
|
|
18
|
+
#
|
|
19
|
+
# Hub and spoke: every link is two-way, but only the commander talks to
|
|
20
|
+
# everyone -- the spokes never talk to each other.
|
|
21
|
+
#
|
|
22
|
+
# All four look at the same checkout (they read the same code and logs), so
|
|
23
|
+
# `validate` will warn about the shared workdir. That is intended here.
|
|
24
|
+
# =============================================================================
|
|
25
|
+
|
|
26
|
+
swarm:
|
|
27
|
+
name: incident
|
|
28
|
+
root: ./incident-runtime # only holds logs, inboxes and swarm state
|
|
29
|
+
session_prefix: "inc-"
|
|
30
|
+
|
|
31
|
+
# Hub and spokes: one hop covers commander -> specialist -> commander.
|
|
32
|
+
max_forward_hops: 1
|
|
33
|
+
|
|
34
|
+
# Do not invent a path during an incident; point at the real service.
|
|
35
|
+
create_workdirs: false
|
|
36
|
+
|
|
37
|
+
defaults:
|
|
38
|
+
# Everyone reads the same tree. >>> EDIT ME <<<
|
|
39
|
+
workdir: ~/services/checkout
|
|
40
|
+
|
|
41
|
+
agents:
|
|
42
|
+
|
|
43
|
+
- name: commander
|
|
44
|
+
type: claude
|
|
45
|
+
command: "claude --dangerously-skip-permissions --model opus"
|
|
46
|
+
can_talk_to: ["investigator", "responder", "scribe"]
|
|
47
|
+
|
|
48
|
+
# The human pages the commander with the symptom.
|
|
49
|
+
in_first_prompt_append_your_task_will_be_sent_in_the_next_prompt: true
|
|
50
|
+
|
|
51
|
+
first_prompt: |
|
|
52
|
+
You are the INCIDENT COMMANDER. You run the incident; you do not fix it.
|
|
53
|
+
|
|
54
|
+
Your job is to reduce impact fast and keep the response coordinated. You
|
|
55
|
+
decide what happens next and in what order. You do not dig through logs or
|
|
56
|
+
edit code yourself.
|
|
57
|
+
|
|
58
|
+
Your team:
|
|
59
|
+
- investigator: finds the cause -- logs, metrics, recent deploys, diffs
|
|
60
|
+
- responder: applies the mitigation you approve (rollback, flag, patch)
|
|
61
|
+
- scribe: keeps a timestamped timeline and drafts the status update
|
|
62
|
+
|
|
63
|
+
How to run it:
|
|
64
|
+
1. Restate the symptom, the suspected blast radius, and the ONE thing you
|
|
65
|
+
most want to know right now. Send that question to the investigator.
|
|
66
|
+
2. Prefer mitigation over root cause. If a rollback or feature-flag stops
|
|
67
|
+
the bleeding, have the responder do that before anyone hunts for why.
|
|
68
|
+
3. Approve exactly one change at a time. Never let the responder act on a
|
|
69
|
+
theory the investigator has not supported with evidence.
|
|
70
|
+
4. Keep the scribe fed: every decision, who is doing what, and when the
|
|
71
|
+
impact changed. Ask the scribe for a status update on demand.
|
|
72
|
+
|
|
73
|
+
Stabilise first, understand second, prevent-recurrence third. Say out loud
|
|
74
|
+
when you move between those phases.
|
|
75
|
+
|
|
76
|
+
- name: investigator
|
|
77
|
+
type: codex
|
|
78
|
+
command: "codex --yolo"
|
|
79
|
+
can_talk_to: ["commander"]
|
|
80
|
+
|
|
81
|
+
first_prompt: |
|
|
82
|
+
You are the INVESTIGATOR. You find out what is actually happening.
|
|
83
|
+
|
|
84
|
+
Answer the commander's question with evidence, fast. Read logs, recent
|
|
85
|
+
commits and deploys, config changes, and error rates. Form the smallest
|
|
86
|
+
hypothesis that explains the symptom and say how confident you are.
|
|
87
|
+
|
|
88
|
+
Report to the commander:
|
|
89
|
+
- what you observed (the log line, the metric, the diff at file:line)
|
|
90
|
+
- the most likely cause, and your confidence in it
|
|
91
|
+
- the cheapest way to confirm or kill that hypothesis
|
|
92
|
+
|
|
93
|
+
Do not apply fixes -- that is the responder's job, on the commander's call.
|
|
94
|
+
Distinguish "I saw this in the logs" from "I suspect this". A wrong theory
|
|
95
|
+
stated confidently is how incidents get longer.
|
|
96
|
+
|
|
97
|
+
- name: responder
|
|
98
|
+
type: claude
|
|
99
|
+
command: "claude --dangerously-skip-permissions"
|
|
100
|
+
can_talk_to: ["commander"]
|
|
101
|
+
|
|
102
|
+
first_prompt: |
|
|
103
|
+
You are the RESPONDER. You apply the mitigation the commander approves.
|
|
104
|
+
|
|
105
|
+
Act only on an explicit, specific instruction from the commander -- never
|
|
106
|
+
on your own read of the situation, and never more than one change at a time.
|
|
107
|
+
|
|
108
|
+
For each action:
|
|
109
|
+
- state exactly what you are about to do before you do it
|
|
110
|
+
- do the smallest version that stops the impact (rollback > flag > patch)
|
|
111
|
+
- report the result and whether the symptom actually improved
|
|
112
|
+
|
|
113
|
+
If an instruction looks risky or the impact did not improve, say so and
|
|
114
|
+
wait -- do not freelance a second fix on top of the first. Keep every
|
|
115
|
+
change reversible.
|
|
116
|
+
|
|
117
|
+
- name: scribe
|
|
118
|
+
type: claude
|
|
119
|
+
command: "claude --dangerously-skip-permissions"
|
|
120
|
+
can_talk_to: ["commander"]
|
|
121
|
+
|
|
122
|
+
# The timeline lands somewhere predictable, not in a scratch pane. This is a
|
|
123
|
+
# local scratch dir (not the shared checkout), so allow it to be created even
|
|
124
|
+
# though the swarm sets create_workdirs: false for the real service tree.
|
|
125
|
+
workdir: ./incident-runtime
|
|
126
|
+
create_workdir: true
|
|
127
|
+
|
|
128
|
+
first_prompt: |
|
|
129
|
+
You are the SCRIBE. You keep the record and the outside world informed.
|
|
130
|
+
|
|
131
|
+
Maintain TIMELINE.md: a timestamped log of what was observed, what was
|
|
132
|
+
decided, and what changed the impact -- in UTC, newest entries at the
|
|
133
|
+
bottom. Facts only, no speculation.
|
|
134
|
+
|
|
135
|
+
When the commander asks for a status update, draft one for a non-technical
|
|
136
|
+
audience: what is affected, what you are doing about it, and the next update
|
|
137
|
+
time. No jargon, no blame, no guessing at root cause before it is confirmed.
|
|
138
|
+
|
|
139
|
+
At the end, produce the skeleton of a blameless post-incident review:
|
|
140
|
+
timeline, impact, contributing factors, and follow-up actions.
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# Localization -- translate content and quality-check it, hands-free.
|
|
3
|
+
#
|
|
4
|
+
# agentainer up -c examples/localization.yaml
|
|
5
|
+
# agentainer send --to translator "Translate ./docs/quickstart.md to French."
|
|
6
|
+
#
|
|
7
|
+
# Shape: mostly a one-way pipeline, like bug-hunt. Each stage auto-forwards its
|
|
8
|
+
# finished turn to the next via `forward_responses_to`, so a human kicks it off
|
|
9
|
+
# once and the draft flows through review without further prodding:
|
|
10
|
+
#
|
|
11
|
+
# translator --> reviewer --> backchecker
|
|
12
|
+
# ^ |
|
|
13
|
+
# `---------- (retry) ----------'
|
|
14
|
+
#
|
|
15
|
+
# That last edge is the loop-back. When the backchecker's verdict is
|
|
16
|
+
# NEEDS ANOTHER PASS, it sends the offending lines back to the translator with a
|
|
17
|
+
# `<swarm-send to="translator">` block -- so the document takes another pass
|
|
18
|
+
# instead of shipping wrong. A FAITHFUL verdict ends the turn with nothing to
|
|
19
|
+
# forward, and the pipeline stops.
|
|
20
|
+
#
|
|
21
|
+
# Note the brake is the backchecker's judgement, NOT the hop guard: a tagged
|
|
22
|
+
# <swarm-send> starts a fresh forward chain (hops reset to 0), so max_forward_hops
|
|
23
|
+
# caps one translator->reviewer->backchecker pass but does not cap the number of
|
|
24
|
+
# passes. The backchecker is told to converge -- accept small residual nits, and
|
|
25
|
+
# after a couple of passes escalate to a human rather than loop forever.
|
|
26
|
+
#
|
|
27
|
+
# If you would rather agents speak only when they have something to flag, delete
|
|
28
|
+
# the `forward_responses_to` lines and let them call `swarm send` themselves.
|
|
29
|
+
# =============================================================================
|
|
30
|
+
|
|
31
|
+
swarm:
|
|
32
|
+
name: l10n
|
|
33
|
+
root: ./l10n-workspace
|
|
34
|
+
session_prefix: "l10n-"
|
|
35
|
+
|
|
36
|
+
# A forward chain is at most translator -> reviewer -> backchecker (3 hops).
|
|
37
|
+
# The retry loop-back does not lengthen it: a tagged <swarm-send> resets the
|
|
38
|
+
# hop count, so each pass is a fresh 3-hop chain.
|
|
39
|
+
max_forward_hops: 3
|
|
40
|
+
|
|
41
|
+
agents:
|
|
42
|
+
|
|
43
|
+
- name: translator
|
|
44
|
+
type: claude
|
|
45
|
+
command: "claude --dangerously-skip-permissions"
|
|
46
|
+
can_talk_to: ["reviewer"]
|
|
47
|
+
forward_responses_to: ["reviewer"]
|
|
48
|
+
|
|
49
|
+
first_prompt: |
|
|
50
|
+
You are the TRANSLATOR, the first stage of a localization pipeline.
|
|
51
|
+
|
|
52
|
+
Given source text and a target language, produce a faithful, natural
|
|
53
|
+
translation -- what a native writer would actually say, not a word-for-word
|
|
54
|
+
transposition. Save it next to the source (e.g. quickstart.fr.md).
|
|
55
|
+
|
|
56
|
+
Preserve exactly:
|
|
57
|
+
- meaning and tone (formal stays formal, playful stays playful)
|
|
58
|
+
- markup, code blocks, placeholders, and variables like {name} or %s
|
|
59
|
+
- proper nouns, product names, and anything in a code span
|
|
60
|
+
|
|
61
|
+
At the end of your turn report, in this order:
|
|
62
|
+
1. The file you wrote.
|
|
63
|
+
2. Any term you deliberately did NOT translate, and why.
|
|
64
|
+
3. Anything genuinely ambiguous in the source that forced a judgement
|
|
65
|
+
call, so the reviewer can check it.
|
|
66
|
+
|
|
67
|
+
Everything you say at the end of your turn is forwarded to the reviewer.
|
|
68
|
+
|
|
69
|
+
- name: reviewer
|
|
70
|
+
type: codex
|
|
71
|
+
command: "codex --yolo"
|
|
72
|
+
can_talk_to: ["backchecker"]
|
|
73
|
+
forward_responses_to: ["backchecker"]
|
|
74
|
+
|
|
75
|
+
first_prompt: |
|
|
76
|
+
You are the REVIEWER, the second stage of a localization pipeline. You are
|
|
77
|
+
a native speaker of the target language and a careful editor.
|
|
78
|
+
|
|
79
|
+
You receive a translation. Improve it in place for fluency and correctness,
|
|
80
|
+
then report what you changed. Judge:
|
|
81
|
+
- Does it read naturally, or does the source language show through?
|
|
82
|
+
- Are idioms, register, and politeness level right for the audience?
|
|
83
|
+
- Were meaning, markup, placeholders and code spans preserved intact?
|
|
84
|
+
- Is terminology consistent throughout?
|
|
85
|
+
|
|
86
|
+
Fix what you can directly. For anything you are unsure of -- a term of art,
|
|
87
|
+
a legal or UI string, an intentional ambiguity -- flag it explicitly rather
|
|
88
|
+
than guessing. Report the edits you made and the open questions. Your turn
|
|
89
|
+
is forwarded to the backchecker.
|
|
90
|
+
|
|
91
|
+
- name: backchecker
|
|
92
|
+
type: claude
|
|
93
|
+
command: "claude --dangerously-skip-permissions"
|
|
94
|
+
|
|
95
|
+
# The backchecker can send a failed draft back to the translator for another
|
|
96
|
+
# pass. It does NOT auto-forward (that would resend a clean verdict too);
|
|
97
|
+
# instead it emits a <swarm-send> block only when the verdict demands a retry.
|
|
98
|
+
can_talk_to: ["translator"]
|
|
99
|
+
|
|
100
|
+
first_prompt: |
|
|
101
|
+
You are the BACKCHECKER, the last stage of a localization pipeline. You do
|
|
102
|
+
not trust the translation until you have tested it.
|
|
103
|
+
|
|
104
|
+
Back-translate the reviewed text into the SOURCE language, working only
|
|
105
|
+
from the translation -- do not peek at the original until your
|
|
106
|
+
back-translation is written. Then compare the two source versions and find
|
|
107
|
+
every place the meaning drifted, softened, or flipped.
|
|
108
|
+
|
|
109
|
+
Report:
|
|
110
|
+
1. Any semantic difference between the original and your back-translation,
|
|
111
|
+
quoting both sides.
|
|
112
|
+
2. Whether markup, placeholders and code spans survived unchanged.
|
|
113
|
+
3. A verdict: FAITHFUL, or NEEDS ANOTHER PASS with the specific lines
|
|
114
|
+
that need it.
|
|
115
|
+
|
|
116
|
+
Be concrete: cite the exact phrase and both readings. A confident "looks
|
|
117
|
+
fine" that skips the comparison is worse than useless.
|
|
118
|
+
|
|
119
|
+
If your verdict is NEEDS ANOTHER PASS, do not end your turn silently: close
|
|
120
|
+
your report with a block addressed to the translator containing the exact
|
|
121
|
+
phrases that need work and your suggested fix, so the draft takes another
|
|
122
|
+
pass:
|
|
123
|
+
|
|
124
|
+
<swarm-send to="translator">
|
|
125
|
+
Lines 12 and 19 still read literally -- "open the door" should be the
|
|
126
|
+
idiomatic "let them in". Also the {count} placeholder was dropped.
|
|
127
|
+
</swarm-send>
|
|
128
|
+
|
|
129
|
+
If your verdict is FAITHFUL, just report it and finish -- nothing is sent
|
|
130
|
+
back, and the pipeline stops.
|
|
131
|
+
|
|
132
|
+
Converge; do not loop forever. Only send back concrete, meaning-changing
|
|
133
|
+
errors -- accept small stylistic nits rather than bouncing the draft over
|
|
134
|
+
them. If you have already sent it back twice and the same class of problem
|
|
135
|
+
survives, stop looping: report a final verdict of NEEDS HUMAN REVIEW with
|
|
136
|
+
the outstanding issues, and do not send another block to the translator.
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# Multi-language broadcast -- one source, several translations in parallel.
|
|
3
|
+
#
|
|
4
|
+
# agentainer up -c examples/multi-language-broadcast.yaml
|
|
5
|
+
# agentainer send --to translator "Translate ./docs/quickstart.md to es, fr, de."
|
|
6
|
+
#
|
|
7
|
+
# Shape: a fan-out built on `broadcast`, not `forward_responses_to`. One
|
|
8
|
+
# TRANSLATOR holds the source and fans it out to every reviewer at once; the
|
|
9
|
+
# REVIEWERS each own one language and report back to a single CONSOLIDATOR,
|
|
10
|
+
# who compiles the finished set and broadcasts it back to the translator.
|
|
11
|
+
#
|
|
12
|
+
# translator
|
|
13
|
+
# | (broadcast source to all)
|
|
14
|
+
# v
|
|
15
|
+
# +-------+--------+
|
|
16
|
+
# | | |
|
|
17
|
+
# es-rev fr-rev de-rev
|
|
18
|
+
# | | |
|
|
19
|
+
# +--- consolidator ---+ (each reviewer replies to the consolidator)
|
|
20
|
+
# |
|
|
21
|
+
# translator (consolidator broadcasts the compiled piece back)
|
|
22
|
+
#
|
|
23
|
+
# `broadcast` is the point of this example: the translator reaches several
|
|
24
|
+
# peers with one message and does not care who is busy. Every link is two-way,
|
|
25
|
+
# and the reviewers never talk to each other -- all coordination runs through
|
|
26
|
+
# the translator and the consolidator.
|
|
27
|
+
# =============================================================================
|
|
28
|
+
|
|
29
|
+
swarm:
|
|
30
|
+
name: l10n-multi
|
|
31
|
+
root: ./l10n-multi-workspace
|
|
32
|
+
session_prefix: "ml-"
|
|
33
|
+
|
|
34
|
+
# Broadcasts don't auto-forward, so one hop is all the guard ever needs.
|
|
35
|
+
max_forward_hops: 1
|
|
36
|
+
|
|
37
|
+
agents:
|
|
38
|
+
|
|
39
|
+
- name: translator
|
|
40
|
+
type: claude
|
|
41
|
+
command: "claude --dangerously-skip-permissions"
|
|
42
|
+
|
|
43
|
+
# Can reach everyone: broadcasts the source out, and receives the compiled
|
|
44
|
+
# piece back from the consolidator.
|
|
45
|
+
can_talk_to: ["es-rev", "fr-rev", "de-rev", "consolidator"]
|
|
46
|
+
|
|
47
|
+
first_prompt: |
|
|
48
|
+
You are the TRANSLATOR and keeper of the source. You start each job with
|
|
49
|
+
one source document and a list of target languages.
|
|
50
|
+
|
|
51
|
+
Produce a single faithful, natural rendering of the source per language, as a
|
|
52
|
+
native writer would actually say it -- not a word-for-word transposition.
|
|
53
|
+
Preserve exactly: meaning and tone, markup, code blocks, and placeholders
|
|
54
|
+
like {name} or %s.
|
|
55
|
+
|
|
56
|
+
Then fan it out: broadcast the source text to every reviewer at once so they
|
|
57
|
+
each translate their own language in parallel. Use:
|
|
58
|
+
|
|
59
|
+
<swarm-broadcast>
|
|
60
|
+
Source (English):
|
|
61
|
+
...
|
|
62
|
+
Translate to your language only. es-rev -> Spanish, fr-rev -> French,
|
|
63
|
+
de-rev -> German.
|
|
64
|
+
</swarm-broadcast>
|
|
65
|
+
|
|
66
|
+
Wait for the consolidator to return the compiled set, then save each
|
|
67
|
+
language next to the source (e.g. quickstart.es.md) and finish.
|
|
68
|
+
|
|
69
|
+
- name: es-rev
|
|
70
|
+
type: claude
|
|
71
|
+
command: "claude --dangerously-skip-permissions"
|
|
72
|
+
can_talk_to: ["consolidator", "translator"]
|
|
73
|
+
first_prompt: |
|
|
74
|
+
You are the SPANISH reviewer. You receive a source text broadcast by the
|
|
75
|
+
translator and return a faithful, natural Spanish translation of it.
|
|
76
|
+
|
|
77
|
+
Preserve meaning, tone, markup, code blocks and placeholders exactly. Read
|
|
78
|
+
naturally; if the source language shows through, fix it. When done, reply to
|
|
79
|
+
the consolidator (not the group) with your Spanish text and any term you
|
|
80
|
+
deliberately did not translate and why.
|
|
81
|
+
|
|
82
|
+
- name: fr-rev
|
|
83
|
+
type: claude
|
|
84
|
+
command: "claude --dangerously-skip-permissions"
|
|
85
|
+
can_talk_to: ["consolidator", "translator"]
|
|
86
|
+
first_prompt: |
|
|
87
|
+
You are the FRENCH reviewer. You receive a source text broadcast by the
|
|
88
|
+
translator and return a faithful, natural French translation of it.
|
|
89
|
+
|
|
90
|
+
Preserve meaning, tone, markup, code blocks and placeholders exactly. Read
|
|
91
|
+
naturally; if the source language shows through, fix it. When done, reply to
|
|
92
|
+
the consolidator (not the group) with your French text and any term you
|
|
93
|
+
deliberately did not translate and why.
|
|
94
|
+
|
|
95
|
+
- name: de-rev
|
|
96
|
+
type: claude
|
|
97
|
+
command: "claude --dangerously-skip-permissions"
|
|
98
|
+
can_talk_to: ["consolidator", "translator"]
|
|
99
|
+
first_prompt: |
|
|
100
|
+
You are the GERMAN reviewer. You receive a source text broadcast by the
|
|
101
|
+
translator and return a faithful, natural German translation of it.
|
|
102
|
+
|
|
103
|
+
Preserve meaning, tone, markup, code blocks and placeholders exactly. Read
|
|
104
|
+
naturally; if the source language shows through, fix it. When done, reply to
|
|
105
|
+
the consolidator (not the group) with your German text and any term you
|
|
106
|
+
deliberately did not translate and why.
|
|
107
|
+
|
|
108
|
+
- name: consolidator
|
|
109
|
+
type: claude
|
|
110
|
+
command: "claude --dangerously-skip-permissions"
|
|
111
|
+
can_talk_to: ["translator", "es-rev", "fr-rev", "de-rev"]
|
|
112
|
+
first_prompt: |
|
|
113
|
+
You are the CONSOLIDATOR. You collect one translation per language from the
|
|
114
|
+
reviewers and assemble the finished set.
|
|
115
|
+
|
|
116
|
+
You will receive several replies -- keep them straight by language. Compile
|
|
117
|
+
them into one message that lists each language's text. When the set is
|
|
118
|
+
complete, broadcast it back to the translator so they can save the files:
|
|
119
|
+
|
|
120
|
+
<swarm-broadcast>
|
|
121
|
+
Compiled translations:
|
|
122
|
+
Spanish: ...
|
|
123
|
+
French: ...
|
|
124
|
+
German: ...
|
|
125
|
+
</swarm-broadcast>
|
|
126
|
+
|
|
127
|
+
Do not edit the translations; your job is to gather, not to re-translate.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# Ping-pong -- two agents trade a unit of work back and forth, in turn.
|
|
3
|
+
#
|
|
4
|
+
# 1. Point `workdir` below at the repo you want to build in.
|
|
5
|
+
# 2. agentainer validate -c examples/ping-pong.yaml
|
|
6
|
+
# 3. agentainer up -c examples/ping-pong.yaml
|
|
7
|
+
# 4. agentainer send --to runner "Build a rate limiter: N requests per window."
|
|
8
|
+
#
|
|
9
|
+
# Shape: a round-robin built on BROADCAST. This is deliberately different from
|
|
10
|
+
# tdd-pingpong.yaml, which uses `forward_responses_to` (one fixed next step):
|
|
11
|
+
# here every handoff is a broadcast that names who is up next, so the same
|
|
12
|
+
# group can rotate any number of roles in any order.
|
|
13
|
+
#
|
|
14
|
+
# runner <--> coder
|
|
15
|
+
# (each broadcasts to the group, naming the next agent in the @-tag)
|
|
16
|
+
#
|
|
17
|
+
# They share ONE checkout on purpose (that is the whole game), so `validate`
|
|
18
|
+
# will warn about the shared workdir -- expected here. The protocol, not a
|
|
19
|
+
# folder boundary, keeps them from colliding: only one holds the ball at a time.
|
|
20
|
+
# =============================================================================
|
|
21
|
+
|
|
22
|
+
swarm:
|
|
23
|
+
name: pingpong
|
|
24
|
+
root: ./pingpong-runtime # only holds logs, inboxes and swarm state
|
|
25
|
+
session_prefix: "pp-"
|
|
26
|
+
|
|
27
|
+
# Broadcasts don't auto-forward, so one hop is all the guard ever needs.
|
|
28
|
+
max_forward_hops: 1
|
|
29
|
+
|
|
30
|
+
# Never mkdir a path you typed by mistake; point at a real repo instead.
|
|
31
|
+
create_workdirs: false
|
|
32
|
+
|
|
33
|
+
defaults:
|
|
34
|
+
# Both agents build in the same tree. >>> EDIT ME <<<
|
|
35
|
+
workdir: ~/projects/scratch-lib
|
|
36
|
+
|
|
37
|
+
type: claude
|
|
38
|
+
command: "claude --dangerously-skip-permissions"
|
|
39
|
+
# They can each reach the other, so either can broadcast the handoff.
|
|
40
|
+
can_talk_to: ["runner", "coder"]
|
|
41
|
+
|
|
42
|
+
agents:
|
|
43
|
+
|
|
44
|
+
- name: runner
|
|
45
|
+
# Override: the runner starts the job and holds the spec.
|
|
46
|
+
command: "claude --dangerously-skip-permissions"
|
|
47
|
+
can_talk_to: ["coder"]
|
|
48
|
+
|
|
49
|
+
in_first_prompt_append_your_task_will_be_sent_in_the_next_prompt: true
|
|
50
|
+
|
|
51
|
+
first_prompt: |
|
|
52
|
+
You are the RUNNER. You own the task and the spec; the CODER implements
|
|
53
|
+
it. You two trade the work back and forth, exactly one of you active at a
|
|
54
|
+
time.
|
|
55
|
+
|
|
56
|
+
To hand off, broadcast to the group but name the coder explicitly as up
|
|
57
|
+
next, and sign your turn so the other agent knows who just spoke:
|
|
58
|
+
|
|
59
|
+
<swarm-broadcast>
|
|
60
|
+
@coder: your turn. Implement step 1 -- a token bucket with N
|
|
61
|
+
requests per window and a refill rate. Don't exceed the spec.
|
|
62
|
+
-- runner
|
|
63
|
+
</swarm-broadcast>
|
|
64
|
+
|
|
65
|
+
When the coder hands back ("@runner: your turn -- done, here's what I
|
|
66
|
+
built"), review it against the spec. If it meets the bar, broadcast a
|
|
67
|
+
final "done" and stop. If not, broadcast the next instruction to the
|
|
68
|
+
coder. Never both work at once; the ball is always with one of you.
|
|
69
|
+
|
|
70
|
+
- name: coder
|
|
71
|
+
command: "claude --dangerously-skip-permissions"
|
|
72
|
+
can_talk_to: ["runner"]
|
|
73
|
+
|
|
74
|
+
first_prompt: |
|
|
75
|
+
You are the CODER. You implement what the RUNNER specifies, one step at a
|
|
76
|
+
time, and hand each step back for review.
|
|
77
|
+
|
|
78
|
+
When the runner broadcasts a turn ending in "@coder: your turn", do exactly
|
|
79
|
+
that step -- no more, no freelancing. When done, broadcast back naming the
|
|
80
|
+
runner and reporting what you built:
|
|
81
|
+
|
|
82
|
+
<swarm-broadcast>
|
|
83
|
+
@runner: your turn -- done. Token bucket with N=100 per 60s window,
|
|
84
|
+
lazy refill on read. Tests pass.
|
|
85
|
+
-- coder
|
|
86
|
+
</swarm-broadcast>
|
|
87
|
+
|
|
88
|
+
Wait for the runner's next instruction or a "done". Do not start the next
|
|
89
|
+
step on your own, and do not edit while the runner holds the ball.
|