agentainer 0.1.7 → 2.0.1
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 +248 -677
- package/agentainer +16 -18
- package/agentainer.example.yaml +86 -0
- package/bin/agentainer.js +9 -8
- package/examples/academic-coauthor.yaml +123 -0
- package/examples/accessibility-audit.yaml +152 -0
- package/examples/affiliate-product-reviews.yaml +106 -0
- package/examples/api-design.yaml +157 -0
- package/examples/app-store-optimization.yaml +108 -0
- package/examples/brainstorm.yaml +27 -128
- package/examples/brand-voice-style-guide.yaml +109 -0
- package/examples/bug-hunt.yaml +51 -96
- package/examples/candidate-screen.yaml +122 -0
- package/examples/case-study-writer.yaml +100 -0
- package/examples/changelog-release-notes.yaml +114 -0
- package/examples/chatbot-builder.yaml +138 -0
- package/examples/code-review.yaml +73 -0
- package/examples/comparison-guide-writer.yaml +106 -0
- package/examples/competitive-intel.yaml +126 -0
- package/examples/content-studio.yaml +91 -0
- package/examples/course-creator.yaml +133 -0
- package/examples/customer-support-triage.yaml +118 -0
- package/examples/daily-briefing.yaml +119 -0
- package/examples/data-pipeline-builder.yaml +135 -0
- package/examples/debate.yaml +16 -90
- package/examples/design-system.yaml +138 -0
- package/examples/ebook-generator.yaml +90 -0
- package/examples/ecommerce-listing-optimizer.yaml +126 -0
- package/examples/email-newsletter.yaml +103 -0
- package/examples/faq-knowledge-sync.yaml +107 -0
- package/examples/game-design.yaml +122 -0
- package/examples/glossary-term-writer.yaml +103 -0
- package/examples/incident-response.yaml +52 -109
- package/examples/knowledge-base.yaml +115 -0
- package/examples/landing-page-converter.yaml +103 -0
- package/examples/legal-contract-review.yaml +118 -0
- package/examples/linkedin-ghostwriter.yaml +93 -0
- package/examples/localization.yaml +56 -123
- package/examples/meeting-notes.yaml +111 -0
- package/examples/migration-planner.yaml +127 -0
- package/examples/onboarding-buddy.yaml +111 -0
- package/examples/performance-audit.yaml +123 -0
- package/examples/podcast-production.yaml +117 -0
- package/examples/postmortem.yaml +119 -0
- package/examples/pr-review-gate.yaml +123 -0
- package/examples/press-release-wire.yaml +96 -0
- package/examples/product-spec.yaml +107 -0
- package/examples/prompt-engineering-lab.yaml +109 -0
- package/examples/quickstart.yaml +48 -0
- package/examples/rag-builder.yaml +145 -0
- package/examples/refactor-planner.yaml +127 -0
- package/examples/research.yaml +25 -0
- package/examples/resume-tailor.yaml +116 -0
- package/examples/rfp-response.yaml +124 -0
- package/examples/sales-coach.yaml +123 -0
- package/examples/security-audit.yaml +120 -0
- package/examples/seo-audit-and-fix.yaml +138 -0
- package/examples/seo-content-factory.yaml +103 -0
- package/examples/social-media.yaml +103 -0
- package/examples/software-company.yaml +71 -128
- package/examples/startup-validator.yaml +115 -0
- package/examples/tdd-pingpong.yaml +36 -68
- package/examples/technical-documentation.yaml +112 -0
- package/examples/test-factory.yaml +114 -0
- package/examples/tutorial-howto-creator.yaml +111 -0
- package/examples/twitter-x-thread-factory.yaml +91 -0
- package/examples/white-paper-research.yaml +96 -0
- package/examples/writers-room.yaml +49 -111
- package/examples/youtube-script-studio.yaml +107 -0
- package/hooks/claude_stop.sh +5 -3
- package/hooks/codex_notify.sh +4 -3
- package/lib/cli.py +933 -0
- package/lib/config.py +267 -308
- package/lib/hooks.py +246 -0
- package/lib/lock.py +75 -0
- package/lib/log.py +64 -0
- package/lib/mail.py +699 -0
- package/lib/minyaml.py +1 -39
- package/lib/reconcile.py +544 -0
- package/lib/sessions.py +223 -0
- package/lib/supervisor.py +216 -0
- package/lib/telegram.py +372 -0
- package/lib/tmux.py +355 -0
- package/lib/turn.py +167 -0
- package/lib/ui.py +1219 -0
- package/llms.txt +145 -429
- package/package.json +9 -7
- package/scripts/check-deps.js +18 -61
- package/ui/app.js +1136 -0
- package/ui/index.html +404 -0
- package/agents.example.yaml +0 -257
- package/examples/code-review-broadcast.yaml +0 -109
- package/examples/existing-repo.yaml +0 -74
- package/examples/multi-language-broadcast.yaml +0 -127
- package/examples/ping-pong.yaml +0 -89
- package/examples/red-team.yaml +0 -117
- package/examples/research-swarm.yaml +0 -129
- package/lib/swarm.py +0 -2461
package/ui/index.html
ADDED
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
6
|
+
<meta name="color-scheme" content="light dark" />
|
|
7
|
+
<title>Agentainer</title>
|
|
8
|
+
<style>
|
|
9
|
+
/* ---- design tokens (light + dark) ------------------------------------ */
|
|
10
|
+
:root {
|
|
11
|
+
color-scheme: light dark;
|
|
12
|
+
--bg: #f4f6f9;
|
|
13
|
+
--surface: #ffffff;
|
|
14
|
+
--surface-2: #eef1f5;
|
|
15
|
+
--border: #e2e6ec;
|
|
16
|
+
--text: #171a1f;
|
|
17
|
+
--muted: #667085;
|
|
18
|
+
--accent: #2563eb;
|
|
19
|
+
--accent-fg: #ffffff;
|
|
20
|
+
--accent-soft: #e6efff;
|
|
21
|
+
--ok-bg: #e3f6e9; --ok-fg: #157a3c;
|
|
22
|
+
--busy-bg: #fdf0d5; --busy-fg: #9a6b00;
|
|
23
|
+
--no-bg: #fde2e1; --no-fg: #b4231d;
|
|
24
|
+
--shadow: 0 1px 2px rgba(16,24,40,.06), 0 1px 3px rgba(16,24,40,.10);
|
|
25
|
+
--shadow-lg: 0 8px 28px rgba(16,24,40,.18);
|
|
26
|
+
--radius: 14px;
|
|
27
|
+
--radius-sm: 10px;
|
|
28
|
+
}
|
|
29
|
+
@media (prefers-color-scheme: dark) {
|
|
30
|
+
:root {
|
|
31
|
+
--bg: #0d0f13;
|
|
32
|
+
--surface: #161a21;
|
|
33
|
+
--surface-2: #1e232c;
|
|
34
|
+
--border: #262c37;
|
|
35
|
+
--text: #e7eaee;
|
|
36
|
+
--muted: #8b93a1;
|
|
37
|
+
--accent: #4f8cff;
|
|
38
|
+
--accent-fg: #0b1220;
|
|
39
|
+
--accent-soft: #17233b;
|
|
40
|
+
--ok-bg: #16351f; --ok-fg: #7ee29a;
|
|
41
|
+
--busy-bg: #3a3416; --busy-fg: #ffd97a;
|
|
42
|
+
--no-bg: #3a1d1d; --no-fg: #ff9b9b;
|
|
43
|
+
--shadow: 0 1px 2px rgba(0,0,0,.4);
|
|
44
|
+
--shadow-lg: 0 12px 40px rgba(0,0,0,.55);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
* { box-sizing: border-box; }
|
|
49
|
+
/* The `hidden` attribute must win over class-level `display` rules (e.g. the
|
|
50
|
+
login card's `.center { display: grid }`), or hiding it visually no-ops. */
|
|
51
|
+
[hidden] { display: none !important; }
|
|
52
|
+
html, body { height: 100%; }
|
|
53
|
+
body {
|
|
54
|
+
margin: 0;
|
|
55
|
+
font: 15px/1.55 system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
56
|
+
background: var(--bg);
|
|
57
|
+
color: var(--text);
|
|
58
|
+
-webkit-font-smoothing: antialiased;
|
|
59
|
+
overflow-x: hidden;
|
|
60
|
+
}
|
|
61
|
+
button, input, textarea, select { font: inherit; color: inherit; }
|
|
62
|
+
button { cursor: pointer; }
|
|
63
|
+
a { color: var(--accent); }
|
|
64
|
+
|
|
65
|
+
/* ---- app bar --------------------------------------------------------- */
|
|
66
|
+
header#bar {
|
|
67
|
+
position: sticky; top: 0; z-index: 20;
|
|
68
|
+
display: flex; align-items: center; gap: .75rem;
|
|
69
|
+
padding: .6rem max(.9rem, env(safe-area-inset-left)) .6rem max(.9rem, env(safe-area-inset-left));
|
|
70
|
+
background: color-mix(in srgb, var(--surface) 88%, transparent);
|
|
71
|
+
backdrop-filter: saturate(1.4) blur(10px);
|
|
72
|
+
border-bottom: 1px solid var(--border);
|
|
73
|
+
}
|
|
74
|
+
.brand { display: flex; align-items: center; gap: .55rem; font-weight: 700; letter-spacing: -.01em; }
|
|
75
|
+
.brand .dot {
|
|
76
|
+
width: 26px; height: 26px; border-radius: 8px; flex: 0 0 auto;
|
|
77
|
+
background: linear-gradient(135deg, var(--accent), #7c3aed);
|
|
78
|
+
display: grid; place-items: center; color: #fff; font-size: 15px;
|
|
79
|
+
box-shadow: var(--shadow);
|
|
80
|
+
}
|
|
81
|
+
.brand small { display: block; font-weight: 500; color: var(--muted); font-size: .72rem; margin-top: -2px; }
|
|
82
|
+
header#bar .spacer { flex: 1 1 auto; }
|
|
83
|
+
.navbtn {
|
|
84
|
+
background: transparent; border: 1px solid transparent; color: var(--muted);
|
|
85
|
+
padding: .4rem .7rem; border-radius: 999px; font-weight: 600; font-size: .9rem;
|
|
86
|
+
}
|
|
87
|
+
.navbtn.active { color: var(--text); background: var(--surface-2); border-color: var(--border); }
|
|
88
|
+
.navbtn:hover { color: var(--text); }
|
|
89
|
+
.navbtn { position: relative; }
|
|
90
|
+
|
|
91
|
+
/* availability switch */
|
|
92
|
+
.avail { display: inline-flex; align-items: center; gap: .5rem; }
|
|
93
|
+
.avail .lbl { font-size: .82rem; color: var(--muted); white-space: nowrap; }
|
|
94
|
+
.switch { position: relative; width: 42px; height: 24px; flex: 0 0 auto; }
|
|
95
|
+
.switch input { opacity: 0; width: 0; height: 0; position: absolute; }
|
|
96
|
+
.switch .track {
|
|
97
|
+
position: absolute; inset: 0; border-radius: 999px; background: var(--surface-2);
|
|
98
|
+
border: 1px solid var(--border); transition: background .18s;
|
|
99
|
+
}
|
|
100
|
+
.switch .knob {
|
|
101
|
+
position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; border-radius: 50%;
|
|
102
|
+
background: #fff; box-shadow: var(--shadow); transition: transform .18s;
|
|
103
|
+
}
|
|
104
|
+
.switch input:checked + .track { background: var(--ok-fg); border-color: var(--ok-fg); }
|
|
105
|
+
.switch input:checked + .track + .knob { transform: translateX(18px); }
|
|
106
|
+
|
|
107
|
+
/* ---- layout ---------------------------------------------------------- */
|
|
108
|
+
main { max-width: 1080px; margin: 0 auto; padding: 1rem max(.9rem, env(safe-area-inset-left)) 3rem; }
|
|
109
|
+
.muted { color: var(--muted); }
|
|
110
|
+
.banner { color: var(--no-fg); min-height: 1.1rem; margin: .2rem 0; font-size: .9rem; }
|
|
111
|
+
.center { min-height: 60vh; display: grid; place-items: center; }
|
|
112
|
+
|
|
113
|
+
.card {
|
|
114
|
+
background: var(--surface); border: 1px solid var(--border);
|
|
115
|
+
border-radius: var(--radius); box-shadow: var(--shadow);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* login */
|
|
119
|
+
#login .card { padding: 1.5rem; width: min(420px, 92vw); }
|
|
120
|
+
#login h2 { margin: .2rem 0 .3rem; }
|
|
121
|
+
input.field, textarea.field, select.field {
|
|
122
|
+
width: 100%; background: var(--surface-2); border: 1px solid var(--border);
|
|
123
|
+
border-radius: var(--radius-sm); padding: .6rem .7rem;
|
|
124
|
+
}
|
|
125
|
+
input.field:focus, textarea.field:focus, select.field:focus {
|
|
126
|
+
outline: 2px solid color-mix(in srgb, var(--accent) 45%, transparent); outline-offset: 0;
|
|
127
|
+
border-color: var(--accent);
|
|
128
|
+
}
|
|
129
|
+
.btn {
|
|
130
|
+
background: var(--accent); color: var(--accent-fg); border: 1px solid transparent;
|
|
131
|
+
padding: .55rem .9rem; border-radius: var(--radius-sm); font-weight: 650;
|
|
132
|
+
box-shadow: var(--shadow);
|
|
133
|
+
}
|
|
134
|
+
.btn:hover { filter: brightness(1.06); }
|
|
135
|
+
.btn.ghost { background: var(--surface-2); color: var(--text); border-color: var(--border); box-shadow: none; }
|
|
136
|
+
.btn.danger { background: var(--no-bg); color: var(--no-fg); box-shadow: none; }
|
|
137
|
+
.btn.sm { padding: .35rem .6rem; font-size: .85rem; }
|
|
138
|
+
|
|
139
|
+
/* pills */
|
|
140
|
+
.pill { display: inline-flex; align-items: center; gap: .3rem; padding: .12rem .5rem; border-radius: 999px; font-size: .74rem; font-weight: 600; }
|
|
141
|
+
.pill.ok { background: var(--ok-bg); color: var(--ok-fg); }
|
|
142
|
+
.pill.busy { background: var(--busy-bg); color: var(--busy-fg); }
|
|
143
|
+
.pill.no { background: var(--no-bg); color: var(--no-fg); }
|
|
144
|
+
.pill.mute { background: var(--surface-2); color: var(--muted); }
|
|
145
|
+
/* truthful state pills */
|
|
146
|
+
.pill.st-working { background: var(--ok-bg); color: var(--ok-fg); }
|
|
147
|
+
.pill.st-waiting { background: var(--surface-2); color: var(--muted); }
|
|
148
|
+
.pill.st-attention { background: var(--busy-bg); color: var(--busy-fg); }
|
|
149
|
+
.pill.st-stalled { background: var(--no-bg); color: var(--no-fg); }
|
|
150
|
+
.pill.st-stopped { background: var(--surface-2); color: var(--muted); opacity: .7; }
|
|
151
|
+
.dotpulse { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
|
|
152
|
+
.pill.st-working .dotpulse { animation: dotpulse 1.2s ease-in-out infinite; }
|
|
153
|
+
@keyframes dotpulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .3; transform: scale(.6); } }
|
|
154
|
+
@media (prefers-reduced-motion: reduce) { .pill.st-working .dotpulse { animation: none; } }
|
|
155
|
+
.pill.upbtn { border: 1px solid var(--accent); background: transparent; color: var(--accent); cursor: pointer; font-family: inherit; }
|
|
156
|
+
.pill.upbtn:hover:not(:disabled) { background: var(--accent); color: #fff; }
|
|
157
|
+
.pill.upbtn:disabled, .pill.downbtn:disabled { opacity: .6; cursor: default; }
|
|
158
|
+
.pill.downbtn { border: 1px solid var(--no-fg); background: transparent; color: var(--no-fg); cursor: pointer; font-family: inherit; }
|
|
159
|
+
.pill.downbtn:hover:not(:disabled) { background: var(--no-fg); color: #fff; }
|
|
160
|
+
/* stalled-recovery quick actions (Esc / Restart) on a card */
|
|
161
|
+
.pill.recover { border: 1px solid var(--border); background: var(--surface-2); color: var(--text); cursor: pointer; font-family: inherit; }
|
|
162
|
+
.pill.recover:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
|
|
163
|
+
.pill.recover:disabled { opacity: .6; cursor: default; }
|
|
164
|
+
|
|
165
|
+
/* connection-honesty indicator in the app bar */
|
|
166
|
+
.connind {
|
|
167
|
+
display: inline-flex; align-items: center; gap: .35rem; white-space: nowrap;
|
|
168
|
+
font-size: .76rem; font-weight: 650; padding: .2rem .55rem; border-radius: 999px;
|
|
169
|
+
border: 1px solid var(--border); background: var(--surface-2);
|
|
170
|
+
font-variant-numeric: tabular-nums;
|
|
171
|
+
}
|
|
172
|
+
.connind.live { color: var(--ok-fg); border-color: color-mix(in srgb, var(--ok-fg) 40%, var(--border)); }
|
|
173
|
+
.connind.stale { color: var(--busy-fg); border-color: color-mix(in srgb, var(--busy-fg) 45%, var(--border)); }
|
|
174
|
+
|
|
175
|
+
/* avatar */
|
|
176
|
+
.avatar {
|
|
177
|
+
width: 40px; height: 40px; border-radius: 12px; flex: 0 0 auto; display: grid; place-items: center;
|
|
178
|
+
font-weight: 700; color: #fff; font-size: .95rem;
|
|
179
|
+
}
|
|
180
|
+
.avatar.sm { width: 32px; height: 32px; border-radius: 10px; font-size: .82rem; }
|
|
181
|
+
|
|
182
|
+
/* ---- agents overview grid ------------------------------------------- */
|
|
183
|
+
.grid { display: grid; gap: .9rem; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
|
|
184
|
+
.agentcard { padding: 1rem; display: flex; flex-direction: column; gap: .7rem; cursor: pointer; transition: transform .12s, box-shadow .12s, border-color .12s; }
|
|
185
|
+
.agentcard:hover { transform: translateY(-2px); box-shadow: var(--shadow-lg); border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); }
|
|
186
|
+
.agentcard .top { display: flex; align-items: center; gap: .7rem; }
|
|
187
|
+
.agentcard .name { font-weight: 700; }
|
|
188
|
+
.agentcard .role { color: var(--muted); font-size: .86rem; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; min-height: 2.6em; }
|
|
189
|
+
.agentcard .meta { display: flex; flex-wrap: wrap; gap: .4rem; }
|
|
190
|
+
.sectiontitle { display: flex; align-items: center; justify-content: space-between; gap: .6rem; margin: .3rem 0 .8rem; flex-wrap: wrap; }
|
|
191
|
+
.sectiontitle h2 { margin: 0; font-size: 1.05rem; }
|
|
192
|
+
.agents-tools { display: flex; align-items: center; gap: .8rem; flex-wrap: wrap; }
|
|
193
|
+
.tgl { display: inline-flex; align-items: center; gap: .3rem; font-size: .82rem; color: var(--muted); cursor: pointer; white-space: nowrap; }
|
|
194
|
+
.tgl input { margin: 0; }
|
|
195
|
+
.rateline { margin-left: auto; font-size: .74rem; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
196
|
+
|
|
197
|
+
/* onboarding: template picker (empty state) */
|
|
198
|
+
.tpl-intro { margin: .2rem 0 .7rem; }
|
|
199
|
+
.tplgrid { display: grid; gap: .8rem; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
|
|
200
|
+
.tpl { text-align: left; padding: .9rem; display: flex; flex-direction: column; gap: .3rem; cursor: pointer; transition: transform .12s, box-shadow .12s, border-color .12s; }
|
|
201
|
+
.tpl:hover:not(:disabled) { transform: translateY(-2px); box-shadow: var(--shadow-lg); border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); }
|
|
202
|
+
.tpl:disabled { opacity: .6; cursor: default; }
|
|
203
|
+
.tpl-title { font-weight: 700; }
|
|
204
|
+
.tpl-sum { font-size: .84rem; }
|
|
205
|
+
.tpl-meta { font-size: .74rem; }
|
|
206
|
+
|
|
207
|
+
/* ---- mail app -------------------------------------------------------- */
|
|
208
|
+
.mailhead { display: flex; align-items: center; gap: .6rem; margin-bottom: .8rem; flex-wrap: wrap; }
|
|
209
|
+
.mailhead .who { display: flex; align-items: center; gap: .6rem; }
|
|
210
|
+
.mailhead h2 { margin: 0; font-size: 1.05rem; }
|
|
211
|
+
.mail { display: grid; grid-template-columns: 300px 1fr; gap: .9rem; align-items: start; }
|
|
212
|
+
.contacts { padding: .4rem; overflow: hidden; }
|
|
213
|
+
.contact {
|
|
214
|
+
display: flex; gap: .6rem; align-items: center; padding: .55rem .55rem; border-radius: var(--radius-sm);
|
|
215
|
+
cursor: pointer; border: 1px solid transparent;
|
|
216
|
+
}
|
|
217
|
+
.contact:hover { background: var(--surface-2); }
|
|
218
|
+
.contact.active { background: var(--accent-soft); border-color: color-mix(in srgb, var(--accent) 35%, var(--border)); }
|
|
219
|
+
.contact .info { min-width: 0; flex: 1 1 auto; }
|
|
220
|
+
.contact .cn { display: flex; justify-content: space-between; gap: .4rem; align-items: baseline; }
|
|
221
|
+
.contact .cn b { font-weight: 650; }
|
|
222
|
+
.contact .cn .t { color: var(--muted); font-size: .72rem; white-space: nowrap; }
|
|
223
|
+
.contact .prev { color: var(--muted); font-size: .82rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
224
|
+
.badge { background: var(--accent); color: var(--accent-fg); border-radius: 999px; font-size: .7rem; font-weight: 700; padding: .05rem .42rem; }
|
|
225
|
+
|
|
226
|
+
.thread { display: flex; flex-direction: column; min-height: 60vh; }
|
|
227
|
+
.thread .scroll { padding: 1rem; display: flex; flex-direction: column; gap: .7rem; overflow-y: auto; flex: 1 1 auto; }
|
|
228
|
+
.msg { max-width: 78%; padding: .55rem .75rem; border-radius: 14px; box-shadow: var(--shadow); word-wrap: break-word; overflow-wrap: anywhere; }
|
|
229
|
+
.msg .m-head { font-size: .68rem; color: var(--muted); margin-bottom: .2rem; display: flex; gap: .5rem; }
|
|
230
|
+
/* rendered markdown inside a bubble */
|
|
231
|
+
.msg .m-body > :first-child { margin-top: 0; }
|
|
232
|
+
.msg .m-body > :last-child { margin-bottom: 0; }
|
|
233
|
+
.msg p { margin: 0 0 .45rem; }
|
|
234
|
+
.msg .md-h { margin: .4rem 0 .3rem; font-size: 1rem; line-height: 1.3; }
|
|
235
|
+
.msg ul, .msg ol { margin: .2rem 0 .45rem; padding-left: 1.25rem; }
|
|
236
|
+
.msg li { margin: .1rem 0; }
|
|
237
|
+
.msg code { background: rgba(127,127,127,.18); padding: .05rem .3rem; border-radius: 5px; font: .85em ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
|
|
238
|
+
.msg pre.md-pre { background: rgba(127,127,127,.16); padding: .5rem .6rem; border-radius: 8px; overflow-x: auto; margin: .35rem 0; }
|
|
239
|
+
.msg pre.md-pre code { background: none; padding: 0; }
|
|
240
|
+
.msg blockquote { margin: .3rem 0; padding-left: .6rem; border-left: 3px solid rgba(127,127,127,.4); opacity: .9; }
|
|
241
|
+
.msg a { color: inherit; text-decoration: underline; }
|
|
242
|
+
.msg.out code, .msg.out pre.md-pre { background: rgba(255,255,255,.2); }
|
|
243
|
+
.m-more { display: block; margin-top: .3rem; padding: 0; background: none; border: none; cursor: pointer; font: inherit; font-size: .72rem; color: var(--accent); text-decoration: underline; opacity: .85; }
|
|
244
|
+
.m-more:hover { opacity: 1; }
|
|
245
|
+
.msg.out .m-more { color: color-mix(in srgb, var(--accent-fg) 85%, transparent); }
|
|
246
|
+
.m-status { font-size: .66rem; margin-top: .25rem; text-align: right; color: var(--muted); letter-spacing: .01em; }
|
|
247
|
+
.msg.out .m-status { color: color-mix(in srgb, var(--accent-fg) 78%, transparent); }
|
|
248
|
+
.m-status.s-read { color: var(--ok-fg); }
|
|
249
|
+
.msg.out .m-status.s-read { color: color-mix(in srgb, var(--accent-fg) 92%, var(--ok-fg)); }
|
|
250
|
+
.msg.in { align-self: flex-start; background: var(--surface-2); border-bottom-left-radius: 5px; }
|
|
251
|
+
.msg.out { align-self: flex-end; background: var(--accent); color: var(--accent-fg); border-bottom-right-radius: 5px; }
|
|
252
|
+
.msg.out .m-head { color: color-mix(in srgb, var(--accent-fg) 75%, transparent); }
|
|
253
|
+
.msg.system { align-self: center; background: transparent; border: 1px dashed var(--border); color: var(--muted); font-size: .85rem; box-shadow: none; max-width: 90%; }
|
|
254
|
+
.empty { color: var(--muted); text-align: center; padding: 2rem 1rem; }
|
|
255
|
+
|
|
256
|
+
.compose { border-top: 1px solid var(--border); padding: .7rem; display: flex; gap: .5rem; align-items: flex-end; }
|
|
257
|
+
.compose textarea { min-height: 44px; max-height: 40vh; resize: vertical; }
|
|
258
|
+
.composenote { padding: .7rem; border-top: 1px solid var(--border); color: var(--muted); font-size: .85rem; }
|
|
259
|
+
|
|
260
|
+
/* terminal panel */
|
|
261
|
+
.terminal { margin-top: .9rem; padding: .8rem; }
|
|
262
|
+
.terminal .thead { display: flex; align-items: center; justify-content: space-between; margin-bottom: .5rem; gap: .5rem; }
|
|
263
|
+
pre.pane {
|
|
264
|
+
background: #0b0d11; color: #cdd6e4; border: 1px solid var(--border); border-radius: var(--radius-sm);
|
|
265
|
+
padding: .7rem; max-height: 42vh; overflow: auto; white-space: pre; font: 12.5px/1.45 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
266
|
+
}
|
|
267
|
+
pre.pane.wrap { white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-word; }
|
|
268
|
+
.terminal .thead .wrapchk { margin-right: auto; display: flex; align-items: center; gap: .35rem; font-size: .8rem; color: var(--muted); cursor: pointer; white-space: nowrap; }
|
|
269
|
+
.terminal .thead .wrapchk input { margin: 0; }
|
|
270
|
+
.keyrow { display: flex; flex-wrap: wrap; gap: .35rem; margin-top: .5rem; }
|
|
271
|
+
.keybtn {
|
|
272
|
+
font: 600 .78rem/1 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
273
|
+
padding: .34rem .55rem; border: 1px solid var(--border); border-radius: var(--radius-sm);
|
|
274
|
+
background: var(--surface-2); color: var(--text); cursor: pointer; min-width: 2.1rem;
|
|
275
|
+
}
|
|
276
|
+
.keybtn:hover { background: var(--surface); border-color: var(--accent); }
|
|
277
|
+
.keybtn:active { transform: translateY(1px); }
|
|
278
|
+
.typerow { display: flex; gap: .5rem; margin-top: .5rem; }
|
|
279
|
+
|
|
280
|
+
/* ---- settings -------------------------------------------------------- */
|
|
281
|
+
.settings { display: flex; flex-direction: column; gap: 1rem; }
|
|
282
|
+
.formgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: .8rem; }
|
|
283
|
+
.fld { display: flex; flex-direction: column; gap: .3rem; }
|
|
284
|
+
.fld label { font-size: .8rem; color: var(--muted); font-weight: 600; }
|
|
285
|
+
.panel { padding: 1rem; }
|
|
286
|
+
.panel h3 { margin: 0 0 .2rem; }
|
|
287
|
+
.agentrow { display: flex; align-items: center; gap: .7rem; padding: .6rem .2rem; border-bottom: 1px solid var(--border); }
|
|
288
|
+
.agentrow:last-child { border-bottom: none; }
|
|
289
|
+
.agentrow .info { flex: 1 1 auto; min-width: 0; }
|
|
290
|
+
.row { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; }
|
|
291
|
+
.rowend { display: flex; gap: .5rem; justify-content: flex-end; margin-top: .6rem; }
|
|
292
|
+
|
|
293
|
+
.toast {
|
|
294
|
+
position: fixed; left: 50%; bottom: 1.3rem; transform: translateX(-50%);
|
|
295
|
+
background: var(--text); color: var(--bg); padding: .55rem .9rem; border-radius: 999px;
|
|
296
|
+
box-shadow: var(--shadow-lg); font-size: .88rem; z-index: 50; opacity: 0; transition: opacity .2s, transform .2s;
|
|
297
|
+
pointer-events: none; max-width: 90vw;
|
|
298
|
+
}
|
|
299
|
+
.toast.show { opacity: 1; transform: translateX(-50%) translateY(-4px); }
|
|
300
|
+
|
|
301
|
+
/* modal */
|
|
302
|
+
.modal-back { position: fixed; inset: 0; background: rgba(6,8,12,.55); display: grid; place-items: center; z-index: 40; padding: 1rem; }
|
|
303
|
+
.modal { width: min(560px, 96vw); max-height: 90vh; overflow: auto; padding: 1.2rem; }
|
|
304
|
+
.modal h3 { margin-top: 0; }
|
|
305
|
+
|
|
306
|
+
/* segmented tabs (Mail / Terminal) */
|
|
307
|
+
.tabs { display: inline-flex; background: var(--surface-2); border: 1px solid var(--border); border-radius: 999px; padding: 2px; }
|
|
308
|
+
.tab { border: none; background: transparent; color: var(--muted); padding: .3rem .8rem; border-radius: 999px; font-weight: 600; font-size: .88rem; }
|
|
309
|
+
.tab.active { background: var(--surface); color: var(--text); box-shadow: var(--shadow); }
|
|
310
|
+
|
|
311
|
+
/* activity timeline */
|
|
312
|
+
.timeline { display: flex; flex-direction: column; }
|
|
313
|
+
.event { display: flex; align-items: center; gap: .5rem; padding: .4rem .6rem; border-bottom: 1px solid var(--border); font-size: .88rem; flex-wrap: wrap; }
|
|
314
|
+
.event:last-child { border-bottom: none; }
|
|
315
|
+
.event .t { color: var(--muted); font-size: .74rem; min-width: 3.2rem; font-variant-numeric: tabular-nums; }
|
|
316
|
+
|
|
317
|
+
/* topology graph */
|
|
318
|
+
.edge { stroke: currentColor; stroke-width: 1.6; opacity: .55; }
|
|
319
|
+
/* live flow: an edge into a node that currently holds unread mail */
|
|
320
|
+
.edge-live { stroke: var(--accent); opacity: .95; stroke-width: 2.4; stroke-dasharray: 5 4; animation: edgeflow .6s linear infinite; }
|
|
321
|
+
@keyframes edgeflow { to { stroke-dashoffset: -9; } }
|
|
322
|
+
/* status rings, colored by the agent's live state */
|
|
323
|
+
.gring { stroke-width: 2.5; }
|
|
324
|
+
.gring-working { stroke: var(--ok-fg); animation: ringpulse 1.4s ease-in-out infinite; }
|
|
325
|
+
.gring-attention { stroke: var(--busy-fg); }
|
|
326
|
+
.gring-stalled { stroke: var(--no-fg); }
|
|
327
|
+
.gring-stopped { stroke: var(--muted); }
|
|
328
|
+
@keyframes ringpulse { 0%, 100% { opacity: .9; } 50% { opacity: .3; } }
|
|
329
|
+
@media (prefers-reduced-motion: reduce) { .edge-live, .gring-working { animation: none; } }
|
|
330
|
+
.gnode-t { fill: #fff; font-weight: 700; font-size: 11px; }
|
|
331
|
+
.gnode-l { fill: var(--muted); font-size: 10px; }
|
|
332
|
+
.gnode { cursor: pointer; }
|
|
333
|
+
.gnode circle { transition: opacity .12s; }
|
|
334
|
+
.gnode:hover circle, .gnode:focus circle { opacity: .82; }
|
|
335
|
+
.gnode:hover .gnode-l, .gnode:focus .gnode-l { fill: var(--text); }
|
|
336
|
+
.gnode:focus { outline: none; }
|
|
337
|
+
|
|
338
|
+
.hide { display: none !important; }
|
|
339
|
+
|
|
340
|
+
/* ---- responsive ------------------------------------------------------ */
|
|
341
|
+
@media (max-width: 760px) {
|
|
342
|
+
.brand small { display: none; }
|
|
343
|
+
.avail .lbl { display: none; }
|
|
344
|
+
/* keep the app bar from overflowing on phones; the banner still reports
|
|
345
|
+
a dropped connection, so the chip is redundant here. */
|
|
346
|
+
.connind { display: none; }
|
|
347
|
+
.mail { grid-template-columns: 1fr; }
|
|
348
|
+
/* On mobile show either the contacts list OR the open thread. */
|
|
349
|
+
body[data-pane="thread"] .contacts { display: none; }
|
|
350
|
+
body[data-pane="list"] .thread-wrap { display: none; }
|
|
351
|
+
.msg { max-width: 88%; }
|
|
352
|
+
main { padding: .8rem .7rem 4rem; }
|
|
353
|
+
}
|
|
354
|
+
</style>
|
|
355
|
+
</head>
|
|
356
|
+
<body data-pane="list">
|
|
357
|
+
<header id="bar">
|
|
358
|
+
<div class="brand">
|
|
359
|
+
<span class="dot">◆</span>
|
|
360
|
+
<span>Agentainer<small id="swarmMeta">control plane</small></span>
|
|
361
|
+
</div>
|
|
362
|
+
<span class="spacer"></span>
|
|
363
|
+
<span class="connind" id="connind" hidden></span>
|
|
364
|
+
<div class="avail" id="availWrap" hidden>
|
|
365
|
+
<span class="lbl" id="availLbl">You: away</span>
|
|
366
|
+
<label class="switch" title="Receive mail from agents">
|
|
367
|
+
<input type="checkbox" id="availToggle" />
|
|
368
|
+
<span class="track"></span><span class="knob"></span>
|
|
369
|
+
</label>
|
|
370
|
+
</div>
|
|
371
|
+
<nav id="nav" hidden>
|
|
372
|
+
<button class="navbtn active" data-view="agents">Agents</button>
|
|
373
|
+
<button class="navbtn" data-view="activity">Activity</button>
|
|
374
|
+
<button class="navbtn" data-view="settings">Settings</button>
|
|
375
|
+
</nav>
|
|
376
|
+
</header>
|
|
377
|
+
|
|
378
|
+
<main>
|
|
379
|
+
<div class="banner" id="banner"></div>
|
|
380
|
+
|
|
381
|
+
<!-- login -->
|
|
382
|
+
<section id="login" class="center">
|
|
383
|
+
<div class="card">
|
|
384
|
+
<h2>Connect</h2>
|
|
385
|
+
<p class="muted" style="margin-top:0">Enter the access token printed when you run <code>agentainer up</code> (also shown by <code>agentainer serve</code>).</p>
|
|
386
|
+
<div class="fld">
|
|
387
|
+
<input id="token" class="field" type="password" placeholder="UI token" autocomplete="off" />
|
|
388
|
+
</div>
|
|
389
|
+
<div class="rowend">
|
|
390
|
+
<button class="btn" id="connect">Connect</button>
|
|
391
|
+
</div>
|
|
392
|
+
</div>
|
|
393
|
+
</section>
|
|
394
|
+
|
|
395
|
+
<!-- everything below is rendered by app.js -->
|
|
396
|
+
<section id="view" hidden></section>
|
|
397
|
+
</main>
|
|
398
|
+
|
|
399
|
+
<div id="toast" class="toast"></div>
|
|
400
|
+
<div id="modalRoot"></div>
|
|
401
|
+
|
|
402
|
+
<script src="app.js"></script>
|
|
403
|
+
</body>
|
|
404
|
+
</html>
|
package/agents.example.yaml
DELETED
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
# =============================================================================
|
|
2
|
-
# Agentainer example configuration
|
|
3
|
-
#
|
|
4
|
-
# cp agents.example.yaml agents.yaml
|
|
5
|
-
# agentainer validate --show-prompts # check it without launching anything
|
|
6
|
-
# agentainer up # launch the swarm
|
|
7
|
-
#
|
|
8
|
-
# Every key is documented inline. Anything marked (optional) can be omitted.
|
|
9
|
-
# =============================================================================
|
|
10
|
-
|
|
11
|
-
swarm:
|
|
12
|
-
name: dev-swarm
|
|
13
|
-
|
|
14
|
-
# Where agent working directories are created. One folder per agent, named
|
|
15
|
-
# after the agent. Relative paths resolve against this file's directory.
|
|
16
|
-
root: ./workspace
|
|
17
|
-
|
|
18
|
-
# (optional) Create missing agent folders automatically. Default true.
|
|
19
|
-
# Set to false to point agents at directories that must already exist, so a
|
|
20
|
-
# typo in a path fails loudly instead of silently creating an empty folder.
|
|
21
|
-
create_workdirs: true
|
|
22
|
-
|
|
23
|
-
# (optional) Prefix for tmux session names. With `swarm-`, the agent named
|
|
24
|
-
# `developer` lives in the tmux session `swarm-developer`.
|
|
25
|
-
session_prefix: ""
|
|
26
|
-
|
|
27
|
-
# (optional) Timing knobs, all in milliseconds.
|
|
28
|
-
send_delay_ms: 150 # pause before pasting text into a pane
|
|
29
|
-
enter_delay_ms: 250 # pause between pasting text and pressing Enter
|
|
30
|
-
max_forward_hops: 3 # stops auto-forward loops (A -> B -> A -> ...)
|
|
31
|
-
|
|
32
|
-
# (optional) How long to keep probing an agent's input box for a response
|
|
33
|
-
# before giving up and typing the first prompt anyway. Some CLIs (Claude Code)
|
|
34
|
-
# silently discard keystrokes for several seconds partway through startup, so
|
|
35
|
-
# Agentainer waits for the input box to echo a throwaway token before typing.
|
|
36
|
-
ready_timeout_ms: 60000
|
|
37
|
-
|
|
38
|
-
# (optional) An agent is "busy" from when a message is submitted to it until its
|
|
39
|
-
# next captured turn end; senders are refused meanwhile and told to --queue or
|
|
40
|
-
# --wait. If a capture never fires (crashed CLI, bad hook) the agent would look
|
|
41
|
-
# busy forever, so after this long it is treated as idle again, with a warning.
|
|
42
|
-
busy_timeout_ms: 900000
|
|
43
|
-
|
|
44
|
-
# (optional) How messages look on the wire.
|
|
45
|
-
# tagged -- messages arrive inside <swarm-message from=".." id=".."> ... </swarm-message>,
|
|
46
|
-
# and an agent sends one by writing <swarm-send to="..."> ... </swarm-send>
|
|
47
|
-
# in its reply. No shell quoting, so multi-line bodies survive intact.
|
|
48
|
-
# plain -- the older "[swarm] message from <sender>:" header.
|
|
49
|
-
message_format: tagged
|
|
50
|
-
|
|
51
|
-
# (optional) An agent that answers a question as plain prose sends nothing: only a
|
|
52
|
-
# <swarm-send> block is delivered. When it owes a reply and its turn ends without
|
|
53
|
-
# one, Agentainer messages it explaining how to send. This is how many times.
|
|
54
|
-
max_reply_reminders: 1
|
|
55
|
-
|
|
56
|
-
# (optional) Reattach agents to their previous conversations on `up`, using the ids
|
|
57
|
-
# recorded in <root>/.swarm/sessions.yaml. Same as passing `up --resume` every time.
|
|
58
|
-
# Useful after a reboot. `up --no-resume` overrides it.
|
|
59
|
-
resume: false
|
|
60
|
-
|
|
61
|
-
# (optional) Only used by agents with `capture: pane` (gemini, hermes).
|
|
62
|
-
pane_idle_ms: 2500 # pane must be unchanged this long to count as "done"
|
|
63
|
-
pane_poll_ms: 700 # how often the watcher samples the pane
|
|
64
|
-
pane_scrollback: 400 # lines of scrollback to diff
|
|
65
|
-
|
|
66
|
-
# (optional) tmux comfort settings for when you `agentainer attach <agent>`.
|
|
67
|
-
# The default tmux scrollback (2000 lines) is too small to hold a long
|
|
68
|
-
# multi-agent conversation, so Agentainer raises it before creating sessions.
|
|
69
|
-
# mouse mode lets you wheel-scroll the backlog; press q to leave copy mode.
|
|
70
|
-
# Both are applied to the tmux server, so they also affect your other sessions.
|
|
71
|
-
tmux_history_limit: 50000 # lines of scrollback per agent pane (0 = leave tmux's default)
|
|
72
|
-
tmux_mouse: true # enable mouse wheel scrolling in the panes
|
|
73
|
-
|
|
74
|
-
# -----------------------------------------------------------------------------
|
|
75
|
-
# defaults (optional) -- applied to every agent that does not override them.
|
|
76
|
-
# -----------------------------------------------------------------------------
|
|
77
|
-
defaults:
|
|
78
|
-
type: claude
|
|
79
|
-
append_agents_that_you_can_talk_to_prompt: true
|
|
80
|
-
in_first_prompt_append_your_task_will_be_sent_in_the_next_prompt: false
|
|
81
|
-
env:
|
|
82
|
-
SWARM_DEMO: "1"
|
|
83
|
-
|
|
84
|
-
# -----------------------------------------------------------------------------
|
|
85
|
-
# agent_types (optional) -- override the built-in launch commands, or define
|
|
86
|
-
# entirely new agent types. Built-ins are: claude, codex, gemini, hermes.
|
|
87
|
-
#
|
|
88
|
-
# capture: how Agentainer learns that an agent finished a turn.
|
|
89
|
-
# hook -- the CLI can run an external program on turn completion.
|
|
90
|
-
# Supported for claude (Stop hook) and codex (notify program).
|
|
91
|
-
# pane -- no such facility: poll the tmux pane and diff it. Heuristic.
|
|
92
|
-
# none -- do not capture at all.
|
|
93
|
-
#
|
|
94
|
-
# boot_delay_ms: a grace period before Agentainer starts probing the input
|
|
95
|
-
# box. It does NOT need to cover the full startup time -- delivery of the
|
|
96
|
-
# first prompt is verified and retried, so a small value is fine.
|
|
97
|
-
# -----------------------------------------------------------------------------
|
|
98
|
-
agent_types:
|
|
99
|
-
claude:
|
|
100
|
-
command: "claude --dangerously-skip-permissions"
|
|
101
|
-
capture: hook
|
|
102
|
-
boot_delay_ms: 3000
|
|
103
|
-
codex:
|
|
104
|
-
command: "codex --yolo"
|
|
105
|
-
capture: hook
|
|
106
|
-
boot_delay_ms: 3000
|
|
107
|
-
gemini:
|
|
108
|
-
command: "gemini --yolo"
|
|
109
|
-
capture: pane
|
|
110
|
-
boot_delay_ms: 4000
|
|
111
|
-
hermes:
|
|
112
|
-
command: "hermes"
|
|
113
|
-
capture: pane
|
|
114
|
-
boot_delay_ms: 3000
|
|
115
|
-
|
|
116
|
-
# -----------------------------------------------------------------------------
|
|
117
|
-
# agents -- one tmux session and one directory each.
|
|
118
|
-
# -----------------------------------------------------------------------------
|
|
119
|
-
agents:
|
|
120
|
-
|
|
121
|
-
- name: orchestrator
|
|
122
|
-
type: claude
|
|
123
|
-
# (optional) Override the type's command, e.g. to pin a model.
|
|
124
|
-
command: "claude --dangerously-skip-permissions --model opus"
|
|
125
|
-
|
|
126
|
-
# Who this agent is allowed to message. Use "*" for "everyone else".
|
|
127
|
-
# An agent that tries to message anyone not listed here is refused.
|
|
128
|
-
can_talk_to: ["researcher", "developer", "reviewer"]
|
|
129
|
-
|
|
130
|
-
first_prompt: |
|
|
131
|
-
You are the ORCHESTRATOR of a small software team.
|
|
132
|
-
|
|
133
|
-
Your job is to break the user's goal into concrete pieces of work, hand
|
|
134
|
-
each piece to the right specialist, and assemble their answers into a
|
|
135
|
-
final result. You do not write production code yourself.
|
|
136
|
-
|
|
137
|
-
Team:
|
|
138
|
-
- researcher: investigates prior art, APIs and docs
|
|
139
|
-
- developer: writes the implementation
|
|
140
|
-
- reviewer: critiques diffs and finds bugs
|
|
141
|
-
|
|
142
|
-
Start by asking the researcher what they can find, then brief the developer.
|
|
143
|
-
|
|
144
|
-
# This agent is told its task arrives in a follow-up prompt, so it will
|
|
145
|
-
# acknowledge and wait rather than inventing work.
|
|
146
|
-
in_first_prompt_append_your_task_will_be_sent_in_the_next_prompt: true
|
|
147
|
-
|
|
148
|
-
- name: researcher
|
|
149
|
-
type: gemini
|
|
150
|
-
command: "gemini --yolo"
|
|
151
|
-
can_talk_to: ["orchestrator", "developer"]
|
|
152
|
-
|
|
153
|
-
# Whenever this agent finishes a turn, its final message is automatically
|
|
154
|
-
# relayed to these agents. Every name here must also be in can_talk_to.
|
|
155
|
-
# Leave it out (the default) to let the agent decide when to speak.
|
|
156
|
-
forward_responses_to: ["orchestrator"]
|
|
157
|
-
|
|
158
|
-
first_prompt: |
|
|
159
|
-
You are the RESEARCHER. You investigate libraries, APIs, prior art and
|
|
160
|
-
documentation, then report findings concisely with sources.
|
|
161
|
-
|
|
162
|
-
You never write production code. When you have an answer, state it plainly:
|
|
163
|
-
what exists, what it costs, and what you recommend.
|
|
164
|
-
|
|
165
|
-
- name: developer
|
|
166
|
-
type: codex
|
|
167
|
-
command: "codex --yolo"
|
|
168
|
-
can_talk_to: ["orchestrator", "reviewer"]
|
|
169
|
-
|
|
170
|
-
# (optional) Per-agent environment variables, exported into its tmux session.
|
|
171
|
-
env:
|
|
172
|
-
GIT_AUTHOR_NAME: "swarm-developer"
|
|
173
|
-
|
|
174
|
-
# (optional) Before typing the first prompt, type a throwaway token and wait
|
|
175
|
-
# for the input box to echo it back. Defaults to true; turn it off only for
|
|
176
|
-
# a command that is not an interactive TUI.
|
|
177
|
-
ready_probe: true
|
|
178
|
-
|
|
179
|
-
# (optional) Refuse incoming messages while this agent is mid-turn, so a second
|
|
180
|
-
# agent is told "developer is busy, --queue it or --wait" instead of interrupting.
|
|
181
|
-
# Needs a capture to know when a turn ends; forced off when capture: none.
|
|
182
|
-
busy_check: true
|
|
183
|
-
|
|
184
|
-
# (optional) Read <swarm-send> blocks out of this agent's replies and deliver
|
|
185
|
-
# them. Needs a capture; forced off when capture: none or message_format: plain.
|
|
186
|
-
parse_outbound_tags: true
|
|
187
|
-
|
|
188
|
-
# (optional) Nudge this agent when it owes a reply but sent nothing, or when the
|
|
189
|
-
# block it wrote could not be delivered. Off when its tags are not parsed.
|
|
190
|
-
reply_reminder: true
|
|
191
|
-
|
|
192
|
-
# (optional) How to reattach this agent to a previous conversation. `resume_args`
|
|
193
|
-
# is appended to `command`; `resume_command` replaces it outright, which you need
|
|
194
|
-
# when the command goes through an alias or wrapper. {session_id} is substituted.
|
|
195
|
-
#
|
|
196
|
-
# resume_args: "resume {session_id}" # -> codex --yolo resume <id>
|
|
197
|
-
# resume_command: "bash -ic 'mywrapper --resume {session_id}'"
|
|
198
|
-
|
|
199
|
-
first_prompt: |
|
|
200
|
-
You are the DEVELOPER. You implement what the orchestrator asks for, in
|
|
201
|
-
the working directory you were started in.
|
|
202
|
-
|
|
203
|
-
Write real, runnable code. When you finish a unit of work, send the
|
|
204
|
-
reviewer a short summary of what you changed and why, and ask for review.
|
|
205
|
-
|
|
206
|
-
- name: reviewer
|
|
207
|
-
type: claude
|
|
208
|
-
command: "claude --dangerously-skip-permissions"
|
|
209
|
-
can_talk_to: ["developer", "orchestrator"]
|
|
210
|
-
|
|
211
|
-
# (optional) Run this agent somewhere specific instead of <root>/<name>.
|
|
212
|
-
# Relative paths resolve against this file. `~` is expanded. The
|
|
213
|
-
# placeholders {name}, {root}, {swarm} and {type} are substituted, so a
|
|
214
|
-
# single `defaults.workdir` can serve every agent, e.g. "{root}/{name}-wt".
|
|
215
|
-
#
|
|
216
|
-
# Several agents may share one directory (they then see each other's edits;
|
|
217
|
-
# Agentainer warns you). Pair `create_workdir: false` with an existing
|
|
218
|
-
# project so a bad path is an error, not a new empty folder.
|
|
219
|
-
#
|
|
220
|
-
# workdir: ~/projects/acme-api
|
|
221
|
-
# create_workdir: false
|
|
222
|
-
|
|
223
|
-
# (optional) Read the prompt from a file instead of inlining it here.
|
|
224
|
-
# first_prompt_file: ./prompts/reviewer.md
|
|
225
|
-
first_prompt: |
|
|
226
|
-
You are the REVIEWER. You read the developer's changes and hunt for real
|
|
227
|
-
bugs: wrong logic, unhandled errors, race conditions, security problems.
|
|
228
|
-
|
|
229
|
-
Be specific and cite file:line. If a change is fine, say so briefly rather
|
|
230
|
-
than inventing nitpicks. Report your verdict back to the developer.
|
|
231
|
-
|
|
232
|
-
- name: scribe
|
|
233
|
-
type: hermes
|
|
234
|
-
command: "hermes"
|
|
235
|
-
|
|
236
|
-
# This agent listens only: nobody can be messaged by it, and its own
|
|
237
|
-
# responses are not captured.
|
|
238
|
-
can_talk_to: []
|
|
239
|
-
capture: none
|
|
240
|
-
|
|
241
|
-
# Turn off the auto-appended communication block, since it has no peers.
|
|
242
|
-
append_agents_that_you_can_talk_to_prompt: false
|
|
243
|
-
|
|
244
|
-
first_prompt: |
|
|
245
|
-
You are the SCRIBE. Keep a running changelog of the project in NOTES.md.
|
|
246
|
-
|
|
247
|
-
# -----------------------------------------------------------------------------
|
|
248
|
-
# templates (optional) -- override the text Agentainer appends to first prompts.
|
|
249
|
-
# Available placeholders: {agent} {swarm} {peers} {prefix} {inbox} {workdir}
|
|
250
|
-
# -----------------------------------------------------------------------------
|
|
251
|
-
#
|
|
252
|
-
# templates:
|
|
253
|
-
# comms: |
|
|
254
|
-
# You are {agent}. You may message: {peers}.
|
|
255
|
-
# Send with: swarm send --to <agent> "message"
|
|
256
|
-
# task_notice: |
|
|
257
|
-
# Stand by. Your real task arrives in the next message.
|